mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-28 23:10:22 +00:00
Misc tweaks
Add Cap Pikachu const value updating for USUM, also set Magearna const for USUM (not only SM) Remove `NotDistributed` property from WC3 as only CXD events used it, no longer WC3 type. Delete ArrayUtil; move remaining methods into the StorageUtil class that used them for compressing/inserting bulk into boxes. Add shiny wormhole flag Extract byte array strings into spans, faster tests and less overhead.
This commit is contained in:
parent
84d42807e0
commit
67fc0d0885
28 changed files with 552 additions and 312 deletions
|
@ -24,8 +24,8 @@ public sealed class EventWorkspace<TSave, TWork> where TSave : class, IEventFlag
|
|||
{
|
||||
SAV.SetEventFlags(Flags);
|
||||
SAV.SetAllEventWork(Values);
|
||||
if (SAV is EventWork7SM s7) // Ensure Magearna event flag has magic constant
|
||||
s7.UpdateMagearnaConstant();
|
||||
if (SAV is EventWork7 sm) // Ensure QR event flag has magic constant(s)
|
||||
sm.UpdateQrConstants();
|
||||
}
|
||||
|
||||
private static string GetResourceSuffix(GameVersion version) => version switch
|
||||
|
|
|
@ -56,23 +56,10 @@ public sealed class FilteredGameDataSource
|
|||
};
|
||||
|
||||
static IEnumerable<ComboItem> FilterAbove(IReadOnlyList<ComboItem> species, int limit)
|
||||
{
|
||||
foreach (var s in species)
|
||||
{
|
||||
if (s.Value <= limit)
|
||||
yield return s;
|
||||
}
|
||||
}
|
||||
=> species.Where(s => s.Value <= limit);
|
||||
|
||||
static IEnumerable<ComboItem> FilterUnavailable<T>(IReadOnlyList<ComboItem> source, T table) where T : IPersonalTable
|
||||
{
|
||||
foreach (var s in source)
|
||||
{
|
||||
var species = s.Value;
|
||||
if (table.IsSpeciesInGame((ushort)species))
|
||||
yield return s;
|
||||
}
|
||||
}
|
||||
=> source.Where(s => table.IsSpeciesInGame((ushort)s.Value));
|
||||
}
|
||||
|
||||
private static IEnumerable<ComboItem> GetFilteredMoves(IGameValueLimit limit, GameDataSource source, bool HaX = false)
|
||||
|
@ -103,27 +90,27 @@ public sealed class FilteredGameDataSource
|
|||
public readonly IReadOnlyList<ComboItem> G4GroundTiles;
|
||||
public readonly IReadOnlyList<ComboItem> ConsoleRegions = GameDataSource.Regions;
|
||||
|
||||
public IReadOnlyList<ComboItem> GetAbilityList(PKM pk)
|
||||
{
|
||||
return GetAbilityList(pk.PersonalInfo);
|
||||
}
|
||||
private const char HiddenAbilitySuffix = 'H';
|
||||
private const char AbilityIndexSuffix = '1';
|
||||
|
||||
public IReadOnlyList<ComboItem> GetAbilityList(PKM pk) => GetAbilityList(pk.PersonalInfo);
|
||||
|
||||
public IReadOnlyList<ComboItem> GetAbilityList(IPersonalAbility pi)
|
||||
{
|
||||
var list = new ComboItem[pi.AbilityCount];
|
||||
|
||||
var alist = Source.Strings.Ability;
|
||||
var suffixes = AbilityIndexSuffixes;
|
||||
for (int i = 0; i < list.Length; i++)
|
||||
{
|
||||
var ability = pi.GetAbilityAtIndex(i);
|
||||
var suffix = suffixes[i];
|
||||
var display = $"{alist[ability]} ({suffix})";
|
||||
list[i] = new ComboItem(display, ability);
|
||||
}
|
||||
|
||||
LoadAbilityList(pi, list, Source.Strings.abilitylist);
|
||||
return list;
|
||||
}
|
||||
|
||||
private static ReadOnlySpan<char> AbilityIndexSuffixes => ['1', '2', 'H'];
|
||||
private static void LoadAbilityList(IPersonalAbility pi, Span<ComboItem> list, ReadOnlySpan<string> names)
|
||||
{
|
||||
for (int i = 0; i < list.Length; i++)
|
||||
{
|
||||
var value = pi.GetAbilityAtIndex(i);
|
||||
var name = names[value];
|
||||
char suffix = i == 2 ? HiddenAbilitySuffix : (char)(AbilityIndexSuffix + i);
|
||||
var display = $"{name} ({suffix})";
|
||||
list[i] = new ComboItem(display, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -261,8 +261,6 @@ public record struct EncounterPossible3(EvoCriteria[] Chain, EncounterTypeGroup
|
|||
{
|
||||
if (evo.Species != enc.Species)
|
||||
continue;
|
||||
if (enc.NotDistributed)
|
||||
break;
|
||||
return SetCurrent(enc);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@ public static class EncounterVerifier
|
|||
{
|
||||
EncounterEgg e => VerifyEncounterEgg(pk, e.Generation),
|
||||
EncounterShadow3Colo { IsEReader: true } when pk.Language != (int)LanguageID.Japanese => GetInvalid(LG3EReader),
|
||||
EncounterStatic3 { Species: (int)Species.Mew, Location: 201 } when pk.Language != (int)LanguageID.Japanese => GetInvalid(LEncUnreleasedEMewJP),
|
||||
EncounterStatic3 { Species: (int)Species.Deoxys, Location: 200 } when pk.Language == (int)LanguageID.Japanese => GetInvalid(LEncUnreleased),
|
||||
EncounterStatic3 { Species: (int)Species.Mew } when pk.Language != (int)LanguageID.Japanese => GetInvalid(LEncUnreleasedEMewJP),
|
||||
EncounterStatic3 { Species: (int)Species.Deoxys } when pk.Language == (int)LanguageID.Japanese => GetInvalid(LEncUnreleased),
|
||||
EncounterStatic4 { Roaming: true } when pk is G4PKM { MetLocation: 193, GroundTile: GroundTileType.Water } => GetInvalid(LG4InvalidTileR45Surf),
|
||||
MysteryGift g => VerifyEncounterEvent(pk, g),
|
||||
{ IsEgg: true } when !pk.IsEgg => VerifyEncounterEgg(pk, enc.Generation),
|
||||
|
@ -315,6 +315,7 @@ public static class EncounterVerifier
|
|||
{
|
||||
// Pokémon that evolve on trade can not be in the phase evolution after the trade
|
||||
// If the trade holds an Everstone, EvolveOnTrade will be false for the encounter
|
||||
// No need to range check the species, as it matched to a valid encounter species.
|
||||
var names = ParseSettings.SpeciesStrings;
|
||||
var evolved = names[species + 1];
|
||||
var unevolved = names[species];
|
||||
|
|
|
@ -114,18 +114,14 @@ public sealed class LegalityAnalysis
|
|||
Valid = false;
|
||||
|
||||
// Moves and Relearn arrays can potentially be empty on error.
|
||||
var moves = Info.Moves;
|
||||
for (var i = 0; i < moves.Length; i++)
|
||||
foreach (ref var p in Info.Moves.AsSpan())
|
||||
{
|
||||
ref var p = ref moves[i];
|
||||
if (!p.IsParsed)
|
||||
p = MoveResult.Unobtainable();
|
||||
}
|
||||
|
||||
moves = Info.Relearn;
|
||||
for (var i = 0; i < moves.Length; i++)
|
||||
foreach (ref var p in Info.Relearn.AsSpan())
|
||||
{
|
||||
ref var p = ref moves[i];
|
||||
if (!p.IsParsed)
|
||||
p = MoveResult.Unobtainable();
|
||||
}
|
||||
|
@ -205,9 +201,6 @@ public sealed class LegalityAnalysis
|
|||
if (Entity.Version == GameVersion.CXD)
|
||||
CXD.Verify(this);
|
||||
|
||||
if (Info.EncounterMatch is WC3 {NotDistributed: true})
|
||||
AddLine(Severity.Invalid, LEncUnreleased, CheckIdentifier.Encounter);
|
||||
|
||||
if (Entity.Format >= 8)
|
||||
Transfer.VerifyTransferLegalityG8(this);
|
||||
}
|
||||
|
|
|
@ -69,16 +69,10 @@ public sealed class EffortValueVerifier : Verifier
|
|||
}
|
||||
|
||||
// Hard cap at 252 for Gen6+
|
||||
private static bool IsAnyAboveHardLimit6(ReadOnlySpan<int> evs) => evs.ContainsAny(253, 254, 255);
|
||||
private static bool IsAnyAboveHardLimit6(ReadOnlySpan<int> evs)
|
||||
=> evs.ContainsAnyExceptInRange(0, EffortValues.Max252);
|
||||
|
||||
// Vitamins can only raise to 100 in Gen3/4
|
||||
private static bool IsAnyAboveVitaminLimit(ReadOnlySpan<int> evs)
|
||||
{
|
||||
foreach (var iv in evs)
|
||||
{
|
||||
if (iv > EffortValues.MaxVitamins34)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
=> evs.ContainsAnyExceptInRange(0, EffortValues.MaxVitamins34);
|
||||
}
|
||||
|
|
|
@ -68,10 +68,13 @@ public static class MoveInfo
|
|||
_ => false,
|
||||
};
|
||||
|
||||
private const uint DynamaxMoveCount = (int)MaxSteelspike - (int)MaxFlare + 1;
|
||||
private const uint TorqueMoveCount = (int)MagicalTorque - (int)BlazingTorque + 1;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the move is a Dynamax-only move.
|
||||
/// </summary>
|
||||
public static bool IsMoveDynamax(ushort move) => move is (>= (int)MaxFlare and <= (int)MaxSteelspike);
|
||||
public static bool IsMoveDynamax(ushort move) => move - (uint)MaxFlare < DynamaxMoveCount;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the move can be known by anything in any context.
|
||||
|
@ -82,7 +85,7 @@ public static class MoveInfo
|
|||
/// <summary>
|
||||
/// Checks if the move is a Starmobile-only move.
|
||||
/// </summary>
|
||||
public static bool IsMoveTorque(ushort move) => move - (uint)BlazingTorque <= 4;
|
||||
public static bool IsMoveTorque(ushort move) => move - (uint)BlazingTorque < TorqueMoveCount;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the <see cref="move"/> is unable to be used in battle.
|
||||
|
@ -157,6 +160,7 @@ public static class MoveInfo
|
|||
/// <summary>
|
||||
/// Checks if the move can be sketched in any game.
|
||||
/// </summary>
|
||||
/// <param name="move">Sketched move</param>
|
||||
private static bool IsSketchPossible(ushort move) => move switch
|
||||
{
|
||||
// Can't Sketch
|
||||
|
@ -172,8 +176,8 @@ public static class MoveInfo
|
|||
/// <summary>
|
||||
/// Checks if the move can be sketched in a specific game context. Pre-check with <see cref="IsSketchPossible(ushort)"/>.
|
||||
/// </summary>
|
||||
/// <param name="move"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="move">Sketched move</param>
|
||||
/// <param name="context">Context currently present in</param>
|
||||
private static bool IsSketchPossible(ushort move, EntityContext context) => context switch
|
||||
{
|
||||
Gen6 when move is (int)ThousandArrows or (int)ThousandWaves => false,
|
||||
|
|
|
@ -43,7 +43,6 @@ public sealed class WC3(GameVersion Version, bool Fateful = false)
|
|||
public override ushort Species { get; set; }
|
||||
public override bool IsEgg { get; set; }
|
||||
public override Moveset Moves { get; set; }
|
||||
public bool NotDistributed { get; init; }
|
||||
public override Shiny Shiny { get; init; }
|
||||
public override GameVersion Version { get; } = Version;
|
||||
public override bool FatefulEncounter { get; } = Fateful; // Obedience Flag
|
||||
|
|
|
@ -931,10 +931,8 @@ public abstract class PKM : ISpeciesForm, ITrainerID32, IGeneration, IShiny, ILa
|
|||
var rnd = Util.Rand;
|
||||
for (int i = 0; i < ivs.Length; i++)
|
||||
{
|
||||
if (template[i] == -1)
|
||||
ivs[i] = rnd.Next(MaxIV + 1);
|
||||
else
|
||||
ivs[i] = template[i];
|
||||
var spec = template[i];
|
||||
ivs[i] = spec != -1 ? spec : rnd.Next(MaxIV + 1);
|
||||
}
|
||||
SetIVs(ivs);
|
||||
}
|
||||
|
|
|
@ -97,20 +97,6 @@ public static class MemeCrypto
|
|||
return hash[..8].SequenceEqual(output[^8..]);
|
||||
}
|
||||
|
||||
public static bool VerifyMemeData(ReadOnlySpan<byte> input, out byte[] output, int offset, int length, MemeKeyIndex keyIndex)
|
||||
{
|
||||
var data = input.Slice(offset, length);
|
||||
if (VerifyMemeData(data, out output, keyIndex))
|
||||
{
|
||||
var newOutput = input.ToArray();
|
||||
output.CopyTo(newOutput, offset);
|
||||
output = newOutput;
|
||||
return true;
|
||||
}
|
||||
output = [];
|
||||
return false;
|
||||
}
|
||||
|
||||
public static byte[] SignMemeData(ReadOnlySpan<byte> input, MemeKeyIndex keyIndex = MemeKeyIndex.PokedexAndSaveFile)
|
||||
{
|
||||
var output = input.ToArray();
|
||||
|
|
|
@ -144,11 +144,11 @@ public readonly ref struct MemeKey
|
|||
private byte[] GetAesKey(ReadOnlySpan<byte> data)
|
||||
{
|
||||
// HashLengthInBytes is 20.
|
||||
Span<byte> hash = stackalloc byte[20];
|
||||
Span<byte> hash = stackalloc byte[SHA1.HashSizeInBytes];
|
||||
using var h = IncrementalHash.CreateHash(HashAlgorithmName.SHA1);
|
||||
h.AppendData(DER);
|
||||
h.AppendData(data);
|
||||
h.TryGetCurrentHash(hash, out _);
|
||||
h.GetCurrentHash(hash);
|
||||
return hash[..chunk].ToArray(); // need a byte[0x10] (not 0x14) for the AES impl
|
||||
}
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ public sealed class SCBlock
|
|||
bw.Write((byte)((byte)SubType ^ xk.Next()));
|
||||
}
|
||||
|
||||
foreach (ref var b in Data.AsSpan())
|
||||
foreach (var b in Data)
|
||||
bw.Write((byte)(b ^ xk.Next()));
|
||||
}
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ public static class SwishCrypto
|
|||
h.AppendData(IntroHashBytes);
|
||||
h.AppendData(data);
|
||||
h.AppendData(OutroHashBytes);
|
||||
h.TryGetCurrentHash(hash, out _);
|
||||
h.GetCurrentHash(hash);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
|
@ -75,9 +76,10 @@ public sealed class SAV3GCMemoryCard(Memory<byte> Raw)
|
|||
ushort csum = 0;
|
||||
ushort inv_csum = 0;
|
||||
|
||||
for (int i = 0; i < span.Length; i += 2)
|
||||
var cast = MemoryMarshal.Cast<byte, ushort>(span);
|
||||
foreach (var u16 in cast)
|
||||
{
|
||||
var value = ReadUInt16BigEndian(span[i..]);
|
||||
var value = BitConverter.IsLittleEndian ? ReverseEndianness(u16) : u16;
|
||||
csum += value;
|
||||
inv_csum += (ushort)~value;
|
||||
}
|
||||
|
@ -155,6 +157,9 @@ public sealed class SAV3GCMemoryCard(Memory<byte> Raw)
|
|||
private bool IsCorruptedMemoryCard()
|
||||
{
|
||||
var csums = VerifyChecksums();
|
||||
if (csums == MemoryCardChecksumStatus.None)
|
||||
return false; // eager return, true for all correct Memory Cards.
|
||||
|
||||
if (csums.HasFlag(MemoryCardChecksumStatus.HeaderBad))
|
||||
return true;
|
||||
|
||||
|
|
|
@ -281,11 +281,13 @@ public sealed class SAV3E : SAV3, IGen3Hoenn, IGen3Joyful, IGen3Wonder, IDaycare
|
|||
private const uint EXTRADATA_SENTINEL = 0x0000B39D;
|
||||
private const int OFS_BV = 31 * 0x1000; // last sector of the save
|
||||
public bool HasBattleVideo => Data.Length > SaveUtil.SIZE_G3RAWHALF && ReadUInt32LittleEndian(Data.AsSpan(OFS_BV)) == EXTRADATA_SENTINEL;
|
||||
public void SetExtraDataSentinelBattleVideo() => WriteUInt32LittleEndian(Data.AsSpan(OFS_BV), EXTRADATA_SENTINEL);
|
||||
|
||||
private Span<byte> BattleVideoData => Data.AsSpan(OFS_BV + 4, BattleVideo3.SIZE);
|
||||
public Memory<byte> BattleVideoData => Data.AsMemory(OFS_BV + 4, BattleVideo3.SIZE);
|
||||
public BattleVideo3 BattleVideo
|
||||
{
|
||||
// decouple from the save file object on get, as the consumer might not be aware that mutations will touch the save.
|
||||
get => HasBattleVideo ? new BattleVideo3(BattleVideoData.ToArray()) : new BattleVideo3();
|
||||
set => SetData(BattleVideoData, value.Data);
|
||||
set => SetData(BattleVideoData.Span, value.Data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -251,4 +251,6 @@ public abstract class SAV7 : SAV_BEEF, ITrainerStatRecord, ISaveBlock7Main, IReg
|
|||
|
||||
IEventFlag37 IEventFlagProvider37.EventWork => EventWork;
|
||||
IMysteryGiftStorage IMysteryGiftStorageProvider.MysteryGiftStorage => MysteryGift;
|
||||
|
||||
public abstract void UpdateQrConstants();
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ public sealed class SAV7SM : SAV7, ISaveBlock7SM
|
|||
|
||||
private const ulong MagearnaConst = 0xCBE05F18356504AC;
|
||||
|
||||
public void UpdateMagearnaConstant()
|
||||
public override void UpdateQrConstants()
|
||||
{
|
||||
var flag = EventWork.GetEventFlag(EventWork7SM.MagearnaEventFlag); // 3100
|
||||
ulong value = flag ? MagearnaConst : 0ul;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
|
@ -66,4 +67,19 @@ public sealed class SAV7USUM : SAV7, ISaveBlock7USUM
|
|||
public override GTS7 GTS => Blocks.GTS;
|
||||
public BattleAgency7 BattleAgency => Blocks.BattleAgency;
|
||||
#endregion
|
||||
|
||||
private const ulong MagearnaConst = 0xCBE05F18356504AC;
|
||||
private const ulong CapPikachuConst = 0xF44E94EA7D19A8D6;
|
||||
|
||||
public override void UpdateQrConstants()
|
||||
{
|
||||
var qr = Blocks.BlockInfo[35];
|
||||
var flag = EventWork.GetEventFlag(EventWork7USUM.MagearnaEventFlag); // 4060
|
||||
ulong value = flag ? MagearnaConst : 0ul;
|
||||
WriteUInt64LittleEndian(Data.AsSpan(qr.Offset + 0x168), value);
|
||||
|
||||
flag = EventWork.GetEventFlag(EventWork7USUM.CapPikachuEventFlag); // 4060
|
||||
value = flag ? CapPikachuConst : 0ul;
|
||||
WriteUInt64LittleEndian(Data.AsSpan(qr.Offset + 0x16C), value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -171,7 +171,7 @@ public sealed class SAV8BS : SaveFile, ISaveFileRevision, ITrainerStatRecord, IE
|
|||
|
||||
#region Checksums
|
||||
|
||||
private const int HashLength = 0x10;
|
||||
private const int HashLength = MD5.HashSizeInBytes;
|
||||
private const int HashOffset = SaveUtil.SIZE_G8BDSP - HashLength;
|
||||
private Span<byte> CurrentHash => Data.AsSpan(HashOffset, HashLength);
|
||||
private static void ComputeHash(ReadOnlySpan<byte> data, Span<byte> dest)
|
||||
|
@ -181,7 +181,7 @@ public sealed class SAV8BS : SaveFile, ISaveFileRevision, ITrainerStatRecord, IE
|
|||
Span<byte> zeroes = stackalloc byte[HashLength]; // Hash is zeroed prior to computing over the payload. Treat it as zero.
|
||||
h.AppendData(zeroes);
|
||||
h.AppendData(data[(HashOffset + HashLength)..]);
|
||||
h.TryGetCurrentHash(dest, out _);
|
||||
h.GetCurrentHash(dest);
|
||||
}
|
||||
|
||||
protected override void SetChecksums() => ComputeHash(Data, CurrentHash);
|
||||
|
|
|
@ -825,63 +825,3 @@ public abstract class SaveFile : ITrainerInfo, IGameValueLimit, IGeneration, IVe
|
|||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public static class StorageUtil
|
||||
{
|
||||
public static bool CompressStorage(this SaveFile sav, Span<byte> storage, out int storedCount, Span<int> slotPointers)
|
||||
{
|
||||
// keep track of empty slots, and only write them at the end if slots were shifted (no need otherwise).
|
||||
var empty = new List<byte[]>();
|
||||
bool shiftedSlots = false;
|
||||
|
||||
ushort ctr = 0;
|
||||
int size = sav.SIZE_BOXSLOT;
|
||||
int count = sav.BoxSlotCount * sav.BoxCount;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
int offset = sav.GetBoxSlotOffset(i);
|
||||
if (sav.IsPKMPresent(storage[offset..]))
|
||||
{
|
||||
if (ctr != i) // copy required
|
||||
{
|
||||
shiftedSlots = true; // appending empty slots afterward is now required since a rewrite was done
|
||||
int destOfs = sav.GetBoxSlotOffset(ctr);
|
||||
storage[offset..(offset + size)].CopyTo(storage[destOfs..(destOfs + size)]);
|
||||
SlotPointerUtil.UpdateRepointFrom(ctr, i, slotPointers);
|
||||
}
|
||||
|
||||
ctr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// pop out an empty slot; save all unused data & preserve order
|
||||
var data = storage.Slice(offset, size).ToArray();
|
||||
empty.Add(data);
|
||||
}
|
||||
|
||||
storedCount = ctr;
|
||||
|
||||
if (!shiftedSlots)
|
||||
return false;
|
||||
|
||||
for (int i = ctr; i < count; i++)
|
||||
{
|
||||
var data = empty[i - ctr];
|
||||
int offset = sav.GetBoxSlotOffset(i);
|
||||
data.CopyTo(storage[offset..]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int FindSlotIndex(this SaveFile sav, Func<PKM, bool> method, int maxCount)
|
||||
{
|
||||
for (int i = 0; i < maxCount; i++)
|
||||
{
|
||||
var pk = sav.GetBoxSlotAtIndex(i);
|
||||
if (method(pk))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,11 @@ using static System.Buffers.Binary.BinaryPrimitives;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public sealed class BattleVideo3(byte[] Data) : IBattleVideo
|
||||
public sealed class BattleVideo3(Memory<byte> Raw) : IBattleVideo
|
||||
{
|
||||
public BattleVideo3() : this(new byte[SIZE]) { }
|
||||
|
||||
public readonly byte[] Data = (byte[])Data.Clone();
|
||||
|
||||
public Span<byte> Data => Raw.Span;
|
||||
internal const int SIZE = 0xF80;
|
||||
public byte Generation => 3;
|
||||
|
||||
|
@ -49,7 +48,7 @@ public sealed class BattleVideo3(byte[] Data) : IBattleVideo
|
|||
for (int p = 0; p < 6; p++)
|
||||
{
|
||||
int offset = ofs + (PokeCrypto.SIZE_3PARTY * p);
|
||||
var span = Data.AsSpan(offset, PokeCrypto.SIZE_3PARTY);
|
||||
var span = Data.Slice(offset, PokeCrypto.SIZE_3PARTY);
|
||||
team[p] = new PK3(span.ToArray());
|
||||
}
|
||||
|
||||
|
@ -62,7 +61,7 @@ public sealed class BattleVideo3(byte[] Data) : IBattleVideo
|
|||
for (int p = 0; p < 6; p++)
|
||||
{
|
||||
int offset = ofs + (PokeCrypto.SIZE_3PARTY * p);
|
||||
team[p].EncryptedPartyData.CopyTo(Data, offset);
|
||||
team[p].EncryptedPartyData.CopyTo(Data[offset..]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,25 +72,25 @@ public sealed class BattleVideo3(byte[] Data) : IBattleVideo
|
|||
|
||||
public uint Seed
|
||||
{
|
||||
get => ReadUInt32LittleEndian(Data.AsSpan(0x4E8));
|
||||
set => WriteUInt32LittleEndian(Data.AsSpan(0x4E8), value);
|
||||
get => ReadUInt32LittleEndian(Data[0x4E8..]);
|
||||
set => WriteUInt32LittleEndian(Data[0x4E8..], value);
|
||||
}
|
||||
|
||||
public uint Mode
|
||||
{
|
||||
get => ReadUInt32LittleEndian(Data.AsSpan(0x4EC));
|
||||
set => WriteUInt32LittleEndian(Data.AsSpan(0x4EC), value);
|
||||
get => ReadUInt32LittleEndian(Data[0x4EC..]);
|
||||
set => WriteUInt32LittleEndian(Data[0x4EC..], value);
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
public uint Checksum
|
||||
{
|
||||
get => ReadUInt32LittleEndian(Data.AsSpan(SIZE - 4));
|
||||
set => WriteUInt32LittleEndian(Data.AsSpan(SIZE - 4), value);
|
||||
get => ReadUInt32LittleEndian(Data[^4..]);
|
||||
set => WriteUInt32LittleEndian(Data[^4..], value);
|
||||
}
|
||||
|
||||
public bool IsChecksumValid() => Checksum == GetByteSum(Data.AsSpan()[..^4]);
|
||||
public bool IsChecksumValid() => Checksum == GetByteSum(Data[..^4]);
|
||||
|
||||
public static uint GetByteSum(ReadOnlySpan<byte> data)
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace PKHeX.Core;
|
|||
|
||||
public abstract class EventWork7(SAV7 sav, Memory<byte> raw) : SaveBlock<SAV7>(sav, raw), IEventFlag37
|
||||
{
|
||||
private readonly SAV7 sav7 = sav;
|
||||
protected abstract Span<byte> WorkSpan { get; }
|
||||
protected abstract Span<byte> FlagSpan { get; }
|
||||
protected abstract Memory<byte> FameSpan { get; }
|
||||
|
@ -37,6 +38,8 @@ public abstract class EventWork7(SAV7 sav, Memory<byte> raw) : SaveBlock<SAV7>(s
|
|||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual((uint)index, (uint)TotalZygardeCellCount);
|
||||
SetWork(celloffset + index, val);
|
||||
}
|
||||
|
||||
public void UpdateQrConstants() => sav7.UpdateQrConstants();
|
||||
}
|
||||
|
||||
public sealed class EventWork7SM(SAV7SM sav, Memory<byte> raw) : EventWork7(sav, raw)
|
||||
|
@ -58,8 +61,6 @@ public sealed class EventWork7SM(SAV7SM sav, Memory<byte> raw) : EventWork7(sav,
|
|||
protected override Memory<byte> FameSpan => Raw.Slice(OffsetPostData, HallOfFame7.SIZE);
|
||||
|
||||
public const int MagearnaEventFlag = 3100;
|
||||
|
||||
public void UpdateMagearnaConstant() => ((SAV7SM)SAV).UpdateMagearnaConstant();
|
||||
}
|
||||
|
||||
public sealed class EventWork7USUM(SAV7USUM sav, Memory<byte> raw) : EventWork7(sav, raw)
|
||||
|
@ -79,6 +80,9 @@ public sealed class EventWork7USUM(SAV7USUM sav, Memory<byte> raw) : EventWork7(
|
|||
protected override Span<byte> WorkSpan => Raw.Span[..(EventWorkCount * sizeof(ushort))];
|
||||
protected override Span<byte> FlagSpan => Raw.Span.Slice(OffsetFlag, FlagCount / 8);
|
||||
protected override Memory<byte> FameSpan => Raw.Slice(OffsetPostData, HallOfFame7.SIZE);
|
||||
|
||||
public const int MagearnaEventFlag = 4060;
|
||||
public const int CapPikachuEventFlag = 4562;
|
||||
}
|
||||
|
||||
public sealed class HallOfFame7(Memory<byte> raw)
|
||||
|
|
|
@ -38,22 +38,22 @@ public sealed class Misc7(SAV7 sav, Memory<byte> raw) : SaveBlock<SAV7>(sav, raw
|
|||
}
|
||||
}
|
||||
|
||||
public int DaysFromRefreshed
|
||||
{
|
||||
get => Data[0x123];
|
||||
set => Data[0x123] = (byte)value;
|
||||
}
|
||||
|
||||
public int Vivillon
|
||||
{
|
||||
get => Data[0x130] & 0x1F;
|
||||
set => Data[0x130] = (byte)((Data[0x130] & ~0x1F) | (value & 0x1F));
|
||||
}
|
||||
|
||||
public uint StarterEncryptionConstant
|
||||
public bool IsWormholeShiny
|
||||
{
|
||||
get => ReadUInt32LittleEndian(Data[0x148..]);
|
||||
set => WriteUInt32LittleEndian(Data[0x148..], value);
|
||||
}
|
||||
|
||||
public int DaysFromRefreshed
|
||||
{
|
||||
get => Data[0x123];
|
||||
set => Data[0x123] = (byte)value;
|
||||
get => Data[0x136] == 1;
|
||||
set => Data[0x136] = (byte)(value ? 1 : 0);
|
||||
}
|
||||
|
||||
public int GetSurfScore(int recordID)
|
||||
|
@ -69,4 +69,10 @@ public sealed class Misc7(SAV7 sav, Memory<byte> raw) : SaveBlock<SAV7>(sav, raw
|
|||
recordID = 0;
|
||||
WriteInt32LittleEndian(Data[(0x138 + (4 * recordID))..], score);
|
||||
}
|
||||
|
||||
public uint StarterEncryptionConstant
|
||||
{
|
||||
get => ReadUInt32LittleEndian(Data[0x148..]);
|
||||
set => WriteUInt32LittleEndian(Data[0x148..], value);
|
||||
}
|
||||
}
|
||||
|
|
102
PKHeX.Core/Saves/Util/StorageUtil.cs
Normal file
102
PKHeX.Core/Saves/Util/StorageUtil.cs
Normal file
|
@ -0,0 +1,102 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public static class StorageUtil
|
||||
{
|
||||
public static bool CompressStorage(this SaveFile sav, Span<byte> storage, out int storedCount, Span<int> slotPointers)
|
||||
{
|
||||
// keep track of empty slots, and only write them at the end if slots were shifted (no need otherwise).
|
||||
var empty = new List<byte[]>();
|
||||
bool shiftedSlots = false;
|
||||
|
||||
ushort ctr = 0;
|
||||
int size = sav.SIZE_BOXSLOT;
|
||||
int count = sav.BoxSlotCount * sav.BoxCount;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
int offset = sav.GetBoxSlotOffset(i);
|
||||
if (sav.IsPKMPresent(storage[offset..]))
|
||||
{
|
||||
if (ctr != i) // copy required
|
||||
{
|
||||
shiftedSlots = true; // appending empty slots afterward is now required since a rewrite was done
|
||||
int destOfs = sav.GetBoxSlotOffset(ctr);
|
||||
storage[offset..(offset + size)].CopyTo(storage[destOfs..(destOfs + size)]);
|
||||
SlotPointerUtil.UpdateRepointFrom(ctr, i, slotPointers);
|
||||
}
|
||||
|
||||
ctr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// pop out an empty slot; save all unused data & preserve order
|
||||
var data = storage.Slice(offset, size).ToArray();
|
||||
empty.Add(data);
|
||||
}
|
||||
|
||||
storedCount = ctr;
|
||||
|
||||
if (!shiftedSlots)
|
||||
return false;
|
||||
|
||||
for (int i = ctr; i < count; i++)
|
||||
{
|
||||
var data = empty[i - ctr];
|
||||
int offset = sav.GetBoxSlotOffset(i);
|
||||
data.CopyTo(storage[offset..]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int FindSlotIndex(this SaveFile sav, Func<PKM, bool> method, int maxCount)
|
||||
{
|
||||
for (int i = 0; i < maxCount; i++)
|
||||
{
|
||||
var pk = sav.GetBoxSlotAtIndex(i);
|
||||
if (method(pk))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies a <see cref="T"/> list to the destination list, with an option to copy to a starting point.
|
||||
/// </summary>
|
||||
/// <param name="list">Source list to copy from</param>
|
||||
/// <param name="dest">Destination list/array</param>
|
||||
/// <param name="skip">Criteria for skipping a slot</param>
|
||||
/// <param name="start">Starting point to copy to</param>
|
||||
/// <returns>Count of <see cref="T"/> copied.</returns>
|
||||
public static int CopyTo<T>(this IEnumerable<T> list, Span<T> dest, Func<int, bool> skip, int start = 0)
|
||||
{
|
||||
int ctr = start;
|
||||
int skipped = 0;
|
||||
foreach (var z in list)
|
||||
{
|
||||
// seek forward to next open slot
|
||||
int next = FindNextValidIndex(dest, skip, ctr);
|
||||
if (next == -1)
|
||||
break;
|
||||
skipped += next - ctr;
|
||||
ctr = next;
|
||||
dest[ctr++] = z;
|
||||
}
|
||||
return ctr - start - skipped;
|
||||
}
|
||||
|
||||
public static int FindNextValidIndex<T>(Span<T> dest, Func<int, bool> skip, int ctr)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if ((uint)ctr >= dest.Length)
|
||||
return -1;
|
||||
var exist = dest[ctr];
|
||||
if (exist == null || !skip(ctr))
|
||||
return ctr;
|
||||
ctr++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Array reusable logic
|
||||
/// </summary>
|
||||
public static class ArrayUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Copies a <see cref="T"/> list to the destination list, with an option to copy to a starting point.
|
||||
/// </summary>
|
||||
/// <param name="list">Source list to copy from</param>
|
||||
/// <param name="dest">Destination list/array</param>
|
||||
/// <param name="skip">Criteria for skipping a slot</param>
|
||||
/// <param name="start">Starting point to copy to</param>
|
||||
/// <returns>Count of <see cref="T"/> copied.</returns>
|
||||
public static int CopyTo<T>(this IEnumerable<T> list, IList<T> dest, Func<int, bool> skip, int start = 0)
|
||||
{
|
||||
int ctr = start;
|
||||
int skipped = 0;
|
||||
foreach (var z in list)
|
||||
{
|
||||
// seek forward to next open slot
|
||||
int next = FindNextValidIndex(dest, skip, ctr);
|
||||
if (next == -1)
|
||||
break;
|
||||
skipped += next - ctr;
|
||||
ctr = next;
|
||||
dest[ctr++] = z;
|
||||
}
|
||||
return ctr - start - skipped;
|
||||
}
|
||||
|
||||
public static int FindNextValidIndex<T>(IList<T> dest, Func<int, bool> skip, int ctr)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if ((uint)ctr >= dest.Count)
|
||||
return -1;
|
||||
var exist = dest[ctr];
|
||||
if (exist == null || !skip(ctr))
|
||||
return ctr;
|
||||
ctr++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -64,20 +64,10 @@ public static class StringUtil
|
|||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an all-caps hex string to a byte array. Expects no separation between byte tuples.
|
||||
/// </summary>
|
||||
public static byte[] ToByteArray(this string toTransform)
|
||||
{
|
||||
var result = new byte[toTransform.Length / 2];
|
||||
LoadHexBytesTo(toTransform, result, 2);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an all-caps encoded ASCII-Text hex string to a byte array.
|
||||
/// </summary>
|
||||
public static void LoadHexBytesTo(Span<byte> dest, ReadOnlySpan<byte> str, int tupleSize)
|
||||
public static void LoadHexBytesTo(ReadOnlySpan<byte> str, Span<byte> dest, int tupleSize)
|
||||
{
|
||||
// The input string is 2-char hex values optionally separated.
|
||||
// The destination array should always be larger or equal than the bytes written. Let the runtime bounds check us.
|
||||
|
|
|
@ -6,18 +6,45 @@ namespace PKHeX.Core.Tests.Legality;
|
|||
|
||||
public class RaidTests
|
||||
{
|
||||
public const string Charizard = "65E79FC0000085F1060060045CF0A3AA142C10005E00140015010000EE5501E2080A00000000000004FCFC0000000000000000008800000000001C0000000000000000000000000000000000000000008AAD000000000000430068006100720069007A00610072006400000000000000000035001E024C009B01181010080303030300000000000000002901FF7F1E3F0A000000000000000000000000000000000000000000000056006900630074006F0072006900610000000000000000000000010201000000320104080000000000000000000000000000000000002C000000020000000000FF0000000000000000000000000000004100720063006800690074000000000000000000000000000000FF000000000000000000140117000000A20009372804000000000000000100000200000000000000000000000000000000000000000064002901B700C10048013D01CE000000";
|
||||
// Just a regular Charizard pk8
|
||||
private static ReadOnlySpan<byte> Charizard =>
|
||||
[
|
||||
0x65, 0xE7, 0x9F, 0xC0, 0x00, 0x00, 0x85, 0xF1, 0x06, 0x00, 0x60, 0x04, 0x5C, 0xF0, 0xA3, 0xAA,
|
||||
0x14, 0x2C, 0x10, 0x00, 0x5E, 0x00, 0x14, 0x00, 0x15, 0x01, 0x00, 0x00, 0xEE, 0x55, 0x01, 0xE2,
|
||||
0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x8A, 0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x68, 0x00, 0x61, 0x00, 0x72, 0x00,
|
||||
0x69, 0x00, 0x7A, 0x00, 0x61, 0x00, 0x72, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x35, 0x00, 0x1E, 0x02, 0x4C, 0x00, 0x9B, 0x01, 0x18, 0x10, 0x10, 0x08, 0x03, 0x03,
|
||||
0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x01, 0xFF, 0x7F, 0x1E, 0x3F,
|
||||
0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x69, 0x00, 0x63, 0x00, 0x74, 0x00,
|
||||
0x6F, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00, 0x32, 0x01, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00,
|
||||
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x72, 0x00, 0x63, 0x00, 0x68, 0x00,
|
||||
0x69, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x01, 0x17, 0x00,
|
||||
0x00, 0x00, 0xA2, 0x00, 0x09, 0x37, 0x28, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x29, 0x01, 0xB7, 0x00, 0xC1, 0x00,
|
||||
0x48, 0x01, 0x3D, 0x01, 0xCE, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
[Theory]
|
||||
[InlineData(Charizard, 0xbefd08cf9e027d0a)]
|
||||
public void CheckMatch(string raw, ulong seed)
|
||||
[Fact]
|
||||
public void CheckDynamaxRaidCharizardPK8()
|
||||
{
|
||||
byte[] data = raw.ToByteArray();
|
||||
var pk8 = new PK8(data);
|
||||
var pk8 = new PK8();
|
||||
|
||||
const ulong seed = 0xbefd08cf9e027d0a;
|
||||
Charizard.CopyTo(pk8.Data);
|
||||
|
||||
bool found = IsPotentialRaidSeed(pk8.EncryptionConstant, pk8.PID, seed);
|
||||
found.Should().BeTrue();
|
||||
|
||||
// Ensure it matches encounter data and the actual seed is matched.
|
||||
var la = new LegalityAnalysis(pk8);
|
||||
var enc = la.EncounterMatch;
|
||||
if (enc is not ISeedCorrelation64<Core.PKM> s64)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
|
@ -6,95 +7,329 @@ namespace PKHeX.Core.Tests.Saves;
|
|||
public class MemeCryptoTests
|
||||
{
|
||||
[Fact]
|
||||
public void TestVerifySaveSignature()
|
||||
{
|
||||
var savebuffer =
|
||||
"58EA53A7133F34DA9F2BEC12F1560354E8BDF8A484ADE4E2954D3C48673118EB67E2D52ED0196E54DC5D93013E9F3B00C8A43B556AEE8C2F763EA9DC125988C6B5F2D3C74CA2C58026BB024B403D09BC5950C54CEB6F21E45D0B66B68791BCBB6D7E67C2F7E4A7F4A517FC50B4FEED9A65BF901ABEB0FFAC44AE07237BE5DD2D"
|
||||
.ToByteArray();
|
||||
Assert.True(MemeCrypto.VerifyMemeData(savebuffer, out _));
|
||||
}
|
||||
public void TestVerifySaveSignature() => Assert.True(MemeCrypto.VerifyMemeData(SaveSignature, out _));
|
||||
|
||||
[Fact]
|
||||
public void TestVerifyMemeBuffer()
|
||||
{
|
||||
var encrypted =
|
||||
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F4185F2713D5A8BCFFBFF47F86867DF680354913FEFEF08D0D0F1054CB054B508E7DE3AA789AC444D087AB9412CEE965A6D38E45EA010C77FF174F8F8D9993AEAFB9C0616E287B74487E0FF3F1874291B8170C71113971752717F8D188A319EA6"
|
||||
.ToByteArray();
|
||||
var decrypted =
|
||||
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7431E10EF7681217C"
|
||||
.ToByteArray();
|
||||
|
||||
Assert.True(MemeCrypto.VerifyMemeData(encrypted, out var actual, MemeKeyIndex.PokedexAndSaveFile));
|
||||
for (var i = 0; i < decrypted.Length; i++)
|
||||
{
|
||||
Assert.Equal(decrypted[i], actual[i]);
|
||||
}
|
||||
const MemeKeyIndex type = MemeKeyIndex.PokedexAndSaveFile;
|
||||
var result = MemeCrypto.VerifyMemeData(Encrypted00FFSigned, out var actual, type);
|
||||
result.Should().BeTrue();
|
||||
DecryptedAsDexSave.SequenceEqual(actual).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestSignMemeBuffer()
|
||||
{
|
||||
var encrypted =
|
||||
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F4185F2713D5A8BCFFBFF47F86867DF680354913FEFEF08D0D0F1054CB054B508E7DE3AA789AC444D087AB9412CEE965A6D38E45EA010C77FF174F8F8D9993AEAFB9C0616E287B74487E0FF3F1874291B8170C71113971752717F8D188A319EA6"
|
||||
.ToByteArray();
|
||||
var decrypted =
|
||||
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"
|
||||
.ToByteArray();
|
||||
|
||||
var actual = MemeCrypto.SignMemeData(decrypted);
|
||||
for (var i = 0; i < encrypted.Length; i++)
|
||||
{
|
||||
Assert.Equal(encrypted[i], actual[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestVerifyMemeBufferOffsetLength()
|
||||
{
|
||||
var encrypted =
|
||||
"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F4185F2713D5A8BCFFBFF47F86867DF680354913FEFEF08D0D0F1054CB054B508E7DE3AA789AC444D087AB9412CEE965A6D38E45EA010C77FF174F8F8D9993AEAFB9C0616E287B74487E0FF3F1874291B8170C71113971752717F8D188A319EA6CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
|
||||
.ToByteArray();
|
||||
var decrypted =
|
||||
"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7431E10EF7681217CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
|
||||
.ToByteArray();
|
||||
|
||||
Assert.True(MemeCrypto.VerifyMemeData(encrypted, out var actual, 0x10, 0x100,
|
||||
MemeKeyIndex.PokedexAndSaveFile));
|
||||
for (var i = 0; i < decrypted.Length; i++)
|
||||
{
|
||||
Assert.Equal(decrypted[i], actual[i]);
|
||||
}
|
||||
var actual = MemeCrypto.SignMemeData(Decrypted00FF);
|
||||
Encrypted00FFSigned.SequenceEqual(actual).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestVerifyPoke()
|
||||
{
|
||||
var vector =
|
||||
"A96E2D8D9B99DBFB934939C097E3AC101C7D48CEC52FCA717B14B19890208592045C430035DD09A31446142E9EA33CF3E6B6E69484B6D2EED500B8389048013491602403DBE7B814EA069667CFADAFE74895217D78037B4A456FAB2CAFD71E69504F4B4509000000000000"
|
||||
.ToByteArray();
|
||||
var vector2 =
|
||||
"A96E2D8D9B99DBFB934939C097E3AC101C7D48CEC52FCA717B14B19890208592045C430035DD09A31446142E9EA33CF3E6B6E69484B6D2EED500B8389048013491602403DBE7B814EA069667CFADAFE74895217D78037B4A456FAB2CAFD71E690000504F4B4509000000000000"
|
||||
.ToByteArray();
|
||||
|
||||
Assert.True(MemeCrypto.VerifyMemePOKE(vector, out _));
|
||||
Assert.True(MemeCrypto.VerifyMemePOKE(vector2, out _));
|
||||
Assert.True(MemeCrypto.VerifyMemePOKE(Vector2[..^2], out _));
|
||||
Assert.True(MemeCrypto.VerifyMemePOKE(Vector2, out _));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(MemeKeyIndex.LocalWireless, "1010030000030000000A0070300051308B3001FFD43020AB301003B430FC30B90830C830D10007C630A382000D6E300A005F00055700305D3046306A300000307530933044304D28306B000B5500158F308C203066002581305A3089A0002744002344308D30612A304C00276E0031DF0001C30830AD30E500110A0042A0004973003D4D305F308880007B0A006830823060C4002F10516A3063004D42305F5200536D009900A6F002F014F026FFF038F04AF05CF06EF080F092F0A4F0B6FFF0C8F0DAF0ECF0FEF110F122F134F1460000B5E400004646F86000F1AB31AB0030D730EC0E30BC30F3020FF173A723C162C9700608C5DCAFAB898032382AF1FA717BBC5D91C61AD7B6EA356220742C2DD4595765FCD8123D1E10ED6B0A1DA45D0C2148035A560BB1C5C246FA7EB64D729FC1DD8B61B4737DC51E184A97E4795E82BFD045743EC2AEAED26E87")]
|
||||
[InlineData(MemeKeyIndex.FriendlyCompetition, "0300000077000000000000000D0106060404003204000101000000000000000000000000000000000000C00000000000000000000000000E000000000000000000000000000000C0070000000000000000000000987E000000000000000000000000000000000000D80300000000000000F00300000000000000E001070000000000000000000000000000000000000000000000000000000101920200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E2D0100015A03000000BE0700000000C287010050006F006B00E9006D006F006E00200054007200610069006E006500720020004F006E006C0069006E006500200043006F006D007000650074006900740069006F006E000000000000007700770077002E0070006F006B0065006D006F006E002D0074007200610069007DC67F945B27557C97D6C0B6D20FF11AFCE1580C5E9E80C7C3FBBA53B67F24D1A91BA2FB8CDD31F7FE29D894B3764A45407658BB9A6E6DC8B3F6A45F77686AC56EA64C0298D1B22F3D3850ADE10AEA6E185FD0EEA91AA38E3F0F0AA9E7ADA132")]
|
||||
[InlineData(MemeKeyIndex.LiveCompetition, "0300000077000000000000000D0006060303003204000101000000000000000000000000000000000000C00000000000000000000000000E000000000000000000000000000000C0070000000000000000000000987E000000000000000000000000000000000000D80300000000000000F00300000000000000E001070000000000000000000000000000000000000000000000000000000101920200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E2D0100015A03000000BE07000000000B9101004900720069007300200043006D007000650074006900740069006F006E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066007200650065000000000000000000000000000000000000000000000000006425CA0A78E79154EBA19550A0734F84A0C49F8B02E51FA8310548FFF14B7338276188C11C85C15701DAED228099FBF95A277E6249625208D8992FF027385D897AC097F0240C93A70E35FB8AD971DFE14832988DC70F5D1BE19C7EF5FBAFCC12")]
|
||||
[InlineData(MemeKeyIndex.RentalTeam, "0300000077000000B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C74E35E4783A7E9E161C919C0E736F61B31741B8C1873C5D06D1D408D9DA9FE28DCB53851518FCC0758915EE2911B2194B20131C2E87BC63A255F3A5187763FAF99B1B99D0E4460125CCB7F1CE4A3CC0FC64463454DB25CC851EF9A360EA3D4BDB44B8DE96D1C9839744A3BF7A27FDF41A86491666DAA7BEF55EBFB954BA3FF741657252490BD11350EEF367DA0D229E04EE61DCA1220576014AC2E24232337AB4E7ADEE92B59C44E9AB8D19E0BA87547A0351C4088EDF8808D692461C84EB5D07C795D3B037290AC7C5A9FD2775A86EAD628F545F6E5193145ED22B3BCDE16FD3CCEEA80A5FD90CF8FD320C1D064C8881BF369F0D82EE0E637C434EC6CA4221FE0952C28A7E930956DC2B990817BCC2349EC4339CDD09E2ABB94DC44C171A1E70E2CC5538B9686A1E4AFF907436378FE2915F217EC7C3BA69E47C913794FFE8285DD399D3E39154CE51BA0C74663BD685634697D76EAB8890CF77E371BA7E5CD5FA78FAC7D58A3843C993331C8AFC5ABDCD17FC42B7C28A196C2FB0EF03FE84CAF3FD626A584D9406BC6FC5DC20DD0E19D1D08C96D9065F376E052639FFC0F61CCCE84CDC833F31B9A6C830DE9F58B257F5CBE5991FCA51871752B611AE3B21F5E1F1AE3CFAB49BC6F6721C1C18B74B11400D029E268D")]
|
||||
[InlineData(MemeKeyIndex.PokedexAndSaveFile, "4F3994147824D4F9D9B3EEBDC2DA6777585413FA41D22347A3593E22467E2F117B51EDFEAE5977E19AD88EB1C63ADB7E9DEDB7F5AEEFECA5F777C7F12527729025C82DC4A12C8B344EB472B9F68BFD999916F0D03460FF1D3FDC5EF0F7A7F8FE")]
|
||||
[InlineData(MemeKeyIndex.GaOle, "7C7F70413806DFD1D4E8F5610BE3CA705245593C24AB3102D7768D43B3D873EEB5BB6B188FD4F38F06EB06C1A27369E9822D10093DAD17692EA2D71BCB8941F883F3F0E2068941F65FB26950B7E54F5990E163809594381C99CF3330F052452C")]
|
||||
[InlineData(MemeKeyIndex.MagearnaEvent, "9D741CBA2ABA23408461AC168B3227199C15FFA2784662FE169459DDC2409AE08FA302A6E7026051C8378D09898500028021FE21B1A8165C9918779BA140597E03ED3EAF2FD82C026B17E6BB0D1C4BC6CE06E9FAC2E5DCDD4025983DE57C67CA")]
|
||||
[InlineData(MemeKeyIndex.MoncolleGet, "9914945B3280796FF8EC694681ED2218F8FCD1C6628FCFACD633A86622D278C09FD1BA1B2E60AF2896EDDAF76110CA246AED9E08D7D90F7F285764BBD3E20E05A11BA214C96B1A54E1A8D48DE6EF060C79011A4B3326FBE55F29FDE40B31F470")]
|
||||
[InlineData(MemeKeyIndex.IslandScanEventSpecial, "34B08442E3D68D3730CF5CEE9E82BCFD5F6664168F43E9F2EA26CC7B94B1F44FF7B3C0BAD5C346693DDAD5461E6087AD061015744F6DBA294F9BCD6F0E7A35859F0A15F358EB00BED5A4C18841A8B6A69D91FC603E6DCE058DD96983C5DFBB04")]
|
||||
[InlineData(MemeKeyIndex.TvTokyoDataBroadcasting, "195B4EA9F48E6ADBEE73EB0D529C14EDC99BB011F214E0812E5198BE40739783646FB8C75ABFFD84AA11FB095EFFF5E383F7F45A56A96780C79EBABB430D860FA6CB3D0BFC163C52EDC5C199963D3E518758F911569E1C667BF8A15643A19E2F")]
|
||||
[InlineData(MemeKeyIndex.CapPikachuEvent, "A96E2D8D9B99DBFB934939C097E3AC101C7D48CEC52FCA717B14B19890208592045C430035DD09A31446142E9EA33CF3E6B6E69484B6D2EED500B8389048013491602403DBE7B814EA069667CFADAFE74895217D78037B4A456FAB2CAFD71E69")]
|
||||
public void TestVerifyKnownKeys(MemeKeyIndex keyIndex, string keyVal)
|
||||
{
|
||||
var key = keyVal.ToByteArray();
|
||||
MemeCrypto.VerifyMemeData(key, out _, keyIndex).Should().BeTrue("because the key should be valid");
|
||||
}
|
||||
private static void Verify(ReadOnlySpan<byte> span, MemeKeyIndex type)
|
||||
=> MemeCrypto.VerifyMemeData(span, out _, type).Should().BeTrue();
|
||||
|
||||
// Various payloads that have been signed with Memecrypto Keys
|
||||
[Fact] public void VerifyMemeKeyLocalWireless() => Verify(MemeKeyLocalWireless, MemeKeyIndex.LocalWireless);
|
||||
[Fact] public void VerifyMemeKeyFriendlyCompetition() => Verify(MemeKeyFriendlyCompetition, MemeKeyIndex.FriendlyCompetition);
|
||||
[Fact] public void VerifyMemeKeyLiveCompetition() => Verify(MemeKeyLiveCompetition, MemeKeyIndex.LiveCompetition);
|
||||
[Fact] public void VerifyMemeKeyRentalTeam() => Verify(MemeKeyRentalTeam, MemeKeyIndex.RentalTeam);
|
||||
[Fact] public void VerifyMemeKeyPokedexAndSaveFile() => Verify(MemeKeyPokedexAndSaveFile, MemeKeyIndex.PokedexAndSaveFile);
|
||||
[Fact] public void VerifyMemeKeyGaOle() => Verify(MemeKeyGaOle, MemeKeyIndex.GaOle);
|
||||
[Fact] public void VerifyMemeKeyMagearnaEvent() => Verify(MemeKeyMagearnaEvent, MemeKeyIndex.MagearnaEvent);
|
||||
[Fact] public void VerifyMemeKeyMoncolleGet() => Verify(MemeKeyMoncolleGet, MemeKeyIndex.MoncolleGet);
|
||||
[Fact] public void VerifyMemeKeyIslandScanEventSpecial() => Verify(MemeKeyIslandScan, MemeKeyIndex.IslandScanEventSpecial);
|
||||
[Fact] public void VerifyMemeKeyTvTokyoDataBroadcasting() => Verify(MemeKeyTvTokyo, MemeKeyIndex.TvTokyoDataBroadcasting);
|
||||
[Fact] public void VerifyMemeKeyCapPikachuEvent() => Verify(MemeKeyCapPikachu, MemeKeyIndex.CapPikachuEvent);
|
||||
|
||||
private static ReadOnlySpan<byte> SaveSignature =>
|
||||
[
|
||||
0x58, 0xEA, 0x53, 0xA7, 0x13, 0x3F, 0x34, 0xDA, 0x9F, 0x2B, 0xEC, 0x12, 0xF1, 0x56, 0x03, 0x54,
|
||||
0xE8, 0xBD, 0xF8, 0xA4, 0x84, 0xAD, 0xE4, 0xE2, 0x95, 0x4D, 0x3C, 0x48, 0x67, 0x31, 0x18, 0xEB,
|
||||
0x67, 0xE2, 0xD5, 0x2E, 0xD0, 0x19, 0x6E, 0x54, 0xDC, 0x5D, 0x93, 0x01, 0x3E, 0x9F, 0x3B, 0x00,
|
||||
0xC8, 0xA4, 0x3B, 0x55, 0x6A, 0xEE, 0x8C, 0x2F, 0x76, 0x3E, 0xA9, 0xDC, 0x12, 0x59, 0x88, 0xC6,
|
||||
0xB5, 0xF2, 0xD3, 0xC7, 0x4C, 0xA2, 0xC5, 0x80, 0x26, 0xBB, 0x02, 0x4B, 0x40, 0x3D, 0x09, 0xBC,
|
||||
0x59, 0x50, 0xC5, 0x4C, 0xEB, 0x6F, 0x21, 0xE4, 0x5D, 0x0B, 0x66, 0xB6, 0x87, 0x91, 0xBC, 0xBB,
|
||||
0x6D, 0x7E, 0x67, 0xC2, 0xF7, 0xE4, 0xA7, 0xF4, 0xA5, 0x17, 0xFC, 0x50, 0xB4, 0xFE, 0xED, 0x9A,
|
||||
0x65, 0xBF, 0x90, 0x1A, 0xBE, 0xB0, 0xFF, 0xAC, 0x44, 0xAE, 0x07, 0x23, 0x7B, 0xE5, 0xDD, 0x2D,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> Decrypted00FF =>
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
|
||||
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
|
||||
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
|
||||
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
|
||||
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
|
||||
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
|
||||
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> Encrypted00FFSigned =>
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
|
||||
|
||||
0x41, 0x85, 0xF2, 0x71, 0x3D, 0x5A, 0x8B, 0xCF, 0xFB, 0xFF, 0x47, 0xF8, 0x68, 0x67, 0xDF, 0x68,
|
||||
0x03, 0x54, 0x91, 0x3F, 0xEF, 0xEF, 0x08, 0xD0, 0xD0, 0xF1, 0x05, 0x4C, 0xB0, 0x54, 0xB5, 0x08,
|
||||
0xE7, 0xDE, 0x3A, 0xA7, 0x89, 0xAC, 0x44, 0x4D, 0x08, 0x7A, 0xB9, 0x41, 0x2C, 0xEE, 0x96, 0x5A,
|
||||
0x6D, 0x38, 0xE4, 0x5E, 0xA0, 0x10, 0xC7, 0x7F, 0xF1, 0x74, 0xF8, 0xF8, 0xD9, 0x99, 0x3A, 0xEA,
|
||||
0xFB, 0x9C, 0x06, 0x16, 0xE2, 0x87, 0xB7, 0x44, 0x87, 0xE0, 0xFF, 0x3F, 0x18, 0x74, 0x29, 0x1B,
|
||||
0x81, 0x70, 0xC7, 0x11, 0x13, 0x97, 0x17, 0x52, 0x71, 0x7F, 0x8D, 0x18, 0x8A, 0x31, 0x9E, 0xA6,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> DecryptedAsDexSave =>
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
|
||||
|
||||
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
|
||||
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
|
||||
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
|
||||
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
|
||||
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
|
||||
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0x43, 0x1E, 0x10, 0xEF, 0x76, 0x81, 0x21, 0x7C,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> Vector2 =>
|
||||
[
|
||||
0xA9, 0x6E, 0x2D, 0x8D, 0x9B, 0x99, 0xDB, 0xFB, 0x93, 0x49, 0x39, 0xC0, 0x97, 0xE3, 0xAC, 0x10,
|
||||
0x1C, 0x7D, 0x48, 0xCE, 0xC5, 0x2F, 0xCA, 0x71, 0x7B, 0x14, 0xB1, 0x98, 0x90, 0x20, 0x85, 0x92,
|
||||
0x04, 0x5C, 0x43, 0x00, 0x35, 0xDD, 0x09, 0xA3, 0x14, 0x46, 0x14, 0x2E, 0x9E, 0xA3, 0x3C, 0xF3,
|
||||
0xE6, 0xB6, 0xE6, 0x94, 0x84, 0xB6, 0xD2, 0xEE, 0xD5, 0x00, 0xB8, 0x38, 0x90, 0x48, 0x01, 0x34,
|
||||
0x91, 0x60, 0x24, 0x03, 0xDB, 0xE7, 0xB8, 0x14, 0xEA, 0x06, 0x96, 0x67, 0xCF, 0xAD, 0xAF, 0xE7,
|
||||
0x48, 0x95, 0x21, 0x7D, 0x78, 0x03, 0x7B, 0x4A, 0x45, 0x6F, 0xAB, 0x2C, 0xAF, 0xD7, 0x1E, 0x69,
|
||||
0x00, 0x00, 0x50, 0x4F, 0x4B, 0x45, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> MemeKeyLocalWireless =>
|
||||
[
|
||||
0x10, 0x10, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x70, 0x30, 0x00, 0x51, 0x30,
|
||||
0x8B, 0x30, 0x01, 0xFF, 0xD4, 0x30, 0x20, 0xAB, 0x30, 0x10, 0x03, 0xB4, 0x30, 0xFC, 0x30, 0xB9,
|
||||
0x08, 0x30, 0xC8, 0x30, 0xD1, 0x00, 0x07, 0xC6, 0x30, 0xA3, 0x82, 0x00, 0x0D, 0x6E, 0x30, 0x0A,
|
||||
0x00, 0x5F, 0x00, 0x05, 0x57, 0x00, 0x30, 0x5D, 0x30, 0x46, 0x30, 0x6A, 0x30, 0x00, 0x00, 0x30,
|
||||
0x75, 0x30, 0x93, 0x30, 0x44, 0x30, 0x4D, 0x28, 0x30, 0x6B, 0x00, 0x0B, 0x55, 0x00, 0x15, 0x8F,
|
||||
0x30, 0x8C, 0x20, 0x30, 0x66, 0x00, 0x25, 0x81, 0x30, 0x5A, 0x30, 0x89, 0xA0, 0x00, 0x27, 0x44,
|
||||
0x00, 0x23, 0x44, 0x30, 0x8D, 0x30, 0x61, 0x2A, 0x30, 0x4C, 0x00, 0x27, 0x6E, 0x00, 0x31, 0xDF,
|
||||
0x00, 0x01, 0xC3, 0x08, 0x30, 0xAD, 0x30, 0xE5, 0x00, 0x11, 0x0A, 0x00, 0x42, 0xA0, 0x00, 0x49,
|
||||
0x73, 0x00, 0x3D, 0x4D, 0x30, 0x5F, 0x30, 0x88, 0x80, 0x00, 0x7B, 0x0A, 0x00, 0x68, 0x30, 0x82,
|
||||
0x30, 0x60, 0xC4, 0x00, 0x2F, 0x10, 0x51, 0x6A, 0x30, 0x63, 0x00, 0x4D, 0x42, 0x30, 0x5F, 0x52,
|
||||
0x00, 0x53, 0x6D, 0x00, 0x99, 0x00, 0xA6, 0xF0, 0x02, 0xF0, 0x14, 0xF0, 0x26, 0xFF, 0xF0, 0x38,
|
||||
0xF0, 0x4A, 0xF0, 0x5C, 0xF0, 0x6E, 0xF0, 0x80, 0xF0, 0x92, 0xF0, 0xA4, 0xF0, 0xB6, 0xFF, 0xF0,
|
||||
0xC8, 0xF0, 0xDA, 0xF0, 0xEC, 0xF0, 0xFE, 0xF1, 0x10, 0xF1, 0x22, 0xF1, 0x34, 0xF1, 0x46, 0x00,
|
||||
0x00, 0xB5, 0xE4, 0x00, 0x00, 0x46, 0x46, 0xF8, 0x60, 0x00, 0xF1, 0xAB, 0x31, 0xAB, 0x00, 0x30,
|
||||
0xD7, 0x30, 0xEC, 0x0E, 0x30, 0xBC, 0x30, 0xF3, 0x02, 0x0F, 0xF1, 0x73, 0xA7, 0x23, 0xC1, 0x62,
|
||||
0xC9, 0x70, 0x06, 0x08, 0xC5, 0xDC, 0xAF, 0xAB, 0x89, 0x80, 0x32, 0x38, 0x2A, 0xF1, 0xFA, 0x71,
|
||||
0x7B, 0xBC, 0x5D, 0x91, 0xC6, 0x1A, 0xD7, 0xB6, 0xEA, 0x35, 0x62, 0x20, 0x74, 0x2C, 0x2D, 0xD4,
|
||||
0x59, 0x57, 0x65, 0xFC, 0xD8, 0x12, 0x3D, 0x1E, 0x10, 0xED, 0x6B, 0x0A, 0x1D, 0xA4, 0x5D, 0x0C,
|
||||
0x21, 0x48, 0x03, 0x5A, 0x56, 0x0B, 0xB1, 0xC5, 0xC2, 0x46, 0xFA, 0x7E, 0xB6, 0x4D, 0x72, 0x9F,
|
||||
0xC1, 0xDD, 0x8B, 0x61, 0xB4, 0x73, 0x7D, 0xC5, 0x1E, 0x18, 0x4A, 0x97, 0xE4, 0x79, 0x5E, 0x82,
|
||||
0xBF, 0xD0, 0x45, 0x74, 0x3E, 0xC2, 0xAE, 0xAE, 0xD2, 0x6E, 0x87,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> MemeKeyFriendlyCompetition =>
|
||||
[
|
||||
0x03, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x01, 0x06, 0x06,
|
||||
0x04, 0x04, 0x00, 0x32, 0x04, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x98, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x07, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x92, 0x02, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x1E, 0x2D, 0x01, 0x00, 0x01, 0x5A, 0x03, 0x00, 0x00, 0x00, 0xBE, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC2, 0x87, 0x01, 0x00, 0x50, 0x00, 0x6F, 0x00, 0x6B, 0x00, 0xE9, 0x00, 0x6D, 0x00, 0x6F, 0x00,
|
||||
0x6E, 0x00, 0x20, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x65, 0x00,
|
||||
0x72, 0x00, 0x20, 0x00, 0x4F, 0x00, 0x6E, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x65, 0x00,
|
||||
0x20, 0x00, 0x43, 0x00, 0x6F, 0x00, 0x6D, 0x00, 0x70, 0x00, 0x65, 0x00, 0x74, 0x00, 0x69, 0x00,
|
||||
0x74, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00,
|
||||
0x77, 0x00, 0x77, 0x00, 0x2E, 0x00, 0x70, 0x00, 0x6F, 0x00, 0x6B, 0x00, 0x65, 0x00, 0x6D, 0x00,
|
||||
0x6F, 0x00, 0x6E, 0x00, 0x2D, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x69, 0x00, 0x7D, 0xC6,
|
||||
0x7F, 0x94, 0x5B, 0x27, 0x55, 0x7C, 0x97, 0xD6, 0xC0, 0xB6, 0xD2, 0x0F, 0xF1, 0x1A, 0xFC, 0xE1,
|
||||
0x58, 0x0C, 0x5E, 0x9E, 0x80, 0xC7, 0xC3, 0xFB, 0xBA, 0x53, 0xB6, 0x7F, 0x24, 0xD1, 0xA9, 0x1B,
|
||||
0xA2, 0xFB, 0x8C, 0xDD, 0x31, 0xF7, 0xFE, 0x29, 0xD8, 0x94, 0xB3, 0x76, 0x4A, 0x45, 0x40, 0x76,
|
||||
0x58, 0xBB, 0x9A, 0x6E, 0x6D, 0xC8, 0xB3, 0xF6, 0xA4, 0x5F, 0x77, 0x68, 0x6A, 0xC5, 0x6E, 0xA6,
|
||||
0x4C, 0x02, 0x98, 0xD1, 0xB2, 0x2F, 0x3D, 0x38, 0x50, 0xAD, 0xE1, 0x0A, 0xEA, 0x6E, 0x18, 0x5F,
|
||||
0xD0, 0xEE, 0xA9, 0x1A, 0xA3, 0x8E, 0x3F, 0x0F, 0x0A, 0xA9, 0xE7, 0xAD, 0xA1, 0x32,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> MemeKeyLiveCompetition =>
|
||||
[
|
||||
0x03, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x06, 0x06,
|
||||
0x03, 0x03, 0x00, 0x32, 0x04, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x98, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x07, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x92, 0x02, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x1E, 0x2D, 0x01, 0x00, 0x01, 0x5A, 0x03, 0x00, 0x00, 0x00, 0xBE, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0B, 0x91, 0x01, 0x00, 0x49, 0x00, 0x72, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x43, 0x00,
|
||||
0x6D, 0x00, 0x70, 0x00, 0x65, 0x00, 0x74, 0x00, 0x69, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6F, 0x00,
|
||||
0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00,
|
||||
0x72, 0x00, 0x65, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x25,
|
||||
0xCA, 0x0A, 0x78, 0xE7, 0x91, 0x54, 0xEB, 0xA1, 0x95, 0x50, 0xA0, 0x73, 0x4F, 0x84, 0xA0, 0xC4,
|
||||
0x9F, 0x8B, 0x02, 0xE5, 0x1F, 0xA8, 0x31, 0x05, 0x48, 0xFF, 0xF1, 0x4B, 0x73, 0x38, 0x27, 0x61,
|
||||
0x88, 0xC1, 0x1C, 0x85, 0xC1, 0x57, 0x01, 0xDA, 0xED, 0x22, 0x80, 0x99, 0xFB, 0xF9, 0x5A, 0x27,
|
||||
0x7E, 0x62, 0x49, 0x62, 0x52, 0x08, 0xD8, 0x99, 0x2F, 0xF0, 0x27, 0x38, 0x5D, 0x89, 0x7A, 0xC0,
|
||||
0x97, 0xF0, 0x24, 0x0C, 0x93, 0xA7, 0x0E, 0x35, 0xFB, 0x8A, 0xD9, 0x71, 0xDF, 0xE1, 0x48, 0x32,
|
||||
0x98, 0x8D, 0xC7, 0x0F, 0x5D, 0x1B, 0xE1, 0x9C, 0x7E, 0xF5, 0xFB, 0xAF, 0xCC, 0x12,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> MemeKeyRentalTeam =>
|
||||
[
|
||||
0x03, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
|
||||
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0x4E, 0x35, 0xE4, 0x78, 0x3A, 0x7E, 0x9E, 0x16,
|
||||
0x1C, 0x91, 0x9C, 0x0E, 0x73, 0x6F, 0x61, 0xB3, 0x17, 0x41, 0xB8, 0xC1, 0x87, 0x3C, 0x5D, 0x06,
|
||||
0xD1, 0xD4, 0x08, 0xD9, 0xDA, 0x9F, 0xE2, 0x8D, 0xCB, 0x53, 0x85, 0x15, 0x18, 0xFC, 0xC0, 0x75,
|
||||
0x89, 0x15, 0xEE, 0x29, 0x11, 0xB2, 0x19, 0x4B, 0x20, 0x13, 0x1C, 0x2E, 0x87, 0xBC, 0x63, 0xA2,
|
||||
0x55, 0xF3, 0xA5, 0x18, 0x77, 0x63, 0xFA, 0xF9, 0x9B, 0x1B, 0x99, 0xD0, 0xE4, 0x46, 0x01, 0x25,
|
||||
0xCC, 0xB7, 0xF1, 0xCE, 0x4A, 0x3C, 0xC0, 0xFC, 0x64, 0x46, 0x34, 0x54, 0xDB, 0x25, 0xCC, 0x85,
|
||||
0x1E, 0xF9, 0xA3, 0x60, 0xEA, 0x3D, 0x4B, 0xDB, 0x44, 0xB8, 0xDE, 0x96, 0xD1, 0xC9, 0x83, 0x97,
|
||||
0x44, 0xA3, 0xBF, 0x7A, 0x27, 0xFD, 0xF4, 0x1A, 0x86, 0x49, 0x16, 0x66, 0xDA, 0xA7, 0xBE, 0xF5,
|
||||
0x5E, 0xBF, 0xB9, 0x54, 0xBA, 0x3F, 0xF7, 0x41, 0x65, 0x72, 0x52, 0x49, 0x0B, 0xD1, 0x13, 0x50,
|
||||
0xEE, 0xF3, 0x67, 0xDA, 0x0D, 0x22, 0x9E, 0x04, 0xEE, 0x61, 0xDC, 0xA1, 0x22, 0x05, 0x76, 0x01,
|
||||
0x4A, 0xC2, 0xE2, 0x42, 0x32, 0x33, 0x7A, 0xB4, 0xE7, 0xAD, 0xEE, 0x92, 0xB5, 0x9C, 0x44, 0xE9,
|
||||
0xAB, 0x8D, 0x19, 0xE0, 0xBA, 0x87, 0x54, 0x7A, 0x03, 0x51, 0xC4, 0x08, 0x8E, 0xDF, 0x88, 0x08,
|
||||
0xD6, 0x92, 0x46, 0x1C, 0x84, 0xEB, 0x5D, 0x07, 0xC7, 0x95, 0xD3, 0xB0, 0x37, 0x29, 0x0A, 0xC7,
|
||||
0xC5, 0xA9, 0xFD, 0x27, 0x75, 0xA8, 0x6E, 0xAD, 0x62, 0x8F, 0x54, 0x5F, 0x6E, 0x51, 0x93, 0x14,
|
||||
0x5E, 0xD2, 0x2B, 0x3B, 0xCD, 0xE1, 0x6F, 0xD3, 0xCC, 0xEE, 0xA8, 0x0A, 0x5F, 0xD9, 0x0C, 0xF8,
|
||||
0xFD, 0x32, 0x0C, 0x1D, 0x06, 0x4C, 0x88, 0x81, 0xBF, 0x36, 0x9F, 0x0D, 0x82, 0xEE, 0x0E, 0x63,
|
||||
0x7C, 0x43, 0x4E, 0xC6, 0xCA, 0x42, 0x21, 0xFE, 0x09, 0x52, 0xC2, 0x8A, 0x7E, 0x93, 0x09, 0x56,
|
||||
0xDC, 0x2B, 0x99, 0x08, 0x17, 0xBC, 0xC2, 0x34, 0x9E, 0xC4, 0x33, 0x9C, 0xDD, 0x09, 0xE2, 0xAB,
|
||||
0xB9, 0x4D, 0xC4, 0x4C, 0x17, 0x1A, 0x1E, 0x70, 0xE2, 0xCC, 0x55, 0x38, 0xB9, 0x68, 0x6A, 0x1E,
|
||||
0x4A, 0xFF, 0x90, 0x74, 0x36, 0x37, 0x8F, 0xE2, 0x91, 0x5F, 0x21, 0x7E, 0xC7, 0xC3, 0xBA, 0x69,
|
||||
0xE4, 0x7C, 0x91, 0x37, 0x94, 0xFF, 0xE8, 0x28, 0x5D, 0xD3, 0x99, 0xD3, 0xE3, 0x91, 0x54, 0xCE,
|
||||
0x51, 0xBA, 0x0C, 0x74, 0x66, 0x3B, 0xD6, 0x85, 0x63, 0x46, 0x97, 0xD7, 0x6E, 0xAB, 0x88, 0x90,
|
||||
0xCF, 0x77, 0xE3, 0x71, 0xBA, 0x7E, 0x5C, 0xD5, 0xFA, 0x78, 0xFA, 0xC7, 0xD5, 0x8A, 0x38, 0x43,
|
||||
0xC9, 0x93, 0x33, 0x1C, 0x8A, 0xFC, 0x5A, 0xBD, 0xCD, 0x17, 0xFC, 0x42, 0xB7, 0xC2, 0x8A, 0x19,
|
||||
0x6C, 0x2F, 0xB0, 0xEF, 0x03, 0xFE, 0x84, 0xCA, 0xF3, 0xFD, 0x62, 0x6A, 0x58, 0x4D, 0x94, 0x06,
|
||||
0xBC, 0x6F, 0xC5, 0xDC, 0x20, 0xDD, 0x0E, 0x19, 0xD1, 0xD0, 0x8C, 0x96, 0xD9, 0x06, 0x5F, 0x37,
|
||||
0x6E, 0x05, 0x26, 0x39, 0xFF, 0xC0, 0xF6, 0x1C, 0xCC, 0xE8, 0x4C, 0xDC, 0x83, 0x3F, 0x31, 0xB9,
|
||||
0xA6, 0xC8, 0x30, 0xDE, 0x9F, 0x58, 0xB2, 0x57, 0xF5, 0xCB, 0xE5, 0x99, 0x1F, 0xCA, 0x51, 0x87,
|
||||
0x17, 0x52, 0xB6, 0x11, 0xAE, 0x3B, 0x21, 0xF5, 0xE1, 0xF1, 0xAE, 0x3C, 0xFA, 0xB4, 0x9B, 0xC6,
|
||||
0xF6, 0x72, 0x1C, 0x1C, 0x18, 0xB7, 0x4B, 0x11, 0x40, 0x0D, 0x02, 0x9E, 0x26, 0x8D,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> MemeKeyPokedexAndSaveFile =>
|
||||
[
|
||||
0x4F, 0x39, 0x94, 0x14, 0x78, 0x24, 0xD4, 0xF9, 0xD9, 0xB3, 0xEE, 0xBD, 0xC2, 0xDA, 0x67, 0x77,
|
||||
0x58, 0x54, 0x13, 0xFA, 0x41, 0xD2, 0x23, 0x47, 0xA3, 0x59, 0x3E, 0x22, 0x46, 0x7E, 0x2F, 0x11,
|
||||
0x7B, 0x51, 0xED, 0xFE, 0xAE, 0x59, 0x77, 0xE1, 0x9A, 0xD8, 0x8E, 0xB1, 0xC6, 0x3A, 0xDB, 0x7E,
|
||||
0x9D, 0xED, 0xB7, 0xF5, 0xAE, 0xEF, 0xEC, 0xA5, 0xF7, 0x77, 0xC7, 0xF1, 0x25, 0x27, 0x72, 0x90,
|
||||
0x25, 0xC8, 0x2D, 0xC4, 0xA1, 0x2C, 0x8B, 0x34, 0x4E, 0xB4, 0x72, 0xB9, 0xF6, 0x8B, 0xFD, 0x99,
|
||||
0x99, 0x16, 0xF0, 0xD0, 0x34, 0x60, 0xFF, 0x1D, 0x3F, 0xDC, 0x5E, 0xF0, 0xF7, 0xA7, 0xF8, 0xFE,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> MemeKeyGaOle =>
|
||||
[
|
||||
0x7C, 0x7F, 0x70, 0x41, 0x38, 0x06, 0xDF, 0xD1, 0xD4, 0xE8, 0xF5, 0x61, 0x0B, 0xE3, 0xCA, 0x70,
|
||||
0x52, 0x45, 0x59, 0x3C, 0x24, 0xAB, 0x31, 0x02, 0xD7, 0x76, 0x8D, 0x43, 0xB3, 0xD8, 0x73, 0xEE,
|
||||
0xB5, 0xBB, 0x6B, 0x18, 0x8F, 0xD4, 0xF3, 0x8F, 0x06, 0xEB, 0x06, 0xC1, 0xA2, 0x73, 0x69, 0xE9,
|
||||
0x82, 0x2D, 0x10, 0x09, 0x3D, 0xAD, 0x17, 0x69, 0x2E, 0xA2, 0xD7, 0x1B, 0xCB, 0x89, 0x41, 0xF8,
|
||||
0x83, 0xF3, 0xF0, 0xE2, 0x06, 0x89, 0x41, 0xF6, 0x5F, 0xB2, 0x69, 0x50, 0xB7, 0xE5, 0x4F, 0x59,
|
||||
0x90, 0xE1, 0x63, 0x80, 0x95, 0x94, 0x38, 0x1C, 0x99, 0xCF, 0x33, 0x30, 0xF0, 0x52, 0x45, 0x2C,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> MemeKeyMagearnaEvent =>
|
||||
[
|
||||
0x9D, 0x74, 0x1C, 0xBA, 0x2A, 0xBA, 0x23, 0x40, 0x84, 0x61, 0xAC, 0x16, 0x8B, 0x32, 0x27, 0x19,
|
||||
0x9C, 0x15, 0xFF, 0xA2, 0x78, 0x46, 0x62, 0xFE, 0x16, 0x94, 0x59, 0xDD, 0xC2, 0x40, 0x9A, 0xE0,
|
||||
0x8F, 0xA3, 0x02, 0xA6, 0xE7, 0x02, 0x60, 0x51, 0xC8, 0x37, 0x8D, 0x09, 0x89, 0x85, 0x00, 0x02,
|
||||
0x80, 0x21, 0xFE, 0x21, 0xB1, 0xA8, 0x16, 0x5C, 0x99, 0x18, 0x77, 0x9B, 0xA1, 0x40, 0x59, 0x7E,
|
||||
0x03, 0xED, 0x3E, 0xAF, 0x2F, 0xD8, 0x2C, 0x02, 0x6B, 0x17, 0xE6, 0xBB, 0x0D, 0x1C, 0x4B, 0xC6,
|
||||
0xCE, 0x06, 0xE9, 0xFA, 0xC2, 0xE5, 0xDC, 0xDD, 0x40, 0x25, 0x98, 0x3D, 0xE5, 0x7C, 0x67, 0xCA,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> MemeKeyMoncolleGet =>
|
||||
[
|
||||
0x99, 0x14, 0x94, 0x5B, 0x32, 0x80, 0x79, 0x6F, 0xF8, 0xEC, 0x69, 0x46, 0x81, 0xED, 0x22, 0x18,
|
||||
0xF8, 0xFC, 0xD1, 0xC6, 0x62, 0x8F, 0xCF, 0xAC, 0xD6, 0x33, 0xA8, 0x66, 0x22, 0xD2, 0x78, 0xC0,
|
||||
0x9F, 0xD1, 0xBA, 0x1B, 0x2E, 0x60, 0xAF, 0x28, 0x96, 0xED, 0xDA, 0xF7, 0x61, 0x10, 0xCA, 0x24,
|
||||
0x6A, 0xED, 0x9E, 0x08, 0xD7, 0xD9, 0x0F, 0x7F, 0x28, 0x57, 0x64, 0xBB, 0xD3, 0xE2, 0x0E, 0x05,
|
||||
0xA1, 0x1B, 0xA2, 0x14, 0xC9, 0x6B, 0x1A, 0x54, 0xE1, 0xA8, 0xD4, 0x8D, 0xE6, 0xEF, 0x06, 0x0C,
|
||||
0x79, 0x01, 0x1A, 0x4B, 0x33, 0x26, 0xFB, 0xE5, 0x5F, 0x29, 0xFD, 0xE4, 0x0B, 0x31, 0xF4, 0x70,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> MemeKeyIslandScan =>
|
||||
[
|
||||
0x34, 0xB0, 0x84, 0x42, 0xE3, 0xD6, 0x8D, 0x37, 0x30, 0xCF, 0x5C, 0xEE, 0x9E, 0x82, 0xBC, 0xFD,
|
||||
0x5F, 0x66, 0x64, 0x16, 0x8F, 0x43, 0xE9, 0xF2, 0xEA, 0x26, 0xCC, 0x7B, 0x94, 0xB1, 0xF4, 0x4F,
|
||||
0xF7, 0xB3, 0xC0, 0xBA, 0xD5, 0xC3, 0x46, 0x69, 0x3D, 0xDA, 0xD5, 0x46, 0x1E, 0x60, 0x87, 0xAD,
|
||||
0x06, 0x10, 0x15, 0x74, 0x4F, 0x6D, 0xBA, 0x29, 0x4F, 0x9B, 0xCD, 0x6F, 0x0E, 0x7A, 0x35, 0x85,
|
||||
0x9F, 0x0A, 0x15, 0xF3, 0x58, 0xEB, 0x00, 0xBE, 0xD5, 0xA4, 0xC1, 0x88, 0x41, 0xA8, 0xB6, 0xA6,
|
||||
0x9D, 0x91, 0xFC, 0x60, 0x3E, 0x6D, 0xCE, 0x05, 0x8D, 0xD9, 0x69, 0x83, 0xC5, 0xDF, 0xBB, 0x04,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> MemeKeyTvTokyo =>
|
||||
[
|
||||
0x19, 0x5B, 0x4E, 0xA9, 0xF4, 0x8E, 0x6A, 0xDB, 0xEE, 0x73, 0xEB, 0x0D, 0x52, 0x9C, 0x14, 0xED,
|
||||
0xC9, 0x9B, 0xB0, 0x11, 0xF2, 0x14, 0xE0, 0x81, 0x2E, 0x51, 0x98, 0xBE, 0x40, 0x73, 0x97, 0x83,
|
||||
0x64, 0x6F, 0xB8, 0xC7, 0x5A, 0xBF, 0xFD, 0x84, 0xAA, 0x11, 0xFB, 0x09, 0x5E, 0xFF, 0xF5, 0xE3,
|
||||
0x83, 0xF7, 0xF4, 0x5A, 0x56, 0xA9, 0x67, 0x80, 0xC7, 0x9E, 0xBA, 0xBB, 0x43, 0x0D, 0x86, 0x0F,
|
||||
0xA6, 0xCB, 0x3D, 0x0B, 0xFC, 0x16, 0x3C, 0x52, 0xED, 0xC5, 0xC1, 0x99, 0x96, 0x3D, 0x3E, 0x51,
|
||||
0x87, 0x58, 0xF9, 0x11, 0x56, 0x9E, 0x1C, 0x66, 0x7B, 0xF8, 0xA1, 0x56, 0x43, 0xA1, 0x9E, 0x2F,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> MemeKeyCapPikachu =>
|
||||
[
|
||||
0xA9, 0x6E, 0x2D, 0x8D, 0x9B, 0x99, 0xDB, 0xFB, 0x93, 0x49, 0x39, 0xC0, 0x97, 0xE3, 0xAC, 0x10,
|
||||
0x1C, 0x7D, 0x48, 0xCE, 0xC5, 0x2F, 0xCA, 0x71, 0x7B, 0x14, 0xB1, 0x98, 0x90, 0x20, 0x85, 0x92,
|
||||
0x04, 0x5C, 0x43, 0x00, 0x35, 0xDD, 0x09, 0xA3, 0x14, 0x46, 0x14, 0x2E, 0x9E, 0xA3, 0x3C, 0xF3,
|
||||
0xE6, 0xB6, 0xE6, 0x94, 0x84, 0xB6, 0xD2, 0xEE, 0xD5, 0x00, 0xB8, 0x38, 0x90, 0x48, 0x01, 0x34,
|
||||
0x91, 0x60, 0x24, 0x03, 0xDB, 0xE7, 0xB8, 0x14, 0xEA, 0x06, 0x96, 0x67, 0xCF, 0xAD, 0xAF, 0xE7,
|
||||
0x48, 0x95, 0x21, 0x7D, 0x78, 0x03, 0x7B, 0x4A, 0x45, 0x6F, 0xAB, 0x2C, 0xAF, 0xD7, 0x1E, 0x69,
|
||||
];
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue