PKHeX/PKHeX.Core/Saves/Storage/Bank7.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

57 lines
2.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using static System.Buffers.Binary.BinaryPrimitives;
namespace PKHeX.Core
{
/// <summary>
/// Generation 7 <see cref="SaveFile"/> object that reads from Pokémon Bank savedata (stored on AWS).
/// </summary>
public sealed class Bank7 : BulkStorage
{
public Bank7(byte[] data, Type t, int start, int slotsPerBox = 30) : base(data, t, start, slotsPerBox) => Version = GameVersion.USUM;
public override PersonalTable Personal => PersonalTable.USUM;
public override IReadOnlyList<ushort> HeldItems => Legal.HeldItems_SM;
protected override SaveFile CloneInternal() => new Bank7((byte[])Data.Clone(), PKMType, BoxStart, SlotsPerBox);
public override string PlayTimeString => $"{Year:00}{Month:00}{Day:00}_{Hours:00}ː{Minutes:00}";
protected internal override string ShortSummary => PlayTimeString;
private const int GroupNameSize = 0x20;
private const int BankNameSize = 0x24;
private const int GroupNameSpacing = GroupNameSize + 2;
private const int BankNameSpacing = BankNameSize + 2;
public ulong UID => ReadUInt64LittleEndian(Data.AsSpan(0));
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);
}
public override int BoxCount => BankCount;
private int BankCount
{
get => Data[0x15E];
set => Data[0x15E] = (byte)value;
}
private int Year => ReadUInt16LittleEndian(Data.AsSpan(0x160));
private int Month => Data[0x162];
private int Day => Data[0x163];
private int Hours => Data[0x164];
private int Minutes => Data[0x165];
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 int GetBoxNameOffset(int box) => GetBoxOffset(box) + (SlotsPerBox * SIZE_STORED);
public int GetBoxIndex(int box) => ReadUInt16LittleEndian(Data.AsSpan(GetBoxNameOffset(box) + BankNameSize));
private const int BoxStart = 0x17C;
public static Bank7 GetBank7(byte[] data) => new(data, typeof(PK7), BoxStart);
}
}