PKHeX/PKHeX.Core/Saves/Substructures/OPower/OPower6.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

85 lines
3.3 KiB
C#

using System;
using static PKHeX.Core.OPower6Type;
namespace PKHeX.Core
{
public sealed class OPower6 : SaveBlock
{
private static readonly OPowerFlagSet[] Mapping =
{
// Skip unused byte
new(5, Hatching) {Offset = 1},
new(5, Bargain) {Offset = 6},
new(5, Prize_Money) {Offset = 11},
new(5, Exp_Point) {Offset = 16},
new(5, Capture) {Offset = 21},
new(3, Encounter) {Offset = 26},
new(3, Stealth) {Offset = 29},
new(3, HP_Restoring) {Offset = 32},
new(3, PP_Restoring) {Offset = 35},
new(1, Full_Recovery) {Offset = 38},
new(5, Befriending) {Offset = 39},
new(3, Attack) {Offset = 44},
new(3, Defense) {Offset = 47},
new(3, Sp_Attack) {Offset = 50},
new(3, Sp_Defense) {Offset = 53},
new(3, Speed) {Offset = 56},
new(3, Critical) {Offset = 59},
new(3, Accuracy) {Offset = 62},
};
public OPower6(SaveFile sav, int offset) : base(sav) => Offset = offset;
private static OPowerFlagSet Get(OPower6Type type) => Array.Find(Mapping, t => t.Identifier == type);
public static int GetOPowerCount(OPower6Type type) => Get(type).BaseCount;
public int GetOPowerLevel(OPower6Type type) => Get(type).GetOPowerLevel(Data.AsSpan(Offset));
public static bool GetHasOPowerS(OPower6Type type) => Get(type).HasOPowerS;
public static bool GetHasOPowerMAX(OPower6Type type) => Get(type).HasOPowerMAX;
public bool GetOPowerS(OPower6Type type) => Get(type).GetOPowerS(Data.AsSpan(Offset));
public bool GetOPowerMAX(OPower6Type type) => Get(type).GetOPowerMAX(Data.AsSpan(Offset));
public void SetOPowerLevel(OPower6Type type, int lvl) => Get(type).SetOPowerLevel(Data.AsSpan(Offset), lvl);
public void SetOPowerS(OPower6Type type, bool value) => Get(type).SetOPowerS(Data.AsSpan(Offset), value);
public void SetOPowerMAX(OPower6Type type, bool value) => Get(type).SetOPowerMAX(Data.AsSpan(Offset), value);
public bool MasterFlag
{
get => Data[Offset] == 1;
set => Data[Offset] = (byte) (value ? OPowerFlagState.Unlocked : OPowerFlagState.Locked);
}
public void UnlockAll() => ToggleFlags(allEvents: true);
public void UnlockRegular() => ToggleFlags();
public void ClearAll() => ToggleFlags(clearOnly: true);
private void ToggleFlags(bool allEvents = false, bool clearOnly = false)
{
var span = Data.AsSpan(Offset);
foreach (var m in Mapping)
{
// Clear before applying new value
m.SetOPowerLevel(span, 0);
m.SetOPowerS(span, false);
m.SetOPowerMAX(span, false);
if (clearOnly)
continue;
int lvl = allEvents ? m.BaseCount : (m.BaseCount != 1 ? 3 : 0); // Full_Recovery is ORAS/event only @ 1 level
m.SetOPowerLevel(span, lvl);
if (!allEvents)
continue;
m.SetOPowerS(span, true);
m.SetOPowerMAX(span, true);
}
}
public byte[] Write() => Data;
}
}