PKHeX/PKHeX.Core/Saves/Substructures/Gen6/SecretBase/SecretBase6PKM.cs
Kurt 47071b41f3
Refactoring: Span-based value writes and method signatures (#3361)
Existing `get`/`set` logic is flawed in that it doesn't work on Big Endian operating systems, and it allocates heap objects when it doesn't need to.

`System.Buffers.Binary.BinaryPrimitives` in the `System.Memory` NuGet package provides both Little Endian and Big Endian methods to read and write data; all the `get`/`set` operations have been reworked to use this new API. This removes the need for PKHeX's manual `BigEndian` class, as all functions are already covered by the BinaryPrimitives API.

The `StringConverter` has now been rewritten to accept a Span to read from & write to, no longer requiring a temporary StringBuilder.

Other Fixes included:
- The Super Training UI for Gen6 has been reworked according to the latest block structure additions.
- Cloning a Stadium2 Save File now works correctly (opening from the Folder browser list).
- Checksum & Sanity properties removed from parent PKM class, and is now implemented via interface.
2022-01-02 21:35:59 -08:00

111 lines
4.8 KiB
C#

using System;
using static System.Buffers.Binary.BinaryPrimitives;
namespace PKHeX.Core
{
public sealed class SecretBase6PKM : ISanityChecksum
{
public const int SIZE = 0x34;
public readonly byte[] Data;
public SecretBase6PKM(byte[] data) => Data = data;
public SecretBase6PKM() => Data = new byte[SIZE];
public uint EncryptionConstant
{
get => ReadUInt32LittleEndian(Data.AsSpan(0x00));
set => WriteUInt32LittleEndian(Data.AsSpan(0x00), value);
}
public ushort Sanity
{
get => ReadUInt16LittleEndian(Data.AsSpan(0x04));
set => WriteUInt16LittleEndian(Data.AsSpan(0x04), value);
}
public ushort Checksum
{
get => ReadUInt16LittleEndian(Data.AsSpan(0x06));
set => WriteUInt16LittleEndian(Data.AsSpan(0x06), value);
}
public int Species
{
get => ReadUInt16LittleEndian(Data.AsSpan(0x08));
set => WriteUInt16LittleEndian(Data.AsSpan(0x08), (ushort)value);
}
public int HeldItem
{
get => ReadUInt16LittleEndian(Data.AsSpan(0x0A));
set => WriteUInt16LittleEndian(Data.AsSpan(0x0A), (ushort)value);
}
public int Ability { get => Data[0x0C]; set => Data[0x0C] = (byte)value; }
public int AbilityNumber { get => Data[0x0D]; set => Data[0x0D] = (byte)value; }
public uint PID
{
get => ReadUInt32LittleEndian(Data.AsSpan(0x10));
set => WriteUInt32LittleEndian(Data.AsSpan(0x10), value);
}
public int Nature { get => Data[0x14]; set => Data[0x14] = (byte)value; }
public bool FatefulEncounter { get => (Data[0x15] & 1) == 1; set => Data[0x15] = (byte)((Data[0x15] & ~0x01) | (value ? 1 : 0)); }
public int Gender { get => (Data[0x15] >> 1) & 0x3; set => Data[0x15] = (byte)((Data[0x15] & ~0x06) | (value << 1)); }
public int Form { get => Data[0x15] >> 3; set => Data[0x15] = (byte)((Data[0x15] & 0x07) | (value << 3)); }
public int EV_HP { get => Data[0x16]; set => Data[0x16] = (byte)value; }
public int EV_ATK { get => Data[0x17]; set => Data[0x17] = (byte)value; }
public int EV_DEF { get => Data[0x18]; set => Data[0x18] = (byte)value; }
public int EV_SPE { get => Data[0x19]; set => Data[0x19] = (byte)value; }
public int EV_SPA { get => Data[0x1A]; set => Data[0x1A] = (byte)value; }
public int EV_SPD { get => Data[0x1B]; set => Data[0x1B] = (byte)value; }
public int Move1
{
get => ReadUInt16LittleEndian(Data.AsSpan(0x1C));
set => WriteUInt16LittleEndian(Data.AsSpan(0x1C), (ushort)value);
}
public int Move2
{
get => ReadUInt16LittleEndian(Data.AsSpan(0x1E));
set => WriteUInt16LittleEndian(Data.AsSpan(0x1E), (ushort)value);
}
public int Move3
{
get => ReadUInt16LittleEndian(Data.AsSpan(0x20));
set => WriteUInt16LittleEndian(Data.AsSpan(0x20), (ushort)value);
}
public int Move4
{
get => ReadUInt16LittleEndian(Data.AsSpan(0x22));
set => WriteUInt16LittleEndian(Data.AsSpan(0x22), (ushort)value);
}
public int Move1_PPUps { get => Data[0x24]; set => Data[0x24] = (byte)value; }
public int Move2_PPUps { get => Data[0x25]; set => Data[0x25] = (byte)value; }
public int Move3_PPUps { get => Data[0x26]; set => Data[0x26] = (byte)value; }
public int Move4_PPUps { get => Data[0x27]; set => Data[0x27] = (byte)value; }
// they messed up their bit struct and these ended up as individual fields? (5bits per byte)
public int IV_HP { get => Data[0x28]; set => Data[0x28] = (byte)value; }
public int IV_ATK { get => Data[0x29]; set => Data[0x29] = (byte)value; }
public int IV_DEF { get => Data[0x2A]; set => Data[0x2A] = (byte)value; }
public int IV_SPE { get => Data[0x2B]; set => Data[0x2B] = (byte)value; }
public int IV_SPA { get => Data[0x2C]; set => Data[0x2C] = (byte)value; }
public int IV_SPD { get => Data[0x2D] & 0x1F; set => Data[0x2D] = (byte)((Data[0x2D] & ~31) | value); }
public bool IsEgg { get => ((Data[0x2D] >> 5) & 1) == 1; set => Data[0x2D] = (byte)((Data[0x2D] & ~32) | (value ? 32 : 0)); }
public bool IsShiny { get => ((Data[0x2D] >> 5) & 1) == 1; set => Data[0x2D] = (byte)((Data[0x2D] & ~32) | (value ? 32 : 0)); }
public int CurrentFriendship { get => Data[0x2E]; set => Data[0x2E] = (byte)value; }
public int Ball { get => Data[0x2F]; set => Data[0x2F] = (byte)value; }
public int CurrentLevel { get => Data[0x30]; set => Data[0x30] = (byte)value; }
// 0x31,0x32,0x33 unused (alignment padding to u32)
}
}