mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-10-01 06:16:51 -05:00
Use span for savefile slot API
No more offset fetch
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
@@ -21,15 +23,17 @@ public sealed record SlotInfoMisc(byte[] Data, int Slot, int Offset, bool PartyF
|
||||
|
||||
public bool WriteTo(SaveFile sav, PKM pk, PKMImportSetting setting = PKMImportSetting.UseDefault)
|
||||
{
|
||||
var span = Data.AsSpan(Offset);
|
||||
if (PartyFormat)
|
||||
sav.SetSlotFormatParty(pk, Data, Offset, setting, setting);
|
||||
sav.SetSlotFormatParty(pk, span, setting, setting);
|
||||
else
|
||||
sav.SetSlotFormatStored(pk, Data, Offset, setting, setting);
|
||||
sav.SetSlotFormatStored(pk, span, setting, setting);
|
||||
return true;
|
||||
}
|
||||
|
||||
public PKM Read(SaveFile sav)
|
||||
{
|
||||
return PartyFormat ? sav.GetPartySlot(Data, Offset) : sav.GetStoredSlot(Data, Offset);
|
||||
var span = Data.AsSpan(Offset);
|
||||
return PartyFormat ? sav.GetPartySlot(span) : sav.GetStoredSlot(span);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ static T[] SetArray<T>(ICollection<T> arr)
|
||||
|
||||
// rather than use Linq to build an array, just do it the quick way directly.
|
||||
var result = new T[arr.Count];
|
||||
((IReadOnlySet<T>)arr).CopyTo(result);
|
||||
arr.CopyTo(result, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ public partial class MemoryContext6
|
||||
/// <summary>
|
||||
/// 24bits of flags allowing certain feelings for a given memory index.
|
||||
/// </summary>
|
||||
private static ReadOnlySpan<uint> MemoryFeelings => new uint[]
|
||||
private static ReadOnlySpan<int> MemoryFeelings => new[]
|
||||
{
|
||||
0x000000, 0x04CBFD, 0x004BFD, 0x04CBFD, 0x04CBFD, 0xFFFBFB, 0x84FFF9, 0x47FFFF, 0xBF7FFA, 0x7660B0,
|
||||
0x80BDF9, 0x88FB7A, 0x083F79, 0x0001FE, 0xCFEFFF, 0x84EBAF, 0xB368B0, 0x091F7E, 0x0320A0, 0x080DDD,
|
||||
|
||||
@@ -291,7 +291,7 @@ public partial class MemoryContext8
|
||||
/// 24bits of flags allowing certain feelings for a given memory index.
|
||||
/// </summary>
|
||||
/// <remarks>Beware, there was an off-by-one error in the game that made Feeling 0 unobtainable, and thus the Happy feeling bit (rightmost) is omitted.</remarks>
|
||||
private static ReadOnlySpan<uint> MemoryFeelings => new uint[]
|
||||
private static ReadOnlySpan<int> MemoryFeelings => new[]
|
||||
{
|
||||
0x000000, 0x04CBFD, 0x004BFD, 0x04CBFD, 0x04CBFD, 0xFFFBFB, 0x84FFF9, 0x47FFFF, 0xBF7FFA, 0x7660B0,
|
||||
0x80BDF9, 0x88FB7A, 0x083F79, 0x0001FE, 0xCFEFFF, 0x84EBAF, 0xB368B0, 0x091F7E, 0x0320A0, 0x080DDD,
|
||||
|
||||
@@ -43,7 +43,7 @@ protected GBPKML(byte[] data, bool jp = false) : base(data)
|
||||
RawNickname.AsSpan().Fill(StringConverter12.G1TerminatorCode);
|
||||
}
|
||||
|
||||
public override void SetNotNicknamed(int language) => GetNonNickname(language).CopyTo(RawNickname);
|
||||
public override void SetNotNicknamed(int language) => GetNonNickname(language).AsSpan().CopyTo(RawNickname);
|
||||
|
||||
protected override byte[] GetNonNickname(int language)
|
||||
{
|
||||
|
||||
@@ -77,7 +77,7 @@ private void Initialize(GameVersion versionOverride)
|
||||
UnpackBox(Offsets.CurrentBox, baseDest, stored, CurrentBox, capacity);
|
||||
}
|
||||
|
||||
var party = GetData(Offsets.Party, SIZE_STOREDPARTY);
|
||||
var party = Data.AsSpan(Offsets.Party, SIZE_STOREDPARTY).ToArray();
|
||||
var partyPL = new PokeList1(party, PokeListType.Party, Japanese);
|
||||
for (int i = 0; i < partyPL.Pokemon.Length; i++)
|
||||
{
|
||||
@@ -107,7 +107,7 @@ private void Initialize(GameVersion versionOverride)
|
||||
|
||||
private void UnpackBox(int srcOfs, int destOfs, int boxSize, int boxIndex, PokeListType boxCapacity)
|
||||
{
|
||||
var boxData = GetData(srcOfs, boxSize);
|
||||
var boxData = Data.AsSpan(srcOfs, boxSize).ToArray();
|
||||
var boxDest = destOfs + (boxIndex * SIZE_BOX);
|
||||
var boxPL = new PokeList1(boxData, boxCapacity, Japanese);
|
||||
for (int i = 0; i < boxPL.Pokemon.Length; i++)
|
||||
@@ -137,11 +137,11 @@ private void PackBox(int boxDest, int boxIndex, PokeListType boxCapacity)
|
||||
// copy to box location
|
||||
var boxData = boxPL.Write();
|
||||
int boxSrc = GetBoxRawDataOffset(boxIndex);
|
||||
SetData(Data, boxData, boxSrc);
|
||||
SetData(Data.AsSpan(boxSrc), boxData);
|
||||
|
||||
// copy to active loc if current box
|
||||
if (boxIndex == CurrentBox)
|
||||
SetData(Data, boxData, Offsets.CurrentBox);
|
||||
SetData(Data.AsSpan(Offsets.CurrentBox), boxData);
|
||||
}
|
||||
|
||||
private const int SIZE_RESERVED = 0x8000; // unpacked box data
|
||||
@@ -176,7 +176,9 @@ protected override byte[] GetFinalData()
|
||||
int pSlot = 0;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
PK1 partyPK = GetPKM(GetData(GetPartyOffset(i), SIZE_STORED));
|
||||
var ofs = GetPartyOffset(i);
|
||||
var data = Data.AsSpan(ofs, SIZE_STORED).ToArray();
|
||||
PK1 partyPK = GetPKM(data);
|
||||
if (partyPK.Species > 0)
|
||||
partyPL[pSlot++] = partyPK;
|
||||
}
|
||||
@@ -257,7 +259,7 @@ private byte GetRBYChecksum(int start, int end)
|
||||
|
||||
public override string OT
|
||||
{
|
||||
get => GetString(Offsets.OT, MaxStringLengthOT);
|
||||
get => GetString(Data.AsSpan(Offsets.OT, MaxStringLengthOT));
|
||||
set => SetString(Data.AsSpan(Offsets.OT, MaxStringLengthOT + 1), value, MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
@@ -285,7 +287,7 @@ public override ushort TID16
|
||||
|
||||
public string Rival
|
||||
{
|
||||
get => GetString(Offsets.Rival, MaxStringLengthOT);
|
||||
get => GetString(Data.AsSpan(Offsets.Rival, MaxStringLengthOT));
|
||||
set => SetString(Data.AsSpan(Offsets.Rival, MaxStringLengthOT), value, MaxStringLengthOT, StringConverterOption.Clear50);
|
||||
}
|
||||
|
||||
@@ -542,20 +544,20 @@ private void SetDexFlag(int region, ushort species, bool value)
|
||||
SetFlag(region + ofs, bit & 7, value);
|
||||
}
|
||||
|
||||
public override void WriteSlotFormatStored(PKM pk, Span<byte> data, int offset)
|
||||
public override void WriteSlotFormatStored(PKM pk, Span<byte> data)
|
||||
{
|
||||
// pk that have never been boxed have yet to save the 'current level' for box indication
|
||||
// set this value at this time
|
||||
((PK1)pk).Stat_LevelBox = pk.CurrentLevel;
|
||||
base.WriteSlotFormatStored(pk, Data, offset);
|
||||
base.WriteSlotFormatStored(pk, data);
|
||||
}
|
||||
|
||||
public override void WriteBoxSlot(PKM pk, Span<byte> data, int offset)
|
||||
public override void WriteBoxSlot(PKM pk, Span<byte> data)
|
||||
{
|
||||
// pk that have never been boxed have yet to save the 'current level' for box indication
|
||||
// set this value at this time
|
||||
((PK1)pk).Stat_LevelBox = pk.CurrentLevel;
|
||||
base.WriteBoxSlot(pk, Data, offset);
|
||||
base.WriteBoxSlot(pk, data);
|
||||
}
|
||||
|
||||
private const int SpawnFlagCount = 0xF0;
|
||||
|
||||
@@ -204,7 +204,7 @@ public string GetTeamName(int team)
|
||||
|
||||
var ofs = GetTeamOffset(team);
|
||||
var otOfs = ofs + (Japanese ? 2 : 1);
|
||||
var str = GetString(otOfs, Japanese ? 5 : 7);
|
||||
var str = GetString(Data.AsSpan(otOfs, Japanese ? 5 : 7));
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
return name;
|
||||
var idOfs = ofs + (Japanese ? 0x8 : 0xC);
|
||||
@@ -249,25 +249,25 @@ public override SlotGroup GetTeam(int team)
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
var rel = ofs + ListHeaderSize + (i * SIZE_STORED);
|
||||
members[i] = (PK1)GetStoredSlot(Data, rel);
|
||||
members[i] = (PK1)GetStoredSlot(Data.AsSpan(rel));
|
||||
}
|
||||
return new SlotGroup(name, members);
|
||||
}
|
||||
|
||||
public override void WriteSlotFormatStored(PKM pk, Span<byte> data, int offset)
|
||||
public override void WriteSlotFormatStored(PKM pk, Span<byte> data)
|
||||
{
|
||||
// pk that have never been boxed have yet to save the 'current level' for box indication
|
||||
// set this value at this time
|
||||
((PK1)pk).Stat_LevelBox = pk.CurrentLevel;
|
||||
base.WriteSlotFormatStored(pk, Data, offset);
|
||||
base.WriteSlotFormatStored(pk, data);
|
||||
}
|
||||
|
||||
public override void WriteBoxSlot(PKM pk, Span<byte> data, int offset)
|
||||
public override void WriteBoxSlot(PKM pk, Span<byte> data)
|
||||
{
|
||||
// pk that have never been boxed have yet to save the 'current level' for box indication
|
||||
// set this value at this time
|
||||
((PK1)pk).Stat_LevelBox = pk.CurrentLevel;
|
||||
base.WriteBoxSlot(pk, Data, offset);
|
||||
base.WriteBoxSlot(pk, data);
|
||||
}
|
||||
|
||||
public static bool IsStadium(ReadOnlySpan<byte> data)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
@@ -118,7 +117,7 @@ public string GetTeamName(int team)
|
||||
var name = $"Team {team + 1}";
|
||||
|
||||
var ofs = GetTeamOffset(team);
|
||||
var str = GetString(ofs + 2, 5);
|
||||
var str = GetString(Data.AsSpan(ofs + 2, 5));
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
return name;
|
||||
var id = ReadUInt16BigEndian(Data.AsSpan(ofs + 8));
|
||||
@@ -136,25 +135,25 @@ public override SlotGroup GetTeam(int team)
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
var rel = ofs + ListHeaderSize + (i * SIZE_STORED);
|
||||
members[i] = (PK1)GetStoredSlot(Data, rel);
|
||||
members[i] = (PK1)GetStoredSlot(Data.AsSpan(rel));
|
||||
}
|
||||
return new SlotGroup(name, members);
|
||||
}
|
||||
|
||||
public override void WriteSlotFormatStored(PKM pk, Span<byte> data, int offset)
|
||||
public override void WriteSlotFormatStored(PKM pk, Span<byte> data)
|
||||
{
|
||||
// pk that have never been boxed have yet to save the 'current level' for box indication
|
||||
// set this value at this time
|
||||
((PK1)pk).Stat_LevelBox = pk.CurrentLevel;
|
||||
base.WriteSlotFormatStored(pk, Data, offset);
|
||||
base.WriteSlotFormatStored(pk, data);
|
||||
}
|
||||
|
||||
public override void WriteBoxSlot(PKM pk, Span<byte> data, int offset)
|
||||
public override void WriteBoxSlot(PKM pk, Span<byte> data)
|
||||
{
|
||||
// pk that have never been boxed have yet to save the 'current level' for box indication
|
||||
// set this value at this time
|
||||
((PK1)pk).Stat_LevelBox = pk.CurrentLevel;
|
||||
base.WriteBoxSlot(pk, Data, offset);
|
||||
base.WriteBoxSlot(pk, data);
|
||||
}
|
||||
|
||||
public static bool IsStadium(ReadOnlySpan<byte> data)
|
||||
|
||||
@@ -74,7 +74,7 @@ private void Initialize()
|
||||
for (int i = 0; i < BoxCount; i++)
|
||||
{
|
||||
int ofs = GetBoxRawDataOffset(i, splitAtIndex);
|
||||
var box = GetData(ofs, stored);
|
||||
var box = Data.AsSpan(ofs, stored).ToArray();
|
||||
var boxDest = baseDest + (i * SIZE_BOX);
|
||||
var boxPL = new PokeList2(box, capacity, Japanese);
|
||||
for (int j = 0; j < boxPL.Pokemon.Length; j++)
|
||||
@@ -87,7 +87,7 @@ private void Initialize()
|
||||
}
|
||||
}
|
||||
|
||||
var current = GetData(Offsets.CurrentBox, stored);
|
||||
var current = Data.AsSpan(Offsets.CurrentBox, stored).ToArray();
|
||||
var curBoxPL = new PokeList2(current, capacity, Japanese);
|
||||
var curDest = baseDest + (CurrentBox * SIZE_BOX);
|
||||
for (int i = 0; i < curBoxPL.Pokemon.Length; i++)
|
||||
@@ -99,7 +99,7 @@ private void Initialize()
|
||||
pkDat.CopyTo(Data, dest);
|
||||
}
|
||||
|
||||
var party = GetData(Offsets.Party, SIZE_STOREDPARTY);
|
||||
var party = Data.AsSpan(Offsets.Party, SIZE_STOREDPARTY).ToArray();
|
||||
var partyPL = new PokeList2(party, PokeListType.Party, Japanese);
|
||||
for (int i = 0; i < partyPL.Pokemon.Length; i++)
|
||||
{
|
||||
@@ -180,7 +180,9 @@ protected override byte[] GetFinalData()
|
||||
int slot = 0;
|
||||
for (int j = 0; j < boxPL.Pokemon.Length; j++)
|
||||
{
|
||||
PK2 boxPK = GetPKM(GetData(GetBoxOffset(i) + (j * SIZE_STORED), SIZE_STORED));
|
||||
var ofs = GetBoxOffset(i) + (j * SIZE_STORED);
|
||||
var data = Data.AsSpan(ofs, SIZE_STORED).ToArray();
|
||||
PK2 boxPK = GetPKM(data);
|
||||
if (boxPK.Species > 0)
|
||||
boxPL[slot++] = boxPK;
|
||||
}
|
||||
@@ -195,7 +197,9 @@ protected override byte[] GetFinalData()
|
||||
int pSlot = 0;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
PK2 partyPK = GetPKM(GetData(GetPartyOffset(i), SIZE_STORED));
|
||||
var ofs = GetPartyOffset(i);
|
||||
var data = Data.AsSpan(ofs, SIZE_STORED).ToArray();
|
||||
PK2 partyPK = GetPKM(data);
|
||||
if (partyPK.Species > 0)
|
||||
partyPL[pSlot++] = partyPK;
|
||||
}
|
||||
@@ -321,7 +325,7 @@ public override bool ChecksumsValid
|
||||
|
||||
public override string OT
|
||||
{
|
||||
get => GetString(Offsets.Trainer1 + 2, (Korean ? 2 : 1) * MaxStringLengthOT);
|
||||
get => GetString(Data.AsSpan(Offsets.Trainer1 + 2, (Korean ? 2 : 1) * MaxStringLengthOT));
|
||||
set => SetString(Data.AsSpan(Offsets.Trainer1 + 2, (Korean ? 2 : 1) * MaxStringLengthOT), value, 8, StringConverterOption.Clear50);
|
||||
}
|
||||
|
||||
@@ -333,7 +337,7 @@ public Span<byte> OT_Trash
|
||||
|
||||
public string Rival
|
||||
{
|
||||
get => GetString(Offsets.Rival, (Korean ? 2 : 1) * MaxStringLengthOT);
|
||||
get => GetString(Data.AsSpan(Offsets.Rival, (Korean ? 2 : 1) * MaxStringLengthOT));
|
||||
set => SetString(Data.AsSpan(Offsets.Rival, (Korean ? 2 : 1) * MaxStringLengthOT), value, 8, StringConverterOption.Clear50);
|
||||
}
|
||||
|
||||
@@ -557,7 +561,7 @@ public bool CurrentBoxChanged
|
||||
public override string GetBoxName(int box)
|
||||
{
|
||||
int len = Korean ? 17 : 9;
|
||||
return GetString(Offsets.BoxNames + (box * len), len);
|
||||
return GetString(Data.AsSpan(Offsets.BoxNames + (box * len), len));
|
||||
}
|
||||
|
||||
public override void SetBoxName(int box, ReadOnlySpan<char> value)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
@@ -137,7 +136,7 @@ public string GetTeamName(int team)
|
||||
var name = $"{((Stadium2TeamType) (team / TeamCountType)).ToString().Replace('_', ' ')} {(team % 10) + 1}";
|
||||
|
||||
var ofs = GetTeamOffset(team);
|
||||
var str = GetString(ofs + 4, 7);
|
||||
var str = GetString(Data.AsSpan(ofs + 4, 7));
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
return name;
|
||||
var id = ReadUInt16BigEndian(Data.AsSpan(ofs + 2));
|
||||
@@ -147,7 +146,8 @@ public string GetTeamName(int team)
|
||||
public override string GetBoxName(int box)
|
||||
{
|
||||
var ofs = GetBoxOffset(box) - 0x10;
|
||||
var str = GetString(ofs, 0x10);
|
||||
var boxNameSpan = Data.AsSpan(ofs, 0x10);
|
||||
var str = GetString(boxNameSpan);
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
return $"Box {box + 1}";
|
||||
return str;
|
||||
@@ -164,7 +164,7 @@ public override SlotGroup GetTeam(int team)
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
var rel = ofs + ListHeaderSizeTeam + (i * SIZE_STORED);
|
||||
members[i] = (SK2)GetStoredSlot(Data, rel);
|
||||
members[i] = (SK2)GetStoredSlot(Data.AsSpan(rel));
|
||||
}
|
||||
return new SlotGroup(name, members);
|
||||
}
|
||||
|
||||
@@ -197,8 +197,8 @@ public void WriteBothSaveSlots(Span<byte> data)
|
||||
protected sealed override PK3 GetPKM(byte[] data) => new(data);
|
||||
protected sealed override byte[] DecryptPKM(byte[] data) => PokeCrypto.DecryptArray3(data);
|
||||
|
||||
protected sealed override byte[] BoxBuffer => Storage;
|
||||
protected sealed override byte[] PartyBuffer => Large;
|
||||
protected sealed override Span<byte> BoxBuffer => Storage;
|
||||
protected sealed override Span<byte> PartyBuffer => Large;
|
||||
|
||||
private const int COUNT_BOX = 14;
|
||||
private const int COUNT_SLOTSPERBOX = 30;
|
||||
@@ -633,9 +633,9 @@ public override void CopyChangesFrom(SaveFile sav)
|
||||
{
|
||||
SetData(sav.Data, 0);
|
||||
var s3 = (SAV3)sav;
|
||||
SetData(Small, s3.Small, 0);
|
||||
SetData(Large, s3.Large, 0);
|
||||
SetData(Storage, s3.Storage, 0);
|
||||
SetData(Small, s3.Small);
|
||||
SetData(Large, s3.Large);
|
||||
SetData(Storage, s3.Storage);
|
||||
}
|
||||
|
||||
#region External Connections
|
||||
|
||||
@@ -65,7 +65,9 @@ private StrategyMemo Initialize()
|
||||
// Count up how many party slots are active.
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (GetPartySlot(Data, GetPartyOffset(i)).Species != 0)
|
||||
var ofs = GetPartyOffset(i);
|
||||
var span = Data.AsSpan(ofs);
|
||||
if (ReadUInt16BigEndian(span) != 0) // species is at offset 0x00
|
||||
PartyCount++;
|
||||
}
|
||||
|
||||
@@ -278,14 +280,16 @@ public override int GetBoxOffset(int box)
|
||||
return Box + (((30 * SIZE_STORED) + 0x14)*box) + 0x14;
|
||||
}
|
||||
|
||||
private Span<byte> GetBoxNameSpan(int box) => Data.AsSpan(Box + (0x24A4 * box), 16);
|
||||
|
||||
public override string GetBoxName(int box)
|
||||
{
|
||||
return GetString(Box + (0x24A4 * box), 16);
|
||||
return GetString(GetBoxNameSpan(box));
|
||||
}
|
||||
|
||||
public override void SetBoxName(int box, ReadOnlySpan<char> value)
|
||||
{
|
||||
SetString(Data.AsSpan(Box + (0x24A4 * box), 16), value, 8, StringConverterOption.ClearZero);
|
||||
SetString(GetBoxNameSpan(box), value, 8, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
protected override CK3 GetPKM(byte[] data)
|
||||
@@ -363,8 +367,8 @@ public override int PlayedSeconds
|
||||
}
|
||||
|
||||
// Trainer Info (offset 0x78, length 0xB18, end @ 0xB90)
|
||||
public override string OT { get => GetString(0x78, 20); set { SetString(Data.AsSpan(0x78, 20), value, 10, StringConverterOption.ClearZero); OT2 = value; } }
|
||||
public string OT2 { get => GetString(0x8C, 20); set => SetString(Data.AsSpan(0x8C, 20), value, 10, StringConverterOption.ClearZero); }
|
||||
public override string OT { get => GetString(Data.AsSpan(0x78, 20)); set { SetString(Data.AsSpan(0x78, 20), value, 10, StringConverterOption.ClearZero); OT2 = value; } }
|
||||
public string OT2 { get => GetString(Data.AsSpan(0x8C, 20)); set => SetString(Data.AsSpan(0x8C, 20), value, 10, StringConverterOption.ClearZero); }
|
||||
|
||||
public override uint ID32 { get => ReadUInt32BigEndian(Data.AsSpan(0xA4)); set => WriteUInt32BigEndian(Data.AsSpan(0xA4), value); }
|
||||
public override ushort SID16 { get => ReadUInt16BigEndian(Data.AsSpan(0xA4)); set => WriteUInt16BigEndian(Data.AsSpan(0xA4), value); }
|
||||
@@ -373,7 +377,7 @@ public override int PlayedSeconds
|
||||
public override int Gender { get => Data[0xAF8]; set => Data[0xAF8] = (byte)value; }
|
||||
public override uint Money { get => ReadUInt32BigEndian(Data.AsSpan(0xAFC)); set => WriteUInt32BigEndian(Data.AsSpan(0xAFC), value); }
|
||||
public uint Coupons { get => ReadUInt32BigEndian(Data.AsSpan(0xB00)); set => WriteUInt32BigEndian(Data.AsSpan(0xB00), value); }
|
||||
public string RUI_Name { get => GetString(0xB3A, 20); set => SetString(Data.AsSpan(0xB3A, 20), value, 10, StringConverterOption.ClearZero); }
|
||||
public string RUI_Name { get => GetString(Data.AsSpan(0xB3A, 20)); set => SetString(Data.AsSpan(0xB3A, 20), value, 10, StringConverterOption.ClearZero); }
|
||||
|
||||
public override IReadOnlyList<InventoryPouch> Inventory
|
||||
{
|
||||
|
||||
@@ -61,14 +61,14 @@ public override uint SecurityKey
|
||||
|
||||
public RTC3 ClockInitial
|
||||
{
|
||||
get => new(GetData(Small, 0x98, RTC3.Size));
|
||||
set => SetData(Small, value.Data, 0x98);
|
||||
get => new(Small.AsSpan(0x98, RTC3.Size).ToArray());
|
||||
set => SetData(Small.AsSpan(0x98), value.Data);
|
||||
}
|
||||
|
||||
public RTC3 ClockElapsed
|
||||
{
|
||||
get => new(GetData(Small, 0xA0, RTC3.Size));
|
||||
set => SetData(Small, value.Data, 0xA0);
|
||||
get => new(Small.AsSpan(0xA0, RTC3.Size).ToArray());
|
||||
set => SetData(Small.AsSpan(0xA0), value.Data);
|
||||
}
|
||||
|
||||
public ushort JoyfulJumpInRow { get => ReadUInt16LittleEndian(Small.AsSpan(0x1FC)); set => WriteUInt16LittleEndian(Small.AsSpan(0x1FC), Math.Min((ushort)9999, value)); }
|
||||
@@ -146,7 +146,7 @@ protected override InventoryPouch3[] GetItems()
|
||||
public PokeBlock3Case PokeBlocks
|
||||
{
|
||||
get => new(Large, 0x848);
|
||||
set => SetData(Large, value.Write(), 0x848);
|
||||
set => SetData(Large.AsSpan(0x848), value.Write());
|
||||
}
|
||||
|
||||
protected override int SeenOffset2 => 0x988;
|
||||
@@ -155,8 +155,8 @@ public PokeBlock3Case PokeBlocks
|
||||
|
||||
public Swarm3 Swarm
|
||||
{
|
||||
get => new(Large.Slice(0x2B90, Swarm3.SIZE));
|
||||
set => SetData(Large, value.Data, 0x2B90);
|
||||
get => new(Large.AsSpan(0x2B90, Swarm3.SIZE).ToArray());
|
||||
set => SetData(Large.AsSpan(0x2B90), value.Data);
|
||||
}
|
||||
|
||||
private void ClearSwarm() => Large.AsSpan(0x2B90, Swarm3.SIZE).Clear();
|
||||
@@ -205,9 +205,9 @@ public int SwarmIndex
|
||||
private int WonderCardOffset => WonderNewsOffset + (Japanese ? WonderNews3.SIZE_JAP : WonderNews3.SIZE);
|
||||
private int WonderCardExtraOffset => WonderCardOffset + (Japanese ? WonderCard3.SIZE_JAP : WonderCard3.SIZE);
|
||||
|
||||
public WonderNews3 WonderNews { get => new(Large.Slice(WonderNewsOffset, Japanese ? WonderNews3.SIZE_JAP : WonderNews3.SIZE)); set => SetData(Large, value.Data, WonderOffset); }
|
||||
public WonderCard3 WonderCard { get => new(Large.Slice(WonderCardOffset, Japanese ? WonderCard3.SIZE_JAP : WonderCard3.SIZE)); set => SetData(Large, value.Data, WonderCardOffset); }
|
||||
public WonderCard3Extra WonderCardExtra { get => new(Large.Slice(WonderCardExtraOffset, WonderCard3Extra.SIZE)); set => SetData(Large, value.Data, WonderCardExtraOffset); }
|
||||
public WonderNews3 WonderNews { get => new(Large.Slice(WonderNewsOffset, Japanese ? WonderNews3.SIZE_JAP : WonderNews3.SIZE)); set => SetData(Large.AsSpan(WonderOffset), value.Data); }
|
||||
public WonderCard3 WonderCard { get => new(Large.Slice(WonderCardOffset, Japanese ? WonderCard3.SIZE_JAP : WonderCard3.SIZE)); set => SetData(Large.AsSpan(WonderCardOffset), value.Data); }
|
||||
public WonderCard3Extra WonderCardExtra { get => new(Large.Slice(WonderCardExtraOffset, WonderCard3Extra.SIZE)); set => SetData(Large.AsSpan(WonderCardExtraOffset), value.Data); }
|
||||
// 0x338: 4 easy chat words
|
||||
// 0x340: news MENewsJisanStruct
|
||||
// 0x344: uint[5], uint[5] tracking?
|
||||
@@ -215,10 +215,10 @@ public int SwarmIndex
|
||||
public override Gen3MysteryData MysteryData
|
||||
{
|
||||
get => new MysteryEvent3(Large.Slice(0x3728, MysteryEvent3.SIZE));
|
||||
set => SetData(Large, value.Data, 0x3728);
|
||||
set => SetData(Large.AsSpan(0x3728), value.Data);
|
||||
}
|
||||
|
||||
public RecordMixing3Gift RecordMixingGift { get => new(Large.Slice(0x3B14, RecordMixing3Gift.SIZE)); set => SetData(Large, value.Data, 0x3B14); }
|
||||
public RecordMixing3Gift RecordMixingGift { get => new(Large.Slice(0x3B14, RecordMixing3Gift.SIZE)); set => SetData(Large.AsSpan(0x3B14), value.Data); }
|
||||
|
||||
protected override int SeenOffset3 => 0x3B24;
|
||||
|
||||
@@ -237,6 +237,6 @@ public override Gen3MysteryData MysteryData
|
||||
public BV3 BattleVideo
|
||||
{
|
||||
get => !HasBattleVideo ? new BV3() : new BV3(Data.Slice(OFS_BV + 4, BV3.SIZE));
|
||||
set => SetData(Data, value.Data, OFS_BV + 4);
|
||||
set => SetData(Data.AsSpan(OFS_BV + 4, BV3.SIZE), value.Data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,9 +162,9 @@ protected override InventoryPouch3[] GetItems()
|
||||
private int WonderCardOffset => WonderNewsOffset + (Japanese ? WonderNews3.SIZE_JAP : WonderNews3.SIZE);
|
||||
private int WonderCardExtraOffset => WonderCardOffset + (Japanese ? WonderCard3.SIZE_JAP : WonderCard3.SIZE);
|
||||
|
||||
public WonderNews3 WonderNews { get => new(Large.Slice(WonderNewsOffset, Japanese ? WonderNews3.SIZE_JAP : WonderNews3.SIZE)); set => SetData(Large, value.Data, WonderOffset); }
|
||||
public WonderCard3 WonderCard { get => new(Large.Slice(WonderCardOffset, Japanese ? WonderCard3.SIZE_JAP : WonderCard3.SIZE)); set => SetData(Large, value.Data, WonderCardOffset); }
|
||||
public WonderCard3Extra WonderCardExtra { get => new(Large.Slice(WonderCardExtraOffset, WonderCard3Extra.SIZE)); set => SetData(Large, value.Data, WonderCardExtraOffset); }
|
||||
public WonderNews3 WonderNews { get => new(Large.Slice(WonderNewsOffset, Japanese ? WonderNews3.SIZE_JAP : WonderNews3.SIZE)); set => SetData(Large.AsSpan(WonderOffset), value.Data); }
|
||||
public WonderCard3 WonderCard { get => new(Large.Slice(WonderCardOffset, Japanese ? WonderCard3.SIZE_JAP : WonderCard3.SIZE)); set => SetData(Large.AsSpan(WonderCardOffset), value.Data); }
|
||||
public WonderCard3Extra WonderCardExtra { get => new(Large.Slice(WonderCardExtraOffset, WonderCard3Extra.SIZE)); set => SetData(Large.AsSpan(WonderCardExtraOffset), value.Data); }
|
||||
// 0x338: 4 easy chat words
|
||||
// 0x340: news MENewsJisanStruct
|
||||
// 0x344: uint[5], uint[5] tracking?
|
||||
@@ -172,7 +172,7 @@ protected override InventoryPouch3[] GetItems()
|
||||
public override Gen3MysteryData MysteryData
|
||||
{
|
||||
get => new MysteryEvent3(Large.Slice(0x361C, MysteryEvent3.SIZE));
|
||||
set => SetData(Large, value.Data, 0x361C);
|
||||
set => SetData(Large.AsSpan(0x361C), value.Data);
|
||||
}
|
||||
|
||||
protected override int SeenOffset3 => 0x3A18;
|
||||
|
||||
@@ -57,14 +57,14 @@ public override bool NationalDex
|
||||
|
||||
public RTC3 ClockInitial
|
||||
{
|
||||
get => new(GetData(Small, 0x98, RTC3.Size));
|
||||
set => SetData(Small, value.Data, 0x98);
|
||||
get => new(Small.AsSpan(0x98, RTC3.Size).ToArray());
|
||||
set => SetData(Small.AsSpan(0x98), value.Data);
|
||||
}
|
||||
|
||||
public RTC3 ClockElapsed
|
||||
{
|
||||
get => new(GetData(Small, 0xA0, RTC3.Size));
|
||||
set => SetData(Small, value.Data, 0xA0);
|
||||
get => new(Small.AsSpan(0xA0, RTC3.Size).ToArray());
|
||||
set => SetData(Small.AsSpan(0xA0), value.Data);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -109,7 +109,7 @@ protected override InventoryPouch3[] GetItems()
|
||||
public PokeBlock3Case PokeBlocks
|
||||
{
|
||||
get => new(Large, 0x7F8);
|
||||
set => SetData(Large, value.Write(), 0x7F8);
|
||||
set => SetData(Large.AsSpan(0x7F8), value.Write());
|
||||
}
|
||||
|
||||
protected override int SeenOffset2 => 0x938;
|
||||
@@ -119,7 +119,7 @@ public PokeBlock3Case PokeBlocks
|
||||
public Swarm3 Swarm
|
||||
{
|
||||
get => new(Large.Slice(0x2AFC, Swarm3.SIZE));
|
||||
set => SetData(Large, value.Data, 0x2AFC);
|
||||
set => SetData(Large.AsSpan(0x2AFC), value.Data);
|
||||
}
|
||||
|
||||
private void ClearSwarm() => Large.AsSpan(0x2AFC, Swarm3.SIZE).Clear();
|
||||
@@ -166,10 +166,10 @@ public int SwarmIndex
|
||||
public override Gen3MysteryData MysteryData
|
||||
{
|
||||
get => new MysteryEvent3RS(Large.Slice(0x3690, MysteryEvent3.SIZE));
|
||||
set => SetData(Large, value.Data, 0x3690);
|
||||
set => SetData(Large.AsSpan(0x3690), value.Data);
|
||||
}
|
||||
|
||||
public RecordMixing3Gift RecordMixingGift { get => new(Large.Slice(0x3A7C, RecordMixing3Gift.SIZE)); set => SetData(Large, value.Data, 0x3A7C); }
|
||||
public RecordMixing3Gift RecordMixingGift { get => new(Large.Slice(0x3A7C, RecordMixing3Gift.SIZE)); set => SetData(Large.AsSpan(0x3A7C), value.Data); }
|
||||
|
||||
protected override int SeenOffset3 => 0x3A8C;
|
||||
#endregion
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
@@ -52,7 +51,7 @@ private void InitializeData()
|
||||
Array.Copy(Data, b.Offset + 0xC, Data, (int) (Box + (b.ID * copySize)), copySize);
|
||||
}
|
||||
|
||||
private static BlockInfoRSBOX[] ReadBlocks(byte[] data)
|
||||
private static BlockInfoRSBOX[] ReadBlocks(ReadOnlySpan<byte> data)
|
||||
{
|
||||
var blocks = new BlockInfoRSBOX[2 * BLOCK_COUNT];
|
||||
for (int i = 0; i < blocks.Length; i++)
|
||||
@@ -91,7 +90,7 @@ private byte[] GetInnerData()
|
||||
|
||||
SetChecksums();
|
||||
|
||||
return GetData(0, Data.Length - SIZE_RESERVED);
|
||||
return Data[..^SIZE_RESERVED];
|
||||
}
|
||||
|
||||
// Configuration
|
||||
@@ -140,11 +139,16 @@ public override int CurrentBox
|
||||
set => Data[Box + 4] = (byte)(value / 2);
|
||||
}
|
||||
|
||||
private Span<byte> GetBoxNameSpan(int box)
|
||||
{
|
||||
int offset = Box + 0x1EC38 + (9 * box);
|
||||
return Data.AsSpan(offset, 9);
|
||||
}
|
||||
|
||||
protected override int GetBoxWallpaperOffset(int box)
|
||||
{
|
||||
// Box Wallpaper is directly after the Box Names
|
||||
int offset = Box + 0x1ED19 + (box / 2);
|
||||
return offset;
|
||||
return Box + 0x1ED19 + (box / 2);
|
||||
}
|
||||
|
||||
public override string GetBoxName(int box)
|
||||
@@ -155,18 +159,18 @@ public override string GetBoxName(int box)
|
||||
string boxName = $"[{lo:00}-{hi:00}] ";
|
||||
box /= 2;
|
||||
|
||||
int offset = Box + 0x1EC38 + (9 * box);
|
||||
if (Data[offset] is 0 or 0xFF)
|
||||
var span = GetBoxNameSpan(box);
|
||||
if (span[0] is 0 or 0xFF)
|
||||
boxName += $"BOX {box + 1}";
|
||||
boxName += GetString(offset, 9);
|
||||
else
|
||||
boxName += GetString(span);
|
||||
|
||||
return boxName;
|
||||
}
|
||||
|
||||
public override void SetBoxName(int box, ReadOnlySpan<char> value)
|
||||
{
|
||||
int offset = Box + 0x1EC38 + (9 * box);
|
||||
var span = Data.AsSpan(offset, 9);
|
||||
var span = GetBoxNameSpan(box);
|
||||
if (value == $"BOX {box + 1}")
|
||||
{
|
||||
span.Clear();
|
||||
@@ -191,9 +195,9 @@ protected override byte[] DecryptPKM(byte[] data)
|
||||
|
||||
protected override void SetDex(PKM pk) { /* No Pokedex for this game, do nothing */ }
|
||||
|
||||
public override void WriteBoxSlot(PKM pk, Span<byte> data, int offset)
|
||||
public override void WriteBoxSlot(PKM pk, Span<byte> data)
|
||||
{
|
||||
base.WriteBoxSlot(pk, data, offset);
|
||||
base.WriteBoxSlot(pk, data);
|
||||
WriteUInt16LittleEndian(data[(PokeCrypto.SIZE_3STORED)..], pk.TID16);
|
||||
WriteUInt16LittleEndian(data[(PokeCrypto.SIZE_3STORED + 2)..], pk.SID16);
|
||||
}
|
||||
|
||||
@@ -131,7 +131,9 @@ private void Initialize()
|
||||
// Count up how many party slots are active.
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (GetPartySlot(Data, GetPartyOffset(i)).Species != 0)
|
||||
var ofs = GetPartyOffset(i);
|
||||
var span = Data.AsSpan(ofs);
|
||||
if (ReadUInt16BigEndian(span) != 0) // species is at offset 0x00
|
||||
PartyCount++;
|
||||
}
|
||||
}
|
||||
@@ -320,7 +322,7 @@ public override int PlayedSeconds
|
||||
|
||||
// Trainer Info
|
||||
public override GameVersion Version { get => GameVersion.XD; protected set { } }
|
||||
public override string OT { get => GetString(Trainer1 + 0x00, 20); set => SetString(Data.AsSpan(Trainer1 + 0x00, 20), value, 10, StringConverterOption.ClearZero); }
|
||||
public override string OT { get => GetString(Data.AsSpan(Trainer1 + 0x00, 20)); set => SetString(Data.AsSpan(Trainer1 + 0x00, 20), value, 10, StringConverterOption.ClearZero); }
|
||||
public override uint ID32 { get => ReadUInt32BigEndian(Data.AsSpan(Trainer1 + 0x2C)); set => WriteUInt32BigEndian(Data.AsSpan(Trainer1 + 0x2C), value); }
|
||||
public override ushort SID16 { get => ReadUInt16BigEndian(Data.AsSpan(Trainer1 + 0x2C)); set => WriteUInt16BigEndian(Data.AsSpan(Trainer1 + 0x2C), value); }
|
||||
public override ushort TID16 { get => ReadUInt16BigEndian(Data.AsSpan(Trainer1 + 0x2E)); set => WriteUInt16BigEndian(Data.AsSpan(Trainer1 + 0x2E), value); }
|
||||
@@ -333,7 +335,7 @@ public override int PlayedSeconds
|
||||
public override int GetPartyOffset(int slot) => Party + (SIZE_STORED * slot);
|
||||
private int GetBoxInfoOffset(int box) => Box + (((30 * SIZE_STORED) + 0x14) * box);
|
||||
public override int GetBoxOffset(int box) => GetBoxInfoOffset(box) + 20;
|
||||
public override string GetBoxName(int box) => GetString(GetBoxInfoOffset(box), 16);
|
||||
public override string GetBoxName(int box) => GetString(Data.AsSpan(GetBoxInfoOffset(box), 16));
|
||||
|
||||
public override void SetBoxName(int box, ReadOnlySpan<char> value)
|
||||
{
|
||||
@@ -348,12 +350,12 @@ protected override XK3 GetPKM(byte[] data)
|
||||
}
|
||||
|
||||
protected override byte[] DecryptPKM(byte[] data) => data;
|
||||
public override XK3 GetPartySlot(byte[] data, int offset) => GetStoredSlot(data, offset);
|
||||
public override XK3 GetPartySlot(ReadOnlySpan<byte> data) => GetStoredSlot(data);
|
||||
|
||||
public override XK3 GetStoredSlot(byte[] data, int offset)
|
||||
public override XK3 GetStoredSlot(ReadOnlySpan<byte> data)
|
||||
{
|
||||
// Get Shadow Data
|
||||
var pk = (XK3)base.GetStoredSlot(data, offset);
|
||||
var pk = (XK3)base.GetStoredSlot(data);
|
||||
if (pk.ShadowID > 0 && pk.ShadowID < ShadowInfo.Count)
|
||||
pk.Purification = ShadowInfo[pk.ShadowID].Purification;
|
||||
return pk;
|
||||
|
||||
@@ -23,8 +23,8 @@ public abstract class SAV4 : SaveFile, IEventFlag37
|
||||
// SaveData is chunked into two pieces.
|
||||
protected readonly byte[] Storage;
|
||||
public readonly byte[] General;
|
||||
protected sealed override byte[] BoxBuffer => Storage;
|
||||
protected sealed override byte[] PartyBuffer => General;
|
||||
protected sealed override Span<byte> BoxBuffer => Storage;
|
||||
protected sealed override Span<byte> PartyBuffer => General;
|
||||
|
||||
protected abstract int StorageStart { get; }
|
||||
public abstract Zukan4 Dex { get; }
|
||||
@@ -48,16 +48,16 @@ protected SAV4(byte[] data, int gSize, int sSize, int sStart) : base(data)
|
||||
|
||||
var gbo = (GeneralBlockPosition == 0 ? 0 : PartitionSize);
|
||||
var sbo = (StorageBlockPosition == 0 ? 0 : PartitionSize) + sStart;
|
||||
General = GetData(gbo, gSize);
|
||||
Storage = GetData(sbo, sSize);
|
||||
General = Data.AsSpan(gbo, gSize).ToArray();
|
||||
Storage = Data.AsSpan(sbo, sSize).ToArray();
|
||||
}
|
||||
|
||||
// Configuration
|
||||
protected sealed override SAV4 CloneInternal()
|
||||
{
|
||||
var sav = CloneInternal4();
|
||||
SetData(sav.General, General, 0);
|
||||
SetData(sav.Storage, Storage, 0);
|
||||
SetData(sav.General, General);
|
||||
SetData(sav.Storage, Storage);
|
||||
return sav;
|
||||
}
|
||||
|
||||
@@ -67,8 +67,8 @@ public sealed override void CopyChangesFrom(SaveFile sav)
|
||||
{
|
||||
SetData(sav.Data, 0);
|
||||
var s4 = (SAV4)sav;
|
||||
SetData(General, s4.General, 0);
|
||||
SetData(Storage, s4.Storage, 0);
|
||||
SetData(General, s4.General);
|
||||
SetData(Storage, s4.Storage);
|
||||
}
|
||||
|
||||
protected sealed override int SIZE_STORED => PokeCrypto.SIZE_4STORED;
|
||||
@@ -432,12 +432,12 @@ protected sealed override DataMysteryGift[] MysteryGiftCards
|
||||
for (int i = 0; i < 8; i++) // 8 PGT
|
||||
{
|
||||
if (value[i] is PGT)
|
||||
SetData(General, value[i].Data, WondercardData + (i *PGT.Size));
|
||||
SetData(General.AsSpan(WondercardData + (i * PGT.Size)), value[i].Data);
|
||||
}
|
||||
for (int i = 8; i < 11; i++) // 3 PCD
|
||||
{
|
||||
if (value[i] is PCD)
|
||||
SetData(General, value[i].Data, WondercardData + (8 *PGT.Size) + ((i - 8)*PCD.Size));
|
||||
SetData(General.AsSpan(WondercardData + (8 * PGT.Size) + ((i - 8) * PCD.Size)), value[i].Data);
|
||||
}
|
||||
if (this is SAV4HGSS hgss && value.Length >= 11 && value[^1] is PCD capsule)
|
||||
hgss.LockCapsuleSlot = capsule;
|
||||
@@ -531,7 +531,7 @@ public void SetEventFlag(int flagNumber, bool value)
|
||||
private const byte SealMaxCount = 99;
|
||||
|
||||
public byte[] GetSealCase() => General.Slice(Seal, (int)Seal4.MAX);
|
||||
public void SetSealCase(byte[] value) => SetData(General, value, Seal);
|
||||
public void SetSealCase(ReadOnlySpan<byte> value) => SetData(General.AsSpan(Seal), value);
|
||||
|
||||
public byte GetSealCount(Seal4 id) => General[Seal + (int)id];
|
||||
public byte SetSealCount(Seal4 id, byte count) => General[Seal + (int)id] = Math.Min(SealMaxCount, count);
|
||||
|
||||
@@ -200,16 +200,21 @@ public override ushort SID16
|
||||
private int BoxName = -1;
|
||||
private const int BoxNameLength = 0x28;
|
||||
|
||||
private Span<byte> GetBoxNameSpan(int box)
|
||||
{
|
||||
int ofs = BoxName + (box * BoxNameLength);
|
||||
return Data.AsSpan(ofs, BoxNameLength);
|
||||
}
|
||||
|
||||
public override string GetBoxName(int box)
|
||||
{
|
||||
if (BoxName < 0)
|
||||
return $"BOX {box + 1}";
|
||||
|
||||
int ofs = BoxName + (box * BoxNameLength);
|
||||
var span = Data.AsSpan(ofs, BoxNameLength);
|
||||
var span = GetBoxNameSpan(box);
|
||||
if (ReadUInt16BigEndian(span) == 0)
|
||||
return $"BOX {box + 1}";
|
||||
return GetString(ofs, BoxNameLength);
|
||||
return GetString(span);
|
||||
}
|
||||
|
||||
public override void SetBoxName(int box, ReadOnlySpan<char> value)
|
||||
@@ -217,8 +222,7 @@ public override void SetBoxName(int box, ReadOnlySpan<char> value)
|
||||
if (BoxName < 0)
|
||||
return;
|
||||
|
||||
int ofs = BoxName + (box * BoxNameLength);
|
||||
var span = Data.AsSpan(ofs, BoxNameLength);
|
||||
var span = GetBoxNameSpan(box);
|
||||
if (ReadUInt16BigEndian(span) == 0)
|
||||
return;
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ public uint PoketchStepCounter
|
||||
public void SetPoketchDotArtistData(ReadOnlySpan<byte> value)
|
||||
{
|
||||
if (value.Length != 120)
|
||||
throw new ArgumentException($"Expected {120} bytes.", nameof(value.Length));
|
||||
throw new ArgumentOutOfRangeException($"Expected {120} bytes.", nameof(value.Length));
|
||||
value.CopyTo(General.AsSpan(PoketchStart + 0x2A));
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ public HoneyTreeValue GetHoneyTree(int index)
|
||||
public void SetHoneyTree(HoneyTreeValue tree, int index)
|
||||
{
|
||||
if (index <= 21)
|
||||
SetData(General, tree.Data, OFS_HONEY + (HONEY_SIZE * index));
|
||||
SetData(General.AsSpan(OFS_HONEY + (HONEY_SIZE * index)), tree.Data);
|
||||
}
|
||||
|
||||
public MunchlaxTreeSet4 GetMunchlaxTrees() => CalculateMunchlaxTrees(TID16, SID16);
|
||||
|
||||
@@ -212,7 +212,7 @@ public byte[] CGearSkinData
|
||||
|
||||
public EntreeForest EntreeData
|
||||
{
|
||||
get => new(GetData(EntreeForestOffset, EntreeForest.SIZE));
|
||||
get => new(Data.AsSpan(EntreeForestOffset, EntreeForest.SIZE).ToArray());
|
||||
set => SetData(value.Write(), EntreeForestOffset);
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ public EntreeForest EntreeData
|
||||
public abstract Encount5 Encount { get; }
|
||||
|
||||
public static int GetMailOffset(int index) => (index * Mail5.SIZE) + 0x1DD00;
|
||||
public byte[] GetMailData(int offset) => GetData(offset, Mail5.SIZE);
|
||||
public byte[] GetMailData(int offset) => Data.AsSpan(offset, Mail5.SIZE).ToArray();
|
||||
public int GetBattleBoxSlot(int slot) => BattleBoxOffset + (slot * SIZE_STORED);
|
||||
|
||||
public MailDetail GetMail(int mailIndex)
|
||||
|
||||
@@ -175,7 +175,7 @@ public override void SetDaycareHasEgg(int loc, bool hasEgg)
|
||||
}
|
||||
|
||||
public override string JPEGTitle => !HasJPPEGData ? string.Empty : StringConverter6.GetString(Data.AsSpan(JPEG, 0x1A));
|
||||
public override byte[] GetJPEGData() => !HasJPPEGData ? Array.Empty<byte>() : GetData(JPEG + 0x54, 0xE004);
|
||||
public override byte[] GetJPEGData() => !HasJPPEGData ? Array.Empty<byte>() : Data.AsSpan(JPEG + 0x54, 0xE004).ToArray();
|
||||
private bool HasJPPEGData => Data[JPEG + 0x54] == 0xFF;
|
||||
|
||||
protected override bool[] MysteryGiftReceivedFlags { get => Blocks.MysteryGift.GetReceivedFlags(); set => Blocks.MysteryGift.SetReceivedFlags(value); }
|
||||
|
||||
@@ -112,7 +112,7 @@ public override void SetDaycareRNGSeed(int loc, string seed)
|
||||
}
|
||||
|
||||
public override string JPEGTitle => !HasJPPEGData ? string.Empty : StringConverter6.GetString(Data.AsSpan(JPEG, 0x1A));
|
||||
public override byte[] GetJPEGData() => !HasJPPEGData ? Array.Empty<byte>() : GetData(JPEG + 0x54, 0xE004);
|
||||
public override byte[] GetJPEGData() => !HasJPPEGData ? Array.Empty<byte>() : Data.AsSpan(JPEG + 0x54, 0xE004).ToArray();
|
||||
private bool HasJPPEGData => Data[JPEG + 0x54] == 0xFF;
|
||||
|
||||
public void UnlockAllFriendSafariSlots()
|
||||
|
||||
@@ -283,7 +283,7 @@ public override int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, i
|
||||
|
||||
public string Rival
|
||||
{
|
||||
get => GetString(0x55F4, 0x1A);
|
||||
get => GetString(Data.AsSpan(0x55F4, 0x1A));
|
||||
set => SetString(Data.AsSpan(0x55F4, 0x1A), value, MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ public override int PartyCount
|
||||
}
|
||||
|
||||
public override PB8 GetDecryptedPKM(byte[] data) => GetPKM(DecryptPKM(data));
|
||||
public override PB8 GetBoxSlot(int offset) => GetDecryptedPKM(GetData(Data, offset, SIZE_PARTY)); // party format in boxes!
|
||||
public override PB8 GetBoxSlot(int offset) => GetDecryptedPKM(Data.AsSpan(offset, SIZE_PARTY).ToArray()); // party format in boxes!
|
||||
|
||||
public enum TopMenuItemType
|
||||
{
|
||||
|
||||
@@ -130,8 +130,8 @@ protected override SAV8LA CloneInternal()
|
||||
public override int PlayedMinutes { get => Played.PlayedMinutes; set => Played.PlayedMinutes = (byte)value; }
|
||||
public override int PlayedSeconds { get => Played.PlayedSeconds; set => Played.PlayedSeconds = (byte)value; }
|
||||
|
||||
protected override byte[] BoxBuffer => BoxInfo.Data;
|
||||
protected override byte[] PartyBuffer => PartyInfo.Data;
|
||||
protected override Span<byte> BoxBuffer => BoxInfo.Data;
|
||||
protected override Span<byte> PartyBuffer => PartyInfo.Data;
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
|
||||
@@ -246,10 +246,10 @@ public override int PartyCount
|
||||
protected set => PartyInfo.PartyCount = value;
|
||||
}
|
||||
|
||||
protected override byte[] BoxBuffer => BoxInfo.Data;
|
||||
protected override byte[] PartyBuffer => PartyInfo.Data;
|
||||
protected override Span<byte> BoxBuffer => BoxInfo.Data;
|
||||
protected override Span<byte> PartyBuffer => PartyInfo.Data;
|
||||
public override PK8 GetDecryptedPKM(byte[] data) => GetPKM(DecryptPKM(data));
|
||||
public override PK8 GetBoxSlot(int offset) => GetDecryptedPKM(GetData(BoxInfo.Data, offset, SIZE_PARTY)); // party format in boxes!
|
||||
public override PK8 GetBoxSlot(int offset) => GetDecryptedPKM(BoxInfo.Data.AsSpan(offset, SIZE_PARTY).ToArray()); // party format in boxes!
|
||||
|
||||
public int GetRecord(int recordID) => Records.GetRecord(recordID);
|
||||
public void SetRecord(int recordID, int value) => Records.SetRecord(recordID, value);
|
||||
|
||||
@@ -217,10 +217,10 @@ public override int PartyCount
|
||||
protected set => PartyInfo.PartyCount = value;
|
||||
}
|
||||
|
||||
protected override byte[] BoxBuffer => BoxInfo.Data;
|
||||
protected override byte[] PartyBuffer => PartyInfo.Data;
|
||||
protected override Span<byte> BoxBuffer => BoxInfo.Data;
|
||||
protected override Span<byte> PartyBuffer => PartyInfo.Data;
|
||||
public override PK9 GetDecryptedPKM(byte[] data) => GetPKM(DecryptPKM(data));
|
||||
public override PK9 GetBoxSlot(int offset) => GetDecryptedPKM(GetData(BoxInfo.Data, offset, SIZE_PARTY)); // party format in boxes!
|
||||
public override PK9 GetBoxSlot(int offset) => GetDecryptedPKM(BoxInfo.Data.AsSpan(offset, SIZE_PARTY).ToArray()); // party format in boxes!
|
||||
|
||||
//public int GetRecord(int recordID) => Records.GetRecord(recordID);
|
||||
//public void SetRecord(int recordID, int value) => Records.SetRecord(recordID, value);
|
||||
|
||||
@@ -67,19 +67,15 @@ protected virtual byte[] GetFinalData()
|
||||
#endregion
|
||||
|
||||
#region Savedata Container Handling
|
||||
public byte[] GetData(int offset, int length) => GetData(Data, offset, length);
|
||||
protected static byte[] GetData(byte[] data, int offset, int length) => data.Slice(offset, length);
|
||||
public void SetData(byte[] input, int offset) => SetData(Data, input, offset);
|
||||
public void SetData(ReadOnlySpan<byte> input, int offset) => SetData(Data, input, offset);
|
||||
public void SetData(ReadOnlySpan<byte> input, int offset) => SetData(Data.AsSpan(offset), input);
|
||||
|
||||
public void SetData(Span<byte> dest, ReadOnlySpan<byte> input, int offset)
|
||||
public void SetData(Span<byte> dest, ReadOnlySpan<byte> input)
|
||||
{
|
||||
input.CopyTo(dest[offset..]);
|
||||
input.CopyTo(dest);
|
||||
State.Edited = true;
|
||||
}
|
||||
|
||||
public abstract string GetString(ReadOnlySpan<byte> data);
|
||||
public string GetString(int offset, int length) => GetString(Data.AsSpan(offset, length));
|
||||
public abstract int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength, StringConverterOption option);
|
||||
#endregion
|
||||
|
||||
@@ -206,7 +202,7 @@ public IList<PKM> PartyData
|
||||
|
||||
PKM[] data = new PKM[count];
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
data[i] = GetPartySlot(PartyBuffer, GetPartyOffset(i));
|
||||
data[i] = GetPartySlotAtIndex(i);
|
||||
return data;
|
||||
}
|
||||
set
|
||||
@@ -219,10 +215,10 @@ public IList<PKM> PartyData
|
||||
#endif
|
||||
int ctr = 0;
|
||||
foreach (var exist in value.Where(pk => pk.Species != 0))
|
||||
SetPartySlot(exist, PartyBuffer, GetPartyOffset(ctr++));
|
||||
SetPartySlotAtIndex(exist, ctr++);
|
||||
PartyCount = ctr;
|
||||
for (int i = ctr; i < 6; i++)
|
||||
SetPartySlot(BlankPKM, PartyBuffer, GetPartyOffset(i));
|
||||
SetPartySlotAtIndex(BlankPKM, i);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -248,7 +244,8 @@ public IList<PKM> PartyData
|
||||
public virtual void SetDaycareOccupied(int loc, int slot, bool occupied) { }
|
||||
#endregion
|
||||
|
||||
public PKM GetPartySlotAtIndex(int index) => GetPartySlot(PartyBuffer, GetPartyOffset(index));
|
||||
private Span<byte> GetPartySpan(int index) => PartyBuffer[GetPartyOffset(index)..];
|
||||
public PKM GetPartySlotAtIndex(int index) => GetPartySlot(GetPartySpan(index));
|
||||
|
||||
public void SetPartySlotAtIndex(PKM pk, int index, PKMImportSetting trade = PKMImportSetting.UseDefault, PKMImportSetting dex = PKMImportSetting.UseDefault)
|
||||
{
|
||||
@@ -267,48 +264,39 @@ public void SetPartySlotAtIndex(PKM pk, int index, PKMImportSetting trade = PKMI
|
||||
PartyCount = index;
|
||||
}
|
||||
|
||||
int offset = GetPartyOffset(index);
|
||||
SetPartySlot(pk, PartyBuffer, offset, trade, dex);
|
||||
SetPartySlot(pk, GetPartySpan(index), trade, dex);
|
||||
}
|
||||
|
||||
public void SetSlotFormatParty(PKM pk, byte[] data, int offset, PKMImportSetting trade = PKMImportSetting.UseDefault, PKMImportSetting dex = PKMImportSetting.UseDefault)
|
||||
public void SetSlotFormatParty(PKM pk, Span<byte> data, PKMImportSetting trade = PKMImportSetting.UseDefault, PKMImportSetting dex = PKMImportSetting.UseDefault)
|
||||
{
|
||||
if (pk.GetType() != PKMType)
|
||||
throw new ArgumentException($"PKM Format needs to be {PKMType} when setting to this Save File.");
|
||||
|
||||
UpdatePKM(pk, isParty: true, trade, dex);
|
||||
SetPartyValues(pk, isParty: true);
|
||||
WritePartySlot(pk, data, offset);
|
||||
WritePartySlot(pk, data);
|
||||
}
|
||||
|
||||
public void SetPartySlot(PKM pk, byte[] data, int offset, PKMImportSetting trade = PKMImportSetting.UseDefault, PKMImportSetting dex = PKMImportSetting.UseDefault)
|
||||
{
|
||||
if (pk.GetType() != PKMType)
|
||||
throw new ArgumentException($"PKM Format needs to be {PKMType} when setting to this Save File.");
|
||||
|
||||
UpdatePKM(pk, isParty: true, trade, dex);
|
||||
SetPartyValues(pk, isParty: true);
|
||||
WritePartySlot(pk, data, offset);
|
||||
}
|
||||
|
||||
public void SetSlotFormatStored(PKM pk, Span<byte> data, int offset, PKMImportSetting trade = PKMImportSetting.UseDefault, PKMImportSetting dex = PKMImportSetting.UseDefault)
|
||||
public void SetSlotFormatStored(PKM pk, Span<byte> data, PKMImportSetting trade = PKMImportSetting.UseDefault, PKMImportSetting dex = PKMImportSetting.UseDefault)
|
||||
{
|
||||
if (pk.GetType() != PKMType)
|
||||
throw new ArgumentException($"PKM Format needs to be {PKMType} when setting to this Save File.");
|
||||
|
||||
UpdatePKM(pk, isParty: false, trade, dex);
|
||||
SetPartyValues(pk, isParty: false);
|
||||
WriteSlotFormatStored(pk, data, offset);
|
||||
WriteSlotFormatStored(pk, data);
|
||||
}
|
||||
|
||||
public void SetBoxSlot(PKM pk, Span<byte> data, int offset, PKMImportSetting trade = PKMImportSetting.UseDefault, PKMImportSetting dex = PKMImportSetting.UseDefault)
|
||||
public void SetPartySlot(PKM pk, Span<byte> data, PKMImportSetting trade = PKMImportSetting.UseDefault, PKMImportSetting dex = PKMImportSetting.UseDefault) => SetSlotFormatParty(pk, data, trade, dex);
|
||||
|
||||
public void SetBoxSlot(PKM pk, Span<byte> data, PKMImportSetting trade = PKMImportSetting.UseDefault, PKMImportSetting dex = PKMImportSetting.UseDefault)
|
||||
{
|
||||
if (pk.GetType() != PKMType)
|
||||
throw new ArgumentException($"PKM Format needs to be {PKMType} when setting to this Save File.");
|
||||
|
||||
UpdatePKM(pk, isParty: false, trade, dex);
|
||||
SetPartyValues(pk, isParty: false);
|
||||
WriteBoxSlot(pk, data, offset);
|
||||
WriteBoxSlot(pk, data);
|
||||
}
|
||||
|
||||
public void DeletePartySlot(int slot)
|
||||
@@ -340,23 +328,23 @@ public void DeletePartySlot(int slot)
|
||||
public abstract int MaxEV { get; }
|
||||
public virtual int MaxIV => 31;
|
||||
public abstract ReadOnlySpan<ushort> HeldItems { get; }
|
||||
protected virtual byte[] BoxBuffer => Data;
|
||||
protected virtual byte[] PartyBuffer => Data;
|
||||
protected virtual Span<byte> BoxBuffer => Data;
|
||||
protected virtual Span<byte> PartyBuffer => Data;
|
||||
public virtual bool IsPKMPresent(ReadOnlySpan<byte> data) => EntityDetection.IsPresent(data);
|
||||
public virtual PKM GetDecryptedPKM(byte[] data) => GetPKM(DecryptPKM(data));
|
||||
public virtual PKM GetPartySlot(byte[] data, int offset) => GetDecryptedPKM(GetData(data, offset, SIZE_PARTY));
|
||||
public virtual PKM GetStoredSlot(byte[] data, int offset) => GetDecryptedPKM(GetData(data, offset, SIZE_STORED));
|
||||
public virtual PKM GetBoxSlot(int offset) => GetStoredSlot(BoxBuffer, offset);
|
||||
public virtual PKM GetPartySlot(ReadOnlySpan<byte> data) => GetDecryptedPKM(data[..SIZE_PARTY].ToArray());
|
||||
public virtual PKM GetStoredSlot(ReadOnlySpan<byte> data) => GetDecryptedPKM(data[..SIZE_STORED].ToArray());
|
||||
public virtual PKM GetBoxSlot(int offset) => GetStoredSlot(BoxBuffer[offset..]);
|
||||
|
||||
public virtual byte[] GetDataForFormatStored(PKM pk) => pk.EncryptedBoxData;
|
||||
public virtual byte[] GetDataForFormatParty(PKM pk) => pk.EncryptedPartyData;
|
||||
public virtual byte[] GetDataForParty(PKM pk) => pk.EncryptedPartyData;
|
||||
public virtual byte[] GetDataForBox(PKM pk) => pk.EncryptedBoxData;
|
||||
|
||||
public virtual void WriteSlotFormatStored(PKM pk, Span<byte> data, int offset) => SetData(data, GetDataForFormatStored(pk), offset);
|
||||
public virtual void WriteSlotFormatParty(PKM pk, Span<byte> data, int offset) => SetData(data, GetDataForFormatParty(pk), offset);
|
||||
public virtual void WritePartySlot(PKM pk, Span<byte> data, int offset) => SetData(data, GetDataForParty(pk), offset);
|
||||
public virtual void WriteBoxSlot(PKM pk, Span<byte> data, int offset) => SetData(data, GetDataForBox(pk), offset);
|
||||
public virtual void WriteSlotFormatStored(PKM pk, Span<byte> data) => SetData(data, GetDataForFormatStored(pk));
|
||||
public virtual void WriteSlotFormatParty(PKM pk, Span<byte> data) => SetData(data, GetDataForFormatParty(pk));
|
||||
public virtual void WritePartySlot(PKM pk, Span<byte> data) => SetData(data, GetDataForParty(pk));
|
||||
public virtual void WriteBoxSlot(PKM pk, Span<byte> data) => SetData(data, GetDataForBox(pk));
|
||||
|
||||
protected virtual void SetPartyValues(PKM pk, bool isParty)
|
||||
{
|
||||
@@ -522,13 +510,15 @@ public void AddBoxData(IList<PKM> data, int box, int index)
|
||||
|
||||
public int NextOpenBoxSlot(int lastKnownOccupied = -1)
|
||||
{
|
||||
var storage = BoxBuffer.AsSpan();
|
||||
var storage = BoxBuffer;
|
||||
int count = SlotCount;
|
||||
for (int i = lastKnownOccupied + 1; i < count; i++)
|
||||
{
|
||||
int offset = GetBoxSlotOffset(i);
|
||||
if (!IsPKMPresent(storage[offset..]))
|
||||
return i;
|
||||
// overwrite protect is only true if there is already data in slot
|
||||
if (IsPKMPresent(storage[offset..]))
|
||||
continue;
|
||||
return i;
|
||||
}
|
||||
return StorageFullValue;
|
||||
}
|
||||
@@ -593,10 +583,10 @@ public int GetBoxSlotOffset(int index)
|
||||
}
|
||||
|
||||
public void SetBoxSlotAtIndex(PKM pk, int box, int slot, PKMImportSetting trade = PKMImportSetting.UseDefault, PKMImportSetting dex = PKMImportSetting.UseDefault)
|
||||
=> SetBoxSlot(pk, BoxBuffer, GetBoxSlotOffset(box, slot), trade, dex);
|
||||
=> SetBoxSlot(pk, BoxBuffer[GetBoxSlotOffset(box, slot)..], trade, dex);
|
||||
|
||||
public void SetBoxSlotAtIndex(PKM pk, int index, PKMImportSetting trade = PKMImportSetting.UseDefault, PKMImportSetting dex = PKMImportSetting.UseDefault)
|
||||
=> SetBoxSlot(pk, BoxBuffer, GetBoxSlotOffset(index), trade, dex);
|
||||
=> SetBoxSlot(pk, BoxBuffer[GetBoxSlotOffset(index)..], trade, dex);
|
||||
#endregion
|
||||
|
||||
#region Storage Manipulations
|
||||
@@ -612,7 +602,7 @@ public bool MoveBox(int box, int insertBeforeBox)
|
||||
return true;
|
||||
}
|
||||
|
||||
private void MoveBox(int box, int insertBeforeBox, byte[] storage)
|
||||
private void MoveBox(int box, int insertBeforeBox, Span<byte> storage)
|
||||
{
|
||||
int pos1 = BoxSlotCount * box;
|
||||
int pos2 = BoxSlotCount * insertBeforeBox;
|
||||
@@ -620,7 +610,7 @@ private void MoveBox(int box, int insertBeforeBox, byte[] storage)
|
||||
int max = Math.Max(pos1, pos2);
|
||||
|
||||
int len = BoxSlotCount * SIZE_BOXSLOT;
|
||||
byte[] boxdata = storage.Slice(GetBoxOffset(0), len * BoxCount); // get all boxes
|
||||
byte[] boxdata = storage.Slice(GetBoxOffset(0), len * BoxCount).ToArray(); // get all boxes
|
||||
string[] boxNames = Get(GetBoxName, BoxCount);
|
||||
int[] boxWallpapers = Get(GetBoxWallpaper, BoxCount);
|
||||
|
||||
@@ -646,7 +636,7 @@ static T[] Get<T>(Func<int, T> act, int count)
|
||||
b = ctr++;
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(boxdata, len * i, storage, GetBoxOffset(b), len);
|
||||
boxdata.AsSpan(len * i, len).CopyTo(storage[GetBoxOffset(b)..]);
|
||||
SetBoxName(b, boxNames[i]);
|
||||
SetBoxWallpaper(b, boxWallpapers[i]);
|
||||
}
|
||||
@@ -754,7 +744,7 @@ public int SortBoxes(int BoxStart = 0, int BoxEnd = -1, Func<IEnumerable<PKM>, i
|
||||
/// <returns>Count of deleted <see cref="PKM"/> slots.</returns>
|
||||
public int ClearBoxes(int BoxStart = 0, int BoxEnd = -1, Func<PKM, bool>? deleteCriteria = null)
|
||||
{
|
||||
var storage = BoxBuffer.AsSpan();
|
||||
var storage = BoxBuffer;
|
||||
|
||||
if ((uint)BoxEnd >= BoxCount)
|
||||
BoxEnd = BoxCount - 1;
|
||||
@@ -777,7 +767,7 @@ public int ClearBoxes(int BoxStart = 0, int BoxEnd = -1, Func<PKM, bool>? delete
|
||||
continue;
|
||||
}
|
||||
|
||||
SetData(storage, blank, ofs);
|
||||
SetData(storage[ofs..], blank);
|
||||
++deleted;
|
||||
}
|
||||
}
|
||||
@@ -796,7 +786,7 @@ public int ModifyBoxes(Action<PKM> action, int BoxStart = 0, int BoxEnd = -1)
|
||||
if ((uint)BoxEnd >= BoxCount)
|
||||
BoxEnd = BoxCount - 1;
|
||||
|
||||
var storage = BoxBuffer.AsSpan();
|
||||
var storage = BoxBuffer;
|
||||
int modified = 0;
|
||||
for (int b = BoxStart; b <= BoxEnd; b++)
|
||||
{
|
||||
@@ -805,12 +795,13 @@ public int ModifyBoxes(Action<PKM> action, int BoxStart = 0, int BoxEnd = -1)
|
||||
if (IsSlotOverwriteProtected(b, s))
|
||||
continue;
|
||||
var ofs = GetBoxSlotOffset(b, s);
|
||||
if (!IsPKMPresent(storage[ofs..]))
|
||||
var dest = storage[ofs..];
|
||||
if (!IsPKMPresent(dest))
|
||||
continue;
|
||||
var pk = GetBoxSlotAtIndex(b, s);
|
||||
action(pk);
|
||||
++modified;
|
||||
SetBoxSlot(pk, storage, ofs, PKMImportSetting.Skip, PKMImportSetting.Skip);
|
||||
SetBoxSlot(pk, dest, PKMImportSetting.Skip, PKMImportSetting.Skip);
|
||||
}
|
||||
}
|
||||
return modified;
|
||||
@@ -846,7 +837,7 @@ public virtual void SetBoxWallpaper(int box, int value)
|
||||
public byte[] GetPCBinary() => BoxData.SelectMany(GetDataForBox).ToArray();
|
||||
public byte[] GetBoxBinary(int box) => GetBoxData(box).SelectMany(GetDataForBox).ToArray();
|
||||
|
||||
public bool SetPCBinary(byte[] data)
|
||||
public bool SetPCBinary(ReadOnlySpan<byte> data)
|
||||
{
|
||||
if (IsRegionOverwriteProtected(0, SlotCount))
|
||||
return false;
|
||||
@@ -855,7 +846,7 @@ public bool SetPCBinary(byte[] data)
|
||||
return SetConcatenatedBinary(data, expectLength);
|
||||
}
|
||||
|
||||
public bool SetBoxBinary(byte[] data, int box)
|
||||
public bool SetBoxBinary(ReadOnlySpan<byte> data, int box)
|
||||
{
|
||||
int start = box * BoxSlotCount;
|
||||
int end = start + BoxSlotCount;
|
||||
@@ -867,16 +858,22 @@ public bool SetBoxBinary(byte[] data, int box)
|
||||
return SetConcatenatedBinary(data, expectLength, start);
|
||||
}
|
||||
|
||||
private bool SetConcatenatedBinary(byte[] data, int expectLength, int start = 0)
|
||||
private bool SetConcatenatedBinary(ReadOnlySpan<byte> data, int expectLength, int start = 0)
|
||||
{
|
||||
if (data.Length != expectLength)
|
||||
return false;
|
||||
|
||||
var BD = BoxData;
|
||||
var entryLength = SIZE_BOXSLOT;
|
||||
var pkdata = ArrayUtil.EnumerateSplit(data, entryLength);
|
||||
|
||||
pkdata.Select(GetPKM).CopyTo(BD, IsSlotOverwriteProtected, start);
|
||||
for (int i = 0, ctr = start; i < data.Length; i += entryLength)
|
||||
{
|
||||
if (IsSlotOverwriteProtected(ctr))
|
||||
continue;
|
||||
var src = data.Slice(i, entryLength);
|
||||
var arr = src.ToArray();
|
||||
var pk = GetPKM(arr);
|
||||
SetBoxSlotAtIndex(pk, ctr++);
|
||||
}
|
||||
BoxData = BD;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
@@ -22,6 +21,6 @@ public sealed class Bank3 : BulkStorage
|
||||
|
||||
private int BoxDataSize => SlotsPerBox * SIZE_STORED;
|
||||
public override int GetBoxOffset(int box) => Box + (BoxDataSize * box);
|
||||
public override string GetBoxName(int box) => GetString(GetBoxNameOffset(box), BoxNameSize);
|
||||
public override string GetBoxName(int box) => GetString(Data.AsSpan(GetBoxNameOffset(box), BoxNameSize));
|
||||
private static int GetBoxNameOffset(int box) => 0x25800 + (9 * box);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
@@ -22,6 +21,6 @@ public sealed class Bank4 : BulkStorage
|
||||
|
||||
private int BoxDataSize => SlotsPerBox * SIZE_STORED;
|
||||
public override int GetBoxOffset(int box) => Box + (BoxDataSize * box);
|
||||
public override string GetBoxName(int box) => GetString(GetBoxNameOffset(box), BoxNameSize / 2);
|
||||
public override string GetBoxName(int box) => GetString(Data.AsSpan(GetBoxNameOffset(box), BoxNameSize / 2));
|
||||
private static int GetBoxNameOffset(int box) => 0x3FC00 + (0x19 * box);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
@@ -28,7 +27,7 @@ public string GetGroupName(int group)
|
||||
if ((uint)group > 10)
|
||||
throw new ArgumentOutOfRangeException(nameof(group), $"{nameof(group)} must be 0-10.");
|
||||
int offset = 0x8 + (GroupNameSpacing * group) + 2; // skip over " "
|
||||
return GetString(offset, GroupNameSize / 2);
|
||||
return GetString(Data.AsSpan(offset, GroupNameSize / 2));
|
||||
}
|
||||
|
||||
public override int BoxCount => BankCount;
|
||||
@@ -47,7 +46,7 @@ private int BankCount
|
||||
|
||||
private int BoxDataSize => (SlotsPerBox * SIZE_STORED) + BankNameSpacing;
|
||||
public override int GetBoxOffset(int box) => Box + (BoxDataSize * box);
|
||||
public override string GetBoxName(int box) => GetString(GetBoxNameOffset(box), BankNameSize / 2);
|
||||
public override string GetBoxName(int box) => GetString(Data.AsSpan(GetBoxNameOffset(box), BankNameSize / 2));
|
||||
public int GetBoxNameOffset(int box) => GetBoxOffset(box) + (SlotsPerBox * SIZE_STORED);
|
||||
public int GetBoxIndex(int box) => ReadUInt16LittleEndian(Data.AsSpan(GetBoxNameOffset(box) + BankNameSize));
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
@@ -51,7 +50,7 @@ public SAV4Ranch(byte[] data) : base(data, typeof(RK4), 0)
|
||||
{
|
||||
Version = Data.Length == SaveUtil.SIZE_G4RANCH_PLAT ? GameVersion.Pt : GameVersion.DP;
|
||||
|
||||
OT = GetString(0x770, 0x12);
|
||||
OT = GetString(Data.AsSpan(0x770, 0x12));
|
||||
|
||||
// 0x18 starts the header table: [u32 BlockID, u32 Offset]
|
||||
// Block 00, Offset = Metadata object
|
||||
@@ -109,7 +108,7 @@ public void SetRanchToy(RanchToy toy, int index)
|
||||
toy = BlankToy;
|
||||
|
||||
int toyOffset = ToyBaseOffset + (RanchToy.SIZE * index);
|
||||
SetData(Data, toy.Data, toyOffset);
|
||||
SetData(Data.AsSpan(toyOffset), toy.Data);
|
||||
}
|
||||
|
||||
public RanchMii GetRanchMii(int index)
|
||||
@@ -128,7 +127,7 @@ public void SetRanchMii(RanchMii trainer, int index)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
int offset = MiiDataOffset + (RanchMii.SIZE * index);
|
||||
SetData(Data, trainer.Data, offset);
|
||||
SetData(Data.AsSpan(offset), trainer.Data);
|
||||
}
|
||||
|
||||
public RanchTrainerMii GetRanchTrainerMii(int index)
|
||||
@@ -147,7 +146,7 @@ public void SetRanchTrainerMii(RanchTrainerMii mii, int index)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
int offset = TrainerMiiDataOffset + (RanchTrainerMii.SIZE * index);
|
||||
SetData(Data, mii.Data, offset);
|
||||
SetData(Data.AsSpan(offset), mii.Data);
|
||||
}
|
||||
|
||||
private const int sha1HashSize = 20;
|
||||
@@ -155,9 +154,8 @@ public void SetRanchTrainerMii(RanchTrainerMii mii, int index)
|
||||
protected override void SetChecksums()
|
||||
{
|
||||
var data = Data.AsSpan();
|
||||
// ensure the final data is cleared if the user screws stuff up
|
||||
WriteInt32BigEndian(data[DataEndMarkerOffset..], DataEndMarker);
|
||||
data[(DataEndMarkerOffset + 4)..].Clear();
|
||||
var slotCount = GetOccupiedSlotCount();
|
||||
UpdateMetadata(slotCount * SIZE_STORED);
|
||||
|
||||
// 20 byte SHA checksum at the top of the file, which covers all data that follows.
|
||||
var hash = data[..sha1HashSize];
|
||||
@@ -165,6 +163,20 @@ protected override void SetChecksums()
|
||||
SHA1.HashData(payload, hash);
|
||||
}
|
||||
|
||||
private int GetOccupiedSlotCount()
|
||||
{
|
||||
int count = SlotCount;
|
||||
for (int i = count - 1; i >= 0; i--)
|
||||
{
|
||||
var ofs = GetBoxSlotOffset(i);
|
||||
var span = Data.AsSpan(ofs, SIZE_STORED);
|
||||
var type = ReadUInt64LittleEndian(span[0x88..]);
|
||||
if (type != 0)
|
||||
return i + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override byte[] DecryptPKM(byte[] data)
|
||||
{
|
||||
var pokeData = PokeCrypto.DecryptArray45(data.Slice(0, PokeCrypto.SIZE_4STORED));
|
||||
@@ -176,7 +188,7 @@ protected override byte[] DecryptPKM(byte[] data)
|
||||
return finalData;
|
||||
}
|
||||
|
||||
public void WriteBoxSlotInternal(PKM pk, Span<byte> data, int offset, string htName = "", ushort htTID = 0, ushort htSID = 0, RanchOwnershipType type = RanchOwnershipType.Hayley)
|
||||
public void WriteBoxSlotInternal(PKM pk, Span<byte> data, string htName = "", ushort htTID = 0, ushort htSID = 0, RanchOwnershipType type = RanchOwnershipType.Hayley)
|
||||
{
|
||||
RK4 rk = (RK4)this.GetCompatiblePKM(pk);
|
||||
rk.OwnershipType = type;
|
||||
@@ -184,33 +196,38 @@ public void WriteBoxSlotInternal(PKM pk, Span<byte> data, int offset, string htN
|
||||
rk.HT_SID = htSID;
|
||||
rk.HT_Name = htName;
|
||||
|
||||
WriteBoxSlot(rk, data, offset);
|
||||
WriteBoxSlot(rk, data);
|
||||
}
|
||||
|
||||
public override void WriteBoxSlot(PKM pk, Span<byte> data, int offset)
|
||||
public override void WriteBoxSlot(PKM pk, Span<byte> data)
|
||||
{
|
||||
bool isBlank = pk.Data.SequenceEqual(BlankPKM.Data);
|
||||
if (pk is not RK4 rk4)
|
||||
{
|
||||
WriteBoxSlotInternal(pk, data, offset);
|
||||
WriteBoxSlotInternal(pk, data);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isBlank = pk.Data.SequenceEqual(BlankPKM.Data);
|
||||
if (!isBlank && rk4.OwnershipType == RanchOwnershipType.None)
|
||||
rk4.OwnershipType = RanchOwnershipType.Hayley; // Pokemon without an Ownership type get erased when the save is loaded. Hayley is considered 'default'.
|
||||
|
||||
base.WriteBoxSlot(rk4, data, offset);
|
||||
if ((offset + SIZE_STORED) > DataEndMarkerOffset)
|
||||
base.WriteBoxSlot(rk4, data);
|
||||
}
|
||||
|
||||
private void UpdateMetadata(int pkEnd)
|
||||
{
|
||||
var data = Data.AsSpan();
|
||||
// ensure the final data is cleared if the user screws stuff up
|
||||
{
|
||||
DataEndMarkerOffset = (offset + SIZE_STORED);
|
||||
WriteInt32BigEndian(Data.AsSpan(0x3C), DataEndMarkerOffset);
|
||||
WriteInt32BigEndian(Data.AsSpan(DataEndMarkerOffset), DataEndMarker);
|
||||
DataEndMarkerOffset = pkEnd;
|
||||
WriteInt32BigEndian(data[0x3C..], pkEnd);
|
||||
WriteInt32BigEndian(data[pkEnd..], DataEndMarker);
|
||||
data[(pkEnd + 4)..].Clear();
|
||||
}
|
||||
|
||||
int pkStart = PokemonCountOffset + 4;
|
||||
int pkEnd = DataEndMarkerOffset;
|
||||
int pkCount = (pkEnd - pkStart) / SIZE_STORED;
|
||||
WriteInt32BigEndian(Data.AsSpan(PokemonCountOffset), pkCount);
|
||||
WriteInt32BigEndian(data[PokemonCountOffset..], pkCount);
|
||||
}
|
||||
|
||||
private TimeSpan PlayedSpan
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
@@ -36,7 +37,11 @@ private static void WritePoffins(SAV4Sinnoh sav, int offset, IReadOnlyList<Poffi
|
||||
{
|
||||
Debug.Assert(poffins.Count == Count);
|
||||
for (int i = 0; i < poffins.Count; i++)
|
||||
sav.SetData(sav.General, poffins[i].Data, offset + (i * Poffin4.SIZE));
|
||||
{
|
||||
var o = offset + (i * Poffin4.SIZE);
|
||||
var span = sav.General.AsSpan(o);
|
||||
sav.SetData(span, poffins[i].Data);
|
||||
}
|
||||
}
|
||||
|
||||
public void FillCase()
|
||||
|
||||
@@ -23,7 +23,7 @@ public EncryptedMysteryGiftAlbum GiftAlbum
|
||||
get
|
||||
{
|
||||
uint seed = ReadUInt32LittleEndian(Data.AsSpan(SeedOffset));
|
||||
byte[] wcData = SAV.GetData(Offset + FlagStart, 0xA90); // Encrypted, Decrypt
|
||||
byte[] wcData = SAV.Data.AsSpan(Offset + FlagStart, 0xA90).ToArray(); // Encrypted, Decrypt
|
||||
return GetAlbum(seed, wcData);
|
||||
}
|
||||
set
|
||||
|
||||
@@ -46,7 +46,7 @@ public DataMysteryGift GetGift(int index)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
var offset = GetGiftOffset(index);
|
||||
var data = SAV.GetData(offset, WC6.Size);
|
||||
var data = SAV.Data.AsSpan(offset, WC6.Size).ToArray();
|
||||
return new WC6(data);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
@@ -10,8 +10,8 @@ public sealed class Puff6 : SaveBlock<SAV6>
|
||||
|
||||
public Puff6(SAV6 SAV, int offset) : base(SAV) => Offset = offset;
|
||||
|
||||
public byte[] GetPuffs() => SAV.GetData(Offset, PuffSlots);
|
||||
public void SetPuffs(byte[] value) => SAV.SetData(value, Offset);
|
||||
public Span<byte> GetPuffs() => SAV.Data.AsSpan(Offset, PuffSlots);
|
||||
public void SetPuffs(ReadOnlySpan<byte> value) => SAV.SetData(value, Offset);
|
||||
|
||||
public int PuffCount
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
@@ -13,7 +13,7 @@ public FashionItem7[] Wardrobe
|
||||
{
|
||||
get
|
||||
{
|
||||
var data = SAV.GetData(Offset, 0x5A8);
|
||||
var data = SAV.Data.AsSpan(Offset, 0x5A8).ToArray();
|
||||
return Array.ConvertAll(data, b => new FashionItem7(b));
|
||||
}
|
||||
set
|
||||
@@ -32,17 +32,25 @@ public FashionItem7[] Wardrobe
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
var offsetList = SAV is SAV7USUM
|
||||
? (SAV.Gender == 0
|
||||
? new[] { 0x03A, 0x109, 0x1DA, 0x305, 0x3D9, 0x4B1, 0x584 } // M
|
||||
: new[] { 0x05E, 0x208, 0x264, 0x395, 0x3B4, 0x4F9, 0x5A8 }) // F
|
||||
: (SAV.Gender == 0
|
||||
? new[] { 0x000, 0x0FB, 0x124, 0x28F, 0x3B4, 0x452, 0x517 } // M
|
||||
: new[] { 0x000, 0x100, 0x223, 0x288, 0x3B4, 0x452, 0x517 }); // F
|
||||
|
||||
var offsetList = GetDefaultFashionOffsets(SAV);
|
||||
foreach (var ofs in offsetList)
|
||||
SAV.Data[Offset + ofs] = 3; // owned | new
|
||||
}
|
||||
|
||||
private static ReadOnlySpan<ushort> GetDefaultFashionOffsets(SAV7 sav) => sav switch
|
||||
{
|
||||
SAV7SM { Gender: 0 } => DefaultFashionOffsetSM_M,
|
||||
SAV7SM { Gender: 1 } => DefaultFashionOffsetSM_F,
|
||||
SAV7USUM { Gender: 0 } => DefaultFashionOffsetUU_M,
|
||||
SAV7USUM { Gender: 1 } => DefaultFashionOffsetUU_F,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(SAV)),
|
||||
};
|
||||
|
||||
// Offsets that are set to '3' when the game starts for a specific gender.
|
||||
private static ReadOnlySpan<ushort> DefaultFashionOffsetSM_M => new ushort[] { 0x000, 0x0FB, 0x124, 0x28F, 0x3B4, 0x452, 0x517 };
|
||||
private static ReadOnlySpan<ushort> DefaultFashionOffsetSM_F => new ushort[] { 0x000, 0x100, 0x223, 0x288, 0x3B4, 0x452, 0x517 };
|
||||
private static ReadOnlySpan<ushort> DefaultFashionOffsetUU_M => new ushort[] { 0x03A, 0x109, 0x1DA, 0x305, 0x3D9, 0x4B1, 0x584 };
|
||||
private static ReadOnlySpan<ushort> DefaultFashionOffsetUU_F => new ushort[] { 0x05E, 0x208, 0x264, 0x395, 0x3B4, 0x4F9, 0x5A8 };
|
||||
}
|
||||
|
||||
// Every fashion item is 2 bits, New Flag (high) & Owned Flag (low)
|
||||
|
||||
@@ -13,7 +13,7 @@ public sealed class FestaFacility
|
||||
public FestaFacility(SAV7 sav, int index)
|
||||
{
|
||||
ofs = (index * SIZE) + sav.Festa.Offset + 0x310;
|
||||
Data = sav.GetData(ofs, SIZE);
|
||||
Data = sav.Data.AsSpan(ofs, SIZE).ToArray();
|
||||
Language = sav.Language;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,9 @@ public ushort RotomAffection
|
||||
|
||||
public string RotomOT
|
||||
{
|
||||
get => SAV.GetString(Offset + 0x30, 0x1A);
|
||||
set => SAV.SetString(Data.AsSpan(Offset + 0x30, 0x1A), value, SAV.MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
get => SAV.GetString(RotomNameSpan);
|
||||
set => SAV.SetString(RotomNameSpan, value, SAV.MaxStringLengthOT, StringConverterOption.ClearZero);
|
||||
}
|
||||
|
||||
private Span<byte> RotomNameSpan => Data.AsSpan(Offset + 0x30, 0x1A);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
@@ -109,10 +108,10 @@ private int[] LoadPointerData()
|
||||
return list;
|
||||
}
|
||||
|
||||
private void SetPointerData(IList<int> vals)
|
||||
private void SetPointerData(ReadOnlySpan<int> vals)
|
||||
{
|
||||
var span = Data.AsSpan(Offset);
|
||||
for (int i = 0; i < vals.Count; i++)
|
||||
for (int i = 0; i < vals.Length; i++)
|
||||
WriteUInt16LittleEndian(span[(i*2)..], (ushort)vals[i]);
|
||||
vals.CopyTo(PokeListInfo);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
@@ -50,7 +50,7 @@ private WC7 GetGift(int index)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
var offset = GetGiftOffset(index);
|
||||
var data = SAV.GetData(offset, WC7.Size);
|
||||
var data = SAV.Data.AsSpan(offset, WC7.Size).ToArray();
|
||||
return new WC7(data);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
@@ -13,13 +13,14 @@ public PK7[] ResortPKM
|
||||
{
|
||||
get
|
||||
{
|
||||
PK7[] data = new PK7[ResortCount];
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
PK7[] result = new PK7[ResortCount];
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
{
|
||||
var bytes = SAV.GetData(GetResortSlotOffset(i), PokeCrypto.SIZE_6STORED);
|
||||
data[i] = new PK7(bytes);
|
||||
var ofs = GetResortSlotOffset(i);
|
||||
var data = SAV.Data.AsSpan(ofs, PokeCrypto.SIZE_6STORED).ToArray();
|
||||
result[i] = new PK7(data);
|
||||
}
|
||||
return data;
|
||||
return result;
|
||||
}
|
||||
set
|
||||
{
|
||||
@@ -27,7 +28,11 @@ public PK7[] ResortPKM
|
||||
throw new ArgumentException(nameof(ResortCount));
|
||||
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
SAV.SetSlotFormatStored(value[i], Data, GetResortSlotOffset(i));
|
||||
{
|
||||
var ofs = GetResortSlotOffset(i);
|
||||
var dest = Data.AsSpan(ofs, PokeCrypto.SIZE_6STORED);
|
||||
SAV.SetSlotFormatStored(value[i], dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace PKHeX.Core;
|
||||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Storage for the species that was fused into <see cref="Species.Kyurem"/> and <see cref="Species.Necrozma"/>.
|
||||
@@ -14,21 +16,11 @@ public static int GetFusedSlotOffset(int slot)
|
||||
return PokeCrypto.SIZE_8PARTY * slot;
|
||||
}
|
||||
|
||||
public PK8 Kyurem
|
||||
{
|
||||
get => (PK8) SAV.GetStoredSlot(Data, GetFusedSlotOffset(0));
|
||||
set => value.EncryptedBoxData.CopyTo(Data, GetFusedSlotOffset(0));
|
||||
}
|
||||
private Span<byte> GetSlotSpan(int index) => Data.AsSpan(GetFusedSlotOffset(index), PokeCrypto.SIZE_8STORED);
|
||||
private PK8 GetStoredSlot(int index) => (PK8)SAV.GetStoredSlot(GetSlotSpan(index));
|
||||
private void SetStoredSlot(PK8 pk, int index) => pk.EncryptedBoxData.CopyTo(GetSlotSpan(index));
|
||||
|
||||
public PK8 NecrozmaSolgaleo
|
||||
{
|
||||
get => (PK8)SAV.GetStoredSlot(Data, GetFusedSlotOffset(1));
|
||||
set => value.EncryptedBoxData.CopyTo(Data, GetFusedSlotOffset(1));
|
||||
}
|
||||
|
||||
public PK8 NecrozmaLunala
|
||||
{
|
||||
get => (PK8)SAV.GetStoredSlot(Data, GetFusedSlotOffset(2));
|
||||
set => value.EncryptedBoxData.CopyTo(Data, GetFusedSlotOffset(2));
|
||||
}
|
||||
public PK8 Kyurem { get => GetStoredSlot(0); set => SetStoredSlot(value, 0); }
|
||||
public PK8 NecrozmaSolgaleo { get => GetStoredSlot(1); set => SetStoredSlot(value, 1); }
|
||||
public PK8 NecrozmaLunala { get => GetStoredSlot(2); set => SetStoredSlot(value, 2); }
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public sealed class Mail2 : MailDetail
|
||||
|
||||
private const int AUTHOR_LENGTH = 7;
|
||||
|
||||
public Mail2(SAV2 sav, int index) : base(sav.GetData(GetMailOffset(index), 0x2F), GetMailOffset(index))
|
||||
public Mail2(SAV2 sav, int index) : base(sav.Data.AsSpan(GetMailOffset(index), 0x2F).ToArray(), GetMailOffset(index))
|
||||
{
|
||||
US = sav is { Japanese: false, Korean: false };
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public Mail4(byte? lang, byte? ver) : base(new byte[SIZE])
|
||||
ResetData();
|
||||
}
|
||||
|
||||
public override void CopyTo(SaveFile sav) => sav.SetData(((SAV4)sav).General, Data, DataOffset);
|
||||
public override void CopyTo(SaveFile sav) => sav.SetData(((SAV4)sav).General.AsSpan(DataOffset), Data);
|
||||
|
||||
private void ResetData()
|
||||
{
|
||||
|
||||
@@ -26,9 +26,9 @@ public static class ArrayUtil
|
||||
public static int Count<T>(this ReadOnlySpan<T> data, T value) where T : IEquatable<T>
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = data.Length - 1; i >= 0; i--)
|
||||
foreach (var t in data)
|
||||
{
|
||||
if (data[i].Equals(value))
|
||||
if (t.Equals(value))
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
@@ -86,26 +86,6 @@ public static int FindNextValidIndex<T>(IList<T> dest, Func<int, bool> skip, int
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies an <see cref="IEnumerable{T}"/> list to the destination list, with an option to copy to a starting point.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Typed object to copy</typeparam>
|
||||
/// <param name="list">Source list to copy from</param>
|
||||
/// <param name="dest">Destination list/array</param>
|
||||
/// <param name="start">Starting point to copy to</param>
|
||||
/// <returns>Count of <see cref="T"/> copied.</returns>
|
||||
public static int CopyTo<T>(this IEnumerable<T> list, IList<T> dest, int start = 0)
|
||||
{
|
||||
int ctr = start;
|
||||
foreach (var z in list)
|
||||
{
|
||||
if ((uint)ctr >= dest.Count)
|
||||
break;
|
||||
dest[ctr++] = z;
|
||||
}
|
||||
return ctr - start;
|
||||
}
|
||||
|
||||
internal static T[] ConcatAll<T>(params T[][] arr)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
@@ -831,7 +831,7 @@ public bool ExportBackup()
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool OpenPCBoxBin(byte[] input, out string c)
|
||||
public bool OpenPCBoxBin(ReadOnlySpan<byte> input, out string c)
|
||||
{
|
||||
if (SAV.GetPCBinary().Length == input.Length)
|
||||
{
|
||||
|
||||
@@ -773,7 +773,7 @@ private void B_DumpFC_Click(object sender, EventArgs e)
|
||||
if (sfd.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var data = SAV.GetData(ofsForestCity, ofsForestCitySize);
|
||||
var data = SAV.Data.AsSpan(ofsForestCity, ofsForestCitySize).ToArray();
|
||||
File.WriteAllBytes(sfd.FileName, data);
|
||||
}
|
||||
|
||||
|
||||
@@ -300,9 +300,9 @@ private void Save()
|
||||
|
||||
private void LoadBattleAgency()
|
||||
{
|
||||
p[0] = SAV.GetStoredSlot(SAV.Data, 0x6C200);
|
||||
p[1] = SAV.GetPartySlot(SAV.Data, 0x6C2E8);
|
||||
p[2] = SAV.GetPartySlot(SAV.Data, 0x6C420);
|
||||
p[0] = SAV.GetStoredSlot(SAV.Data.AsSpan(0x6C200));
|
||||
p[1] = SAV.GetPartySlot(SAV.Data.AsSpan(0x6C2E8));
|
||||
p[2] = SAV.GetPartySlot(SAV.Data.AsSpan(0x6C420));
|
||||
LoadPictureBox();
|
||||
B_ImportParty.Visible = SAV.HasParty;
|
||||
CHK_Choosed.Checked = SAV.GetFlag(0x6C55E, 1);
|
||||
|
||||
Reference in New Issue
Block a user