diff --git a/PKHeX.Core/PKM/Shared/PokeList1.cs b/PKHeX.Core/PKM/Shared/PokeList1.cs
index 765ecd0b4..6b29a6293 100644
--- a/PKHeX.Core/PKM/Shared/PokeList1.cs
+++ b/PKHeX.Core/PKM/Shared/PokeList1.cs
@@ -271,4 +271,46 @@ public static byte[] WrapSingle(PK1 pk)
/// Entity to wrap
/// Destination to write the single-slot list
public static void WrapSingle(PK1 pk, Span output) => WriteToList(output, pk);
+
+ public static void UnpackNOB(ReadOnlySpan input, Span output, int stringLength, bool isParty = false)
+ {
+ // Nickname, OT, Data
+ var lengthBody = GetBodyLength(isParty);
+ var lengthParty = GetBodyLength(true);
+ var nick = input[..stringLength];
+ var trainer = input.Slice(stringLength, stringLength);
+ var box = input.Slice(stringLength * 2, lengthBody);
+
+ var marker = box[0];
+ if (marker is 0) // Ensure deleted (zeroed) slots act as an Empty (FF) slot.
+ marker = SlotEmpty;
+
+ output[0] = 1;
+ output[1] = marker;
+ output = output[3..];
+
+ // Data, OT, Nickname
+ box.CopyTo(output);
+ output = output[lengthParty..];
+ trainer.CopyTo(output);
+ output = output[stringLength..];
+ nick.CopyTo(output);
+ }
+
+ public static void PackNOB(ReadOnlySpan input, Span output, int stringLength, bool isParty = false)
+ {
+ var lengthBody = GetBodyLength(isParty);
+ var lengthParty = GetBodyLength(true);
+
+ input = input[3..]; // Skip header.
+ var box = input[..lengthBody];
+ var trainer = input.Slice(lengthParty, stringLength);
+ var nick = input.Slice(lengthParty + stringLength, stringLength);
+
+ nick.CopyTo(output);
+ output = output[stringLength..];
+ trainer.CopyTo(output);
+ output = output[stringLength..];
+ box.CopyTo(output);
+ }
}
diff --git a/PKHeX.Core/PKM/Shared/PokeList2.cs b/PKHeX.Core/PKM/Shared/PokeList2.cs
index c2063461a..a79364d56 100644
--- a/PKHeX.Core/PKM/Shared/PokeList2.cs
+++ b/PKHeX.Core/PKM/Shared/PokeList2.cs
@@ -274,4 +274,46 @@ public static byte[] WrapSingle(PK2 pk)
/// Entity to wrap
/// Destination to write the single-slot list
public static void WrapSingle(PK2 pk, Span output) => WriteToList(output, pk);
+
+ public static void UnpackNOB(ReadOnlySpan input, Span output, int stringLength, bool isParty = false)
+ {
+ // Nickname, OT, Data
+ var lengthBody = GetBodyLength(isParty);
+ var lengthParty = GetBodyLength(true);
+ var nick = input[..stringLength];
+ var trainer = input.Slice(stringLength, stringLength);
+ var box = input.Slice(stringLength * 2, lengthBody);
+
+ var marker = box[0];
+ if (marker is 0) // Ensure deleted (zeroed) slots act as an Empty (FF) slot.
+ marker = SlotEmpty;
+
+ output[0] = 1;
+ output[1] = marker;
+ output = output[3..];
+
+ // Data, OT, Nickname
+ box.CopyTo(output);
+ output = output[lengthParty..];
+ trainer.CopyTo(output);
+ output = output[stringLength..];
+ nick.CopyTo(output);
+ }
+
+ public static void PackNOB(ReadOnlySpan input, Span output, int stringLength, bool isParty = false)
+ {
+ var lengthBody = GetBodyLength(isParty);
+ var lengthParty = GetBodyLength(true);
+
+ input = input[3..]; // Skip header.
+ var box = input[..lengthBody];
+ var trainer = input.Slice(lengthParty, stringLength);
+ var nick = input.Slice(lengthParty + stringLength, stringLength);
+
+ nick.CopyTo(output);
+ output = output[stringLength..];
+ trainer.CopyTo(output);
+ output = output[stringLength..];
+ box.CopyTo(output);
+ }
}
diff --git a/PKHeX.Core/Saves/SAV1.cs b/PKHeX.Core/Saves/SAV1.cs
index fdf26952e..1b8bbe525 100644
--- a/PKHeX.Core/Saves/SAV1.cs
+++ b/PKHeX.Core/Saves/SAV1.cs
@@ -105,20 +105,11 @@ private void Initialize(GameVersion versionOverride)
PokeList1.Unpack(src, dest, StringLength, 6, true);
}
- ReadOnlySpan rawDC = Data.AsSpan(Offsets.Daycare, 0x38);
- var daycareOffset = DaycareOffset = GetPartyOffset(6);
- var TempDaycare = BoxBuffer[daycareOffset..];
- TempDaycare[0] = rawDC[0];
-
- var dcDest = TempDaycare[3..];
-
- // OT, Nickname, and Core data (rather than the reverse...)
- rawDC.Slice(1, StringLength).CopyTo(dcDest[(PokeCrypto.SIZE_1PARTY + StringLength)..]);
- rawDC.Slice(1 + StringLength, StringLength).CopyTo(dcDest[PokeCrypto.SIZE_1PARTY..]);
- rawDC.Slice(1 + (2 * StringLength), PokeCrypto.SIZE_1STORED).CopyTo(dcDest);
+ var dc = Data.AsSpan(Offsets.Daycare, 0x38);
+ PokeList1.UnpackNOB(dc[1..], PartyBuffer[DaycareOffset..], StringLength);
}
- private int DaycareOffset = -1;
+ private int DaycareOffset => GetPartyOffset(6);
public override bool HasPokeDex => true;
// Event Flags
@@ -177,12 +168,7 @@ protected override byte[] GetFinalData()
}
// Daycare is read-only, but in case it ever becomes editable, copy it back in.
- Span rawDC = Data.AsSpan(Offsets.Daycare, 0x38);
- var TempDaycare = BoxBuffer[DaycareOffset..];
- var dcDest = TempDaycare[3..];
- dcDest.Slice(2 + 1 + PokeCrypto.SIZE_1PARTY + StringLength, StringLength).CopyTo(rawDC[1..]);
- dcDest.Slice(2 + 1 + PokeCrypto.SIZE_1PARTY, StringLength).CopyTo(rawDC[(1 + StringLength)..]);
- dcDest.Slice(2 + 1, PokeCrypto.SIZE_1STORED).CopyTo(rawDC[(1 + (2 * StringLength))..]);
+ PokeList1.PackNOB(PartyBuffer[DaycareOffset..], Data.AsSpan(Offsets.Daycare, 0x38)[1..], StringLength);
SetChecksums();
return Data;
diff --git a/PKHeX.Core/Saves/SAV2.cs b/PKHeX.Core/Saves/SAV2.cs
index 8f177863f..ce21bce8e 100644
--- a/PKHeX.Core/Saves/SAV2.cs
+++ b/PKHeX.Core/Saves/SAV2.cs
@@ -104,48 +104,43 @@ private void Initialize()
if (Offsets.Daycare >= 0)
{
- int offset = Offsets.Daycare;
+ var dc0 = PartyBuffer[GetDaycareSlotOffset(0)..];
+ PokeList2.UnpackNOB(Data.AsSpan(GetRawDaycareSlotOffset(0)), dc0, StringLength);
- offset++;
- var pk1 = ReadPKMFromOffset(offset); // parent 1
- offset += (StringLength * 2) + 0x20; // nick/ot/pk
- offset++;
- //byte steps = Data[offset];
- offset++;
- //byte BreedMotherOrNonDitto = Data[offset];
- offset++;
- var pk2 = ReadPKMFromOffset(offset); // parent 2
- offset += (StringLength * 2) + PokeCrypto.SIZE_2STORED; // nick/ot/pk
- var pk3 = ReadPKMFromOffset(offset); // egg!
- pk3.IsEgg = true;
+ var dc1 = PartyBuffer[GetDaycareSlotOffset(1)..];
+ PokeList2.UnpackNOB(Data.AsSpan(GetRawDaycareSlotOffset(1)), dc1, StringLength);
- PokeList2.WriteToList(PartyBuffer[GetPartyOffset(6 + (0 * 2))..], pk1, 1, true);
- PokeList2.WriteToList(PartyBuffer[GetPartyOffset(6 + (1 * 2))..], pk2, 1, true);
- PokeList2.WriteToList(PartyBuffer[GetPartyOffset(6 + (2 * 2))..], pk3, 1, true);
+ var egg = PartyBuffer[GetDaycareSlotOffset(2)..];
+ PokeList2.UnpackNOB(Data.AsSpan(GetRawDaycareSlotOffset(2)), egg, StringLength);
+ if (egg[2] != PokeList2.SlotEmpty)
+ egg[1] = PokeList2.SlotEgg;
}
}
+ private int GetRawDaycareSlotOffset(int index)
+ {
+ int offset = Offsets.Daycare;
+
+ offset++; // Breeding Status flags
+ if (index == 0)
+ return offset;
+
+ offset += (StringLength * 2) + PokeCrypto.SIZE_2STORED; // nick/ot/pk
+ offset++; // Lady Status flags
+ offset++; // Steps until Egg
+ offset++; // Ditto Parent state
+ if (index == 1)
+ return offset;
+
+ offset += (StringLength * 2) + PokeCrypto.SIZE_2STORED; // nick/ot/pk
+ return offset;
+ }
+
public override bool HasPokeDex => true;
private int EventFlag => Offsets.EventFlag;
private int EventWork => Offsets.EventWork;
- private PK2 ReadPKMFromOffset(int offset)
- {
- var stringLength = StringLength;
- var span = Data.AsSpan(offset);
-
- var pkData = span.Slice(stringLength * 2, PokeCrypto.SIZE_2STORED).ToArray();
- var pk = new PK2(pkData, jp: Japanese);
-
- var nick = span[..stringLength];
- var ot = span.Slice(stringLength, stringLength);
- nick.CopyTo(pk.NicknameTrash);
- ot.CopyTo(pk.OriginalTrainerTrash);
-
- return pk;
- }
-
private int GetBoxRawDataOffset(int i, int splitAtIndex)
{
if (i < splitAtIndex)
@@ -178,6 +173,20 @@ protected override byte[] GetFinalData()
PokeList2.MergeSingles(src, dest, StringLength, 6, true);
}
+ // Write Daycare
+
+ if (Offsets.Daycare >= 0)
+ {
+ var dc0 = PartyBuffer[GetDaycareSlotOffset(0)..];
+ PokeList2.PackNOB(dc0, Data.AsSpan(GetRawDaycareSlotOffset(0)), StringLength);
+
+ var dc1 = PartyBuffer[GetDaycareSlotOffset(1)..];
+ PokeList2.PackNOB(dc1, Data.AsSpan(GetRawDaycareSlotOffset(1)), StringLength);
+
+ var egg = PartyBuffer[GetDaycareSlotOffset(2)..];
+ PokeList2.PackNOB(egg, Data.AsSpan(GetRawDaycareSlotOffset(2)), StringLength);
+ }
+
SetChecksums();
if (Japanese)
{