diff --git a/PKHeX.Core/Editing/Saves/Slots/Info/SlotInfoMisc.cs b/PKHeX.Core/Editing/Saves/Slots/Info/SlotInfoMisc.cs
index 2e579ed6f..2c0ae6e98 100644
--- a/PKHeX.Core/Editing/Saves/Slots/Info/SlotInfoMisc.cs
+++ b/PKHeX.Core/Editing/Saves/Slots/Info/SlotInfoMisc.cs
@@ -1,3 +1,5 @@
+using System;
+
namespace PKHeX.Core;
///
@@ -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);
}
}
diff --git a/PKHeX.Core/Legality/Encounters/Data/EncounterEvent.cs b/PKHeX.Core/Legality/Encounters/Data/EncounterEvent.cs
index 58db1c776..7fc3834a9 100644
--- a/PKHeX.Core/Legality/Encounters/Data/EncounterEvent.cs
+++ b/PKHeX.Core/Legality/Encounters/Data/EncounterEvent.cs
@@ -120,7 +120,7 @@ static T[] SetArray(ICollection arr)
// rather than use Linq to build an array, just do it the quick way directly.
var result = new T[arr.Count];
- ((IReadOnlySet)arr).CopyTo(result);
+ arr.CopyTo(result, 0);
return result;
}
diff --git a/PKHeX.Core/Legality/Restrictions/Memories/MemoryContext6Data.cs b/PKHeX.Core/Legality/Restrictions/Memories/MemoryContext6Data.cs
index cf97896b3..fe890f1f3 100644
--- a/PKHeX.Core/Legality/Restrictions/Memories/MemoryContext6Data.cs
+++ b/PKHeX.Core/Legality/Restrictions/Memories/MemoryContext6Data.cs
@@ -107,7 +107,7 @@ public partial class MemoryContext6
///
/// 24bits of flags allowing certain feelings for a given memory index.
///
- private static ReadOnlySpan MemoryFeelings => new uint[]
+ private static ReadOnlySpan MemoryFeelings => new[]
{
0x000000, 0x04CBFD, 0x004BFD, 0x04CBFD, 0x04CBFD, 0xFFFBFB, 0x84FFF9, 0x47FFFF, 0xBF7FFA, 0x7660B0,
0x80BDF9, 0x88FB7A, 0x083F79, 0x0001FE, 0xCFEFFF, 0x84EBAF, 0xB368B0, 0x091F7E, 0x0320A0, 0x080DDD,
diff --git a/PKHeX.Core/Legality/Restrictions/Memories/MemoryContext8Data.cs b/PKHeX.Core/Legality/Restrictions/Memories/MemoryContext8Data.cs
index f8904d1ce..40eef5d23 100644
--- a/PKHeX.Core/Legality/Restrictions/Memories/MemoryContext8Data.cs
+++ b/PKHeX.Core/Legality/Restrictions/Memories/MemoryContext8Data.cs
@@ -291,7 +291,7 @@ public partial class MemoryContext8
/// 24bits of flags allowing certain feelings for a given memory index.
///
/// 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.
- private static ReadOnlySpan MemoryFeelings => new uint[]
+ private static ReadOnlySpan MemoryFeelings => new[]
{
0x000000, 0x04CBFD, 0x004BFD, 0x04CBFD, 0x04CBFD, 0xFFFBFB, 0x84FFF9, 0x47FFFF, 0xBF7FFA, 0x7660B0,
0x80BDF9, 0x88FB7A, 0x083F79, 0x0001FE, 0xCFEFFF, 0x84EBAF, 0xB368B0, 0x091F7E, 0x0320A0, 0x080DDD,
diff --git a/PKHeX.Core/PKM/Shared/GBPKML.cs b/PKHeX.Core/PKM/Shared/GBPKML.cs
index fae466ab9..d2a3536b2 100644
--- a/PKHeX.Core/PKM/Shared/GBPKML.cs
+++ b/PKHeX.Core/PKM/Shared/GBPKML.cs
@@ -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)
{
diff --git a/PKHeX.Core/Saves/SAV1.cs b/PKHeX.Core/Saves/SAV1.cs
index 1f720fcf8..63fa9484e 100644
--- a/PKHeX.Core/Saves/SAV1.cs
+++ b/PKHeX.Core/Saves/SAV1.cs
@@ -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 data, int offset)
+ public override void WriteSlotFormatStored(PKM pk, Span 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 data, int offset)
+ public override void WriteBoxSlot(PKM pk, Span 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;
diff --git a/PKHeX.Core/Saves/SAV1Stadium.cs b/PKHeX.Core/Saves/SAV1Stadium.cs
index ff3aa4fd9..78510137d 100644
--- a/PKHeX.Core/Saves/SAV1Stadium.cs
+++ b/PKHeX.Core/Saves/SAV1Stadium.cs
@@ -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 data, int offset)
+ public override void WriteSlotFormatStored(PKM pk, Span 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 data, int offset)
+ public override void WriteBoxSlot(PKM pk, Span 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 data)
diff --git a/PKHeX.Core/Saves/SAV1StadiumJ.cs b/PKHeX.Core/Saves/SAV1StadiumJ.cs
index 827993919..af157ae7b 100644
--- a/PKHeX.Core/Saves/SAV1StadiumJ.cs
+++ b/PKHeX.Core/Saves/SAV1StadiumJ.cs
@@ -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 data, int offset)
+ public override void WriteSlotFormatStored(PKM pk, Span 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 data, int offset)
+ public override void WriteBoxSlot(PKM pk, Span 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 data)
diff --git a/PKHeX.Core/Saves/SAV2.cs b/PKHeX.Core/Saves/SAV2.cs
index cbbc5b475..53e221988 100644
--- a/PKHeX.Core/Saves/SAV2.cs
+++ b/PKHeX.Core/Saves/SAV2.cs
@@ -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 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 value)
diff --git a/PKHeX.Core/Saves/SAV2Stadium.cs b/PKHeX.Core/Saves/SAV2Stadium.cs
index 2f0d0d22d..44912afd9 100644
--- a/PKHeX.Core/Saves/SAV2Stadium.cs
+++ b/PKHeX.Core/Saves/SAV2Stadium.cs
@@ -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);
}
diff --git a/PKHeX.Core/Saves/SAV3.cs b/PKHeX.Core/Saves/SAV3.cs
index 8a36eff29..3ce6c7c9a 100644
--- a/PKHeX.Core/Saves/SAV3.cs
+++ b/PKHeX.Core/Saves/SAV3.cs
@@ -197,8 +197,8 @@ public void WriteBothSaveSlots(Span 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 BoxBuffer => Storage;
+ protected sealed override Span 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
diff --git a/PKHeX.Core/Saves/SAV3Colosseum.cs b/PKHeX.Core/Saves/SAV3Colosseum.cs
index 8ab9ce1fd..9724cd2e7 100644
--- a/PKHeX.Core/Saves/SAV3Colosseum.cs
+++ b/PKHeX.Core/Saves/SAV3Colosseum.cs
@@ -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 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 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 Inventory
{
diff --git a/PKHeX.Core/Saves/SAV3E.cs b/PKHeX.Core/Saves/SAV3E.cs
index b43f6f65c..f374171b6 100644
--- a/PKHeX.Core/Saves/SAV3E.cs
+++ b/PKHeX.Core/Saves/SAV3E.cs
@@ -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);
}
}
diff --git a/PKHeX.Core/Saves/SAV3FRLG.cs b/PKHeX.Core/Saves/SAV3FRLG.cs
index be6d77eea..a941f3970 100644
--- a/PKHeX.Core/Saves/SAV3FRLG.cs
+++ b/PKHeX.Core/Saves/SAV3FRLG.cs
@@ -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;
diff --git a/PKHeX.Core/Saves/SAV3RS.cs b/PKHeX.Core/Saves/SAV3RS.cs
index 53801990e..18efd9ed8 100644
--- a/PKHeX.Core/Saves/SAV3RS.cs
+++ b/PKHeX.Core/Saves/SAV3RS.cs
@@ -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
diff --git a/PKHeX.Core/Saves/SAV3RSBox.cs b/PKHeX.Core/Saves/SAV3RSBox.cs
index f99ae67d6..f93fa5017 100644
--- a/PKHeX.Core/Saves/SAV3RSBox.cs
+++ b/PKHeX.Core/Saves/SAV3RSBox.cs
@@ -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 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 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 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 data, int offset)
+ public override void WriteBoxSlot(PKM pk, Span 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);
}
diff --git a/PKHeX.Core/Saves/SAV3XD.cs b/PKHeX.Core/Saves/SAV3XD.cs
index 58c940087..f5f5767a8 100644
--- a/PKHeX.Core/Saves/SAV3XD.cs
+++ b/PKHeX.Core/Saves/SAV3XD.cs
@@ -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 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 data) => GetStoredSlot(data);
- public override XK3 GetStoredSlot(byte[] data, int offset)
+ public override XK3 GetStoredSlot(ReadOnlySpan 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;
diff --git a/PKHeX.Core/Saves/SAV4.cs b/PKHeX.Core/Saves/SAV4.cs
index 0cd5f1498..3f540eef9 100644
--- a/PKHeX.Core/Saves/SAV4.cs
+++ b/PKHeX.Core/Saves/SAV4.cs
@@ -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 BoxBuffer => Storage;
+ protected sealed override Span 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 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);
diff --git a/PKHeX.Core/Saves/SAV4BR.cs b/PKHeX.Core/Saves/SAV4BR.cs
index 75c17088c..84ef086fe 100644
--- a/PKHeX.Core/Saves/SAV4BR.cs
+++ b/PKHeX.Core/Saves/SAV4BR.cs
@@ -200,16 +200,21 @@ public override ushort SID16
private int BoxName = -1;
private const int BoxNameLength = 0x28;
+ private Span 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 value)
@@ -217,8 +222,7 @@ public override void SetBoxName(int box, ReadOnlySpan 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;
diff --git a/PKHeX.Core/Saves/SAV4Sinnoh.cs b/PKHeX.Core/Saves/SAV4Sinnoh.cs
index 7f0110a02..4fabd1fa8 100644
--- a/PKHeX.Core/Saves/SAV4Sinnoh.cs
+++ b/PKHeX.Core/Saves/SAV4Sinnoh.cs
@@ -102,7 +102,7 @@ public uint PoketchStepCounter
public void SetPoketchDotArtistData(ReadOnlySpan 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);
diff --git a/PKHeX.Core/Saves/SAV5.cs b/PKHeX.Core/Saves/SAV5.cs
index 8ca380274..30a6c0a93 100644
--- a/PKHeX.Core/Saves/SAV5.cs
+++ b/PKHeX.Core/Saves/SAV5.cs
@@ -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)
diff --git a/PKHeX.Core/Saves/SAV6AO.cs b/PKHeX.Core/Saves/SAV6AO.cs
index 289af6fc4..8570ae6e4 100644
--- a/PKHeX.Core/Saves/SAV6AO.cs
+++ b/PKHeX.Core/Saves/SAV6AO.cs
@@ -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() : GetData(JPEG + 0x54, 0xE004);
+ public override byte[] GetJPEGData() => !HasJPPEGData ? Array.Empty() : 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); }
diff --git a/PKHeX.Core/Saves/SAV6XY.cs b/PKHeX.Core/Saves/SAV6XY.cs
index 7880a70e9..7c975fa66 100644
--- a/PKHeX.Core/Saves/SAV6XY.cs
+++ b/PKHeX.Core/Saves/SAV6XY.cs
@@ -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() : GetData(JPEG + 0x54, 0xE004);
+ public override byte[] GetJPEGData() => !HasJPPEGData ? Array.Empty() : Data.AsSpan(JPEG + 0x54, 0xE004).ToArray();
private bool HasJPPEGData => Data[JPEG + 0x54] == 0xFF;
public void UnlockAllFriendSafariSlots()
diff --git a/PKHeX.Core/Saves/SAV8BS.cs b/PKHeX.Core/Saves/SAV8BS.cs
index b598fd3de..83a457be0 100644
--- a/PKHeX.Core/Saves/SAV8BS.cs
+++ b/PKHeX.Core/Saves/SAV8BS.cs
@@ -283,7 +283,7 @@ public override int SetString(Span destBuffer, ReadOnlySpan 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
{
diff --git a/PKHeX.Core/Saves/SAV8LA.cs b/PKHeX.Core/Saves/SAV8LA.cs
index 9231c879d..6e9ea668f 100644
--- a/PKHeX.Core/Saves/SAV8LA.cs
+++ b/PKHeX.Core/Saves/SAV8LA.cs
@@ -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 BoxBuffer => BoxInfo.Data;
+ protected override Span PartyBuffer => PartyInfo.Data;
private void Initialize()
{
diff --git a/PKHeX.Core/Saves/SAV8SWSH.cs b/PKHeX.Core/Saves/SAV8SWSH.cs
index 5ba223e44..dba4e4246 100644
--- a/PKHeX.Core/Saves/SAV8SWSH.cs
+++ b/PKHeX.Core/Saves/SAV8SWSH.cs
@@ -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 BoxBuffer => BoxInfo.Data;
+ protected override Span 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);
diff --git a/PKHeX.Core/Saves/SAV9SV.cs b/PKHeX.Core/Saves/SAV9SV.cs
index 82ed014c9..868a4df9d 100644
--- a/PKHeX.Core/Saves/SAV9SV.cs
+++ b/PKHeX.Core/Saves/SAV9SV.cs
@@ -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 BoxBuffer => BoxInfo.Data;
+ protected override Span 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);
diff --git a/PKHeX.Core/Saves/SaveFile.cs b/PKHeX.Core/Saves/SaveFile.cs
index 131631e20..a2c596205 100644
--- a/PKHeX.Core/Saves/SaveFile.cs
+++ b/PKHeX.Core/Saves/SaveFile.cs
@@ -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 input, int offset) => SetData(Data, input, offset);
+ public void SetData(ReadOnlySpan input, int offset) => SetData(Data.AsSpan(offset), input);
- public void SetData(Span dest, ReadOnlySpan input, int offset)
+ public void SetData(Span dest, ReadOnlySpan input)
{
- input.CopyTo(dest[offset..]);
+ input.CopyTo(dest);
State.Edited = true;
}
public abstract string GetString(ReadOnlySpan data);
- public string GetString(int offset, int length) => GetString(Data.AsSpan(offset, length));
public abstract int SetString(Span destBuffer, ReadOnlySpan value, int maxLength, StringConverterOption option);
#endregion
@@ -206,7 +202,7 @@ public IList 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 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 PartyData
public virtual void SetDaycareOccupied(int loc, int slot, bool occupied) { }
#endregion
- public PKM GetPartySlotAtIndex(int index) => GetPartySlot(PartyBuffer, GetPartyOffset(index));
+ private Span 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 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 data, int offset, PKMImportSetting trade = PKMImportSetting.UseDefault, PKMImportSetting dex = PKMImportSetting.UseDefault)
+ public void SetSlotFormatStored(PKM pk, Span 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 data, int offset, PKMImportSetting trade = PKMImportSetting.UseDefault, PKMImportSetting dex = PKMImportSetting.UseDefault)
+ public void SetPartySlot(PKM pk, Span data, PKMImportSetting trade = PKMImportSetting.UseDefault, PKMImportSetting dex = PKMImportSetting.UseDefault) => SetSlotFormatParty(pk, data, trade, dex);
+
+ public void SetBoxSlot(PKM pk, Span 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 HeldItems { get; }
- protected virtual byte[] BoxBuffer => Data;
- protected virtual byte[] PartyBuffer => Data;
+ protected virtual Span BoxBuffer => Data;
+ protected virtual Span PartyBuffer => Data;
public virtual bool IsPKMPresent(ReadOnlySpan 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 data) => GetDecryptedPKM(data[..SIZE_PARTY].ToArray());
+ public virtual PKM GetStoredSlot(ReadOnlySpan 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 data, int offset) => SetData(data, GetDataForFormatStored(pk), offset);
- public virtual void WriteSlotFormatParty(PKM pk, Span data, int offset) => SetData(data, GetDataForFormatParty(pk), offset);
- public virtual void WritePartySlot(PKM pk, Span data, int offset) => SetData(data, GetDataForParty(pk), offset);
- public virtual void WriteBoxSlot(PKM pk, Span data, int offset) => SetData(data, GetDataForBox(pk), offset);
+ public virtual void WriteSlotFormatStored(PKM pk, Span data) => SetData(data, GetDataForFormatStored(pk));
+ public virtual void WriteSlotFormatParty(PKM pk, Span data) => SetData(data, GetDataForFormatParty(pk));
+ public virtual void WritePartySlot(PKM pk, Span data) => SetData(data, GetDataForParty(pk));
+ public virtual void WriteBoxSlot(PKM pk, Span data) => SetData(data, GetDataForBox(pk));
protected virtual void SetPartyValues(PKM pk, bool isParty)
{
@@ -522,13 +510,15 @@ public void AddBoxData(IList 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 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(Func 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, i
/// Count of deleted slots.
public int ClearBoxes(int BoxStart = 0, int BoxEnd = -1, Func? 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? delete
continue;
}
- SetData(storage, blank, ofs);
+ SetData(storage[ofs..], blank);
++deleted;
}
}
@@ -796,7 +786,7 @@ public int ModifyBoxes(Action 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 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 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 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 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;
}
diff --git a/PKHeX.Core/Saves/Storage/Bank3.cs b/PKHeX.Core/Saves/Storage/Bank3.cs
index 322164175..e97de240b 100644
--- a/PKHeX.Core/Saves/Storage/Bank3.cs
+++ b/PKHeX.Core/Saves/Storage/Bank3.cs
@@ -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);
}
diff --git a/PKHeX.Core/Saves/Storage/Bank4.cs b/PKHeX.Core/Saves/Storage/Bank4.cs
index fab29387f..195f961e3 100644
--- a/PKHeX.Core/Saves/Storage/Bank4.cs
+++ b/PKHeX.Core/Saves/Storage/Bank4.cs
@@ -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);
}
diff --git a/PKHeX.Core/Saves/Storage/Bank7.cs b/PKHeX.Core/Saves/Storage/Bank7.cs
index 2353926ec..aa09a5cfb 100644
--- a/PKHeX.Core/Saves/Storage/Bank7.cs
+++ b/PKHeX.Core/Saves/Storage/Bank7.cs
@@ -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));
diff --git a/PKHeX.Core/Saves/Storage/SAV4Ranch.cs b/PKHeX.Core/Saves/Storage/SAV4Ranch.cs
index 441d5f274..116a6f544 100644
--- a/PKHeX.Core/Saves/Storage/SAV4Ranch.cs
+++ b/PKHeX.Core/Saves/Storage/SAV4Ranch.cs
@@ -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 data, int offset, string htName = "", ushort htTID = 0, ushort htSID = 0, RanchOwnershipType type = RanchOwnershipType.Hayley)
+ public void WriteBoxSlotInternal(PKM pk, Span 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 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 data, int offset)
+ public override void WriteBoxSlot(PKM pk, Span 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
diff --git a/PKHeX.Core/Saves/Substructures/Gen4/PoffinCase4.cs b/PKHeX.Core/Saves/Substructures/Gen4/PoffinCase4.cs
index 0b4fcb010..7b10a86ca 100644
--- a/PKHeX.Core/Saves/Substructures/Gen4/PoffinCase4.cs
+++ b/PKHeX.Core/Saves/Substructures/Gen4/PoffinCase4.cs
@@ -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
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 GetPuffs() => SAV.Data.AsSpan(Offset, PuffSlots);
+ public void SetPuffs(ReadOnlySpan value) => SAV.SetData(value, Offset);
public int PuffCount
{
diff --git a/PKHeX.Core/Saves/Substructures/Gen7/FashionBlock7.cs b/PKHeX.Core/Saves/Substructures/Gen7/FashionBlock7.cs
index 91efcdae4..c41148f09 100644
--- a/PKHeX.Core/Saves/Substructures/Gen7/FashionBlock7.cs
+++ b/PKHeX.Core/Saves/Substructures/Gen7/FashionBlock7.cs
@@ -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
///
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 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 DefaultFashionOffsetSM_M => new ushort[] { 0x000, 0x0FB, 0x124, 0x28F, 0x3B4, 0x452, 0x517 };
+ private static ReadOnlySpan DefaultFashionOffsetSM_F => new ushort[] { 0x000, 0x100, 0x223, 0x288, 0x3B4, 0x452, 0x517 };
+ private static ReadOnlySpan DefaultFashionOffsetUU_M => new ushort[] { 0x03A, 0x109, 0x1DA, 0x305, 0x3D9, 0x4B1, 0x584 };
+ private static ReadOnlySpan DefaultFashionOffsetUU_F => new ushort[] { 0x05E, 0x208, 0x264, 0x395, 0x3B4, 0x4F9, 0x5A8 };
}
// Every fashion item is 2 bits, New Flag (high) & Owned Flag (low)
diff --git a/PKHeX.Core/Saves/Substructures/Gen7/FestaFacility.cs b/PKHeX.Core/Saves/Substructures/Gen7/FestaFacility.cs
index 32ae31a73..082529254 100644
--- a/PKHeX.Core/Saves/Substructures/Gen7/FestaFacility.cs
+++ b/PKHeX.Core/Saves/Substructures/Gen7/FestaFacility.cs
@@ -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;
}
diff --git a/PKHeX.Core/Saves/Substructures/Gen7/FieldMenu7.cs b/PKHeX.Core/Saves/Substructures/Gen7/FieldMenu7.cs
index a72835013..58a124cd3 100644
--- a/PKHeX.Core/Saves/Substructures/Gen7/FieldMenu7.cs
+++ b/PKHeX.Core/Saves/Substructures/Gen7/FieldMenu7.cs
@@ -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 RotomNameSpan => Data.AsSpan(Offset + 0x30, 0x1A);
}
diff --git a/PKHeX.Core/Saves/Substructures/Gen7/LGPE/PokeListHeader.cs b/PKHeX.Core/Saves/Substructures/Gen7/LGPE/PokeListHeader.cs
index 3ec689976..064ee7861 100644
--- a/PKHeX.Core/Saves/Substructures/Gen7/LGPE/PokeListHeader.cs
+++ b/PKHeX.Core/Saves/Substructures/Gen7/LGPE/PokeListHeader.cs
@@ -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 vals)
+ private void SetPointerData(ReadOnlySpan 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);
}
diff --git a/PKHeX.Core/Saves/Substructures/Gen7/MysteryBlock7.cs b/PKHeX.Core/Saves/Substructures/Gen7/MysteryBlock7.cs
index eaf11c460..4753bb6f8 100644
--- a/PKHeX.Core/Saves/Substructures/Gen7/MysteryBlock7.cs
+++ b/PKHeX.Core/Saves/Substructures/Gen7/MysteryBlock7.cs
@@ -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);
}
diff --git a/PKHeX.Core/Saves/Substructures/Gen7/ResortSave7.cs b/PKHeX.Core/Saves/Substructures/Gen7/ResortSave7.cs
index 32bec0b16..14062a0ba 100644
--- a/PKHeX.Core/Saves/Substructures/Gen7/ResortSave7.cs
+++ b/PKHeX.Core/Saves/Substructures/Gen7/ResortSave7.cs
@@ -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);
+ }
}
}
diff --git a/PKHeX.Core/Saves/Substructures/Gen8/BS/BerryTreeGrowSave8b.cs b/PKHeX.Core/Saves/Substructures/Gen8/BS/BerryTreeGrowSave8b.cs
index 5823f5b84..2cecdbf8b 100644
--- a/PKHeX.Core/Saves/Substructures/Gen8/BS/BerryTreeGrowSave8b.cs
+++ b/PKHeX.Core/Saves/Substructures/Gen8/BS/BerryTreeGrowSave8b.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.ComponentModel;
using static System.Buffers.Binary.BinaryPrimitives;
diff --git a/PKHeX.Core/Saves/Substructures/Gen8/SWSH/Fused8.cs b/PKHeX.Core/Saves/Substructures/Gen8/SWSH/Fused8.cs
index 70016f9ae..6402c5db6 100644
--- a/PKHeX.Core/Saves/Substructures/Gen8/SWSH/Fused8.cs
+++ b/PKHeX.Core/Saves/Substructures/Gen8/SWSH/Fused8.cs
@@ -1,4 +1,6 @@
-namespace PKHeX.Core;
+using System;
+
+namespace PKHeX.Core;
///
/// Storage for the species that was fused into and .
@@ -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 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); }
}
diff --git a/PKHeX.Core/Saves/Substructures/Mail/Mail2.cs b/PKHeX.Core/Saves/Substructures/Mail/Mail2.cs
index 8ba0e22f0..ed4e0aa10 100644
--- a/PKHeX.Core/Saves/Substructures/Mail/Mail2.cs
+++ b/PKHeX.Core/Saves/Substructures/Mail/Mail2.cs
@@ -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 };
}
diff --git a/PKHeX.Core/Saves/Substructures/Mail/Mail4.cs b/PKHeX.Core/Saves/Substructures/Mail/Mail4.cs
index 8610b1ce6..d691e905b 100644
--- a/PKHeX.Core/Saves/Substructures/Mail/Mail4.cs
+++ b/PKHeX.Core/Saves/Substructures/Mail/Mail4.cs
@@ -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()
{
diff --git a/PKHeX.Core/Util/ArrayUtil.cs b/PKHeX.Core/Util/ArrayUtil.cs
index 01e3f3ba7..602010d22 100644
--- a/PKHeX.Core/Util/ArrayUtil.cs
+++ b/PKHeX.Core/Util/ArrayUtil.cs
@@ -26,9 +26,9 @@ public static class ArrayUtil
public static int Count(this ReadOnlySpan data, T value) where T : IEquatable
{
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(IList dest, Func skip, int
}
}
- ///
- /// Copies an list to the destination list, with an option to copy to a starting point.
- ///
- /// Typed object to copy
- /// Source list to copy from
- /// Destination list/array
- /// Starting point to copy to
- /// Count of copied.
- public static int CopyTo(this IEnumerable list, IList 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(params T[][] arr)
{
int len = 0;
diff --git a/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.cs b/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.cs
index dec826170..1fe274004 100644
--- a/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.cs
+++ b/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.cs
@@ -831,7 +831,7 @@ public bool ExportBackup()
return true;
}
- public bool OpenPCBoxBin(byte[] input, out string c)
+ public bool OpenPCBoxBin(ReadOnlySpan input, out string c)
{
if (SAV.GetPCBinary().Length == input.Length)
{
diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen5/SAV_Misc5.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen5/SAV_Misc5.cs
index fe70422cd..1d5d190f5 100644
--- a/PKHeX.WinForms/Subforms/Save Editors/Gen5/SAV_Misc5.cs
+++ b/PKHeX.WinForms/Subforms/Save Editors/Gen5/SAV_Misc5.cs
@@ -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);
}
diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_FestivalPlaza.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_FestivalPlaza.cs
index cce086446..6f157b51b 100644
--- a/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_FestivalPlaza.cs
+++ b/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_FestivalPlaza.cs
@@ -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);