From 5f44fb75d417d73ae284b39db2fd84b610c1a7bc Mon Sep 17 00:00:00 2001 From: Kurt Date: Thu, 2 Apr 2026 08:48:51 -0500 Subject: [PATCH] add champions side-data storage note lack of training values being stored in home; possibly they're managed server-side in champions. wonder if they'll allow inter-player training transfer? the 0x10 could be a hash of immutable core data... still have to wait for Champions to release to see what data is filled in, since HOME doesn't seem to manage it? --- PKHeX.Core/PKM/HOME/GameDataPC9.cs | 66 ++++++++---------------------- PKHeX.Core/PKM/HOME/PKH.cs | 2 +- 2 files changed, 17 insertions(+), 51 deletions(-) diff --git a/PKHeX.Core/PKM/HOME/GameDataPC9.cs b/PKHeX.Core/PKM/HOME/GameDataPC9.cs index 483a04ca1..8af042264 100644 --- a/PKHeX.Core/PKM/HOME/GameDataPC9.cs +++ b/PKHeX.Core/PKM/HOME/GameDataPC9.cs @@ -1,14 +1,13 @@ using System; +using System.Text; using static System.Buffers.Binary.BinaryPrimitives; namespace PKHeX.Core; -// TODO -- NOTHING HERE IS CORRECT - /// -/// Side game data for Champions data linked to HOME (assumedly, not FR/LG). +/// Side game data for Champions data linked to HOME. /// -public sealed class GameDataPC9 : HomeOptional1, IScaledSize3, IGameDataSide +public sealed class GameDataPC9 : HomeOptional1 { private const HomeGameDataFormat ExpectFormat = HomeGameDataFormat.PC9; private const int SIZE = HomeCrypto.SIZE_4GAME_PC9; @@ -20,20 +19,10 @@ public sealed class GameDataPC9 : HomeOptional1, IScaledSize3, IGameDataSide public int WriteTo(Span result) => WriteWithHeader(result); #region Structure - public byte Scale { get => Data[0x00]; set => Data[0x00] = value; } - public ushort Move1 { get => ReadUInt16LittleEndian(Data[0x01..]); set => WriteUInt16LittleEndian(Data[0x01..], value); } - public ushort Move2 { get => ReadUInt16LittleEndian(Data[0x03..]); set => WriteUInt16LittleEndian(Data[0x03..], value); } - public ushort Move3 { get => ReadUInt16LittleEndian(Data[0x05..]); set => WriteUInt16LittleEndian(Data[0x05..], value); } - public ushort Move4 { get => ReadUInt16LittleEndian(Data[0x07..]); set => WriteUInt16LittleEndian(Data[0x07..], value); } - - public ushort RelearnMove1 { get => ReadUInt16LittleEndian(Data[0x11..]); set => WriteUInt16LittleEndian(Data[0x11..], value); } - public ushort RelearnMove2 { get => ReadUInt16LittleEndian(Data[0x13..]); set => WriteUInt16LittleEndian(Data[0x13..], value); } - public ushort RelearnMove3 { get => ReadUInt16LittleEndian(Data[0x15..]); set => WriteUInt16LittleEndian(Data[0x15..], value); } - public ushort RelearnMove4 { get => ReadUInt16LittleEndian(Data[0x17..]); set => WriteUInt16LittleEndian(Data[0x17..], value); } - public byte Ball { get => Data[0x1B]; set => Data[0x1B] = value; } - public ushort EggLocation { get => ReadUInt16LittleEndian(Data[0x1C..]); set => WriteUInt16LittleEndian(Data[0x1C..], value); } - public ushort MetLocation { get => ReadUInt16LittleEndian(Data[0x1E..]); set => WriteUInt16LittleEndian(Data[0x1E..], value); } - + public bool IsTransferred { get => Data[0x00] != 0; set => Data[0x00] = value ? (byte)1 : (byte)0; } + public ulong Timestamp { get => ReadUInt64LittleEndian(Data[0x01..]); set => WriteUInt64LittleEndian(Data[0x01..], value); } + public Span TransferID { get => Data.Slice(0x09, 0x10); set => value.CopyTo(Data.Slice(0x09, 0x10)); } + public string TransferText { get => Encoding.UTF8.GetString(TransferID); set => Encoding.UTF8.GetBytes(value, TransferID); } // todo, this is just a guess #endregion @@ -47,39 +36,16 @@ public sealed class GameDataPC9 : HomeOptional1, IScaledSize3, IGameDataSide #endregion /// Reconstructive logic to best apply suggested values. - public static GameDataPC9? TryCreate(PKH pkh) + public static GameDataPC9? TryCreate(PKH pkh) => CreateInternal(); + + private static GameDataPC9? CreateInternal() { - if (!PersonalTable.ZA.IsPresentInGame(pkh.Species, pkh.Form)) - return null; - - var result = CreateInternal(pkh); - if (result is null) - return null; - - result.PopulateFromCore(pkh); + var result = new GameDataPC9() + { + IsTransferred = true, + Timestamp = (ulong)DateTimeOffset.UtcNow.ToUnixTimeSeconds(), + // TODO HOME CP -- transfer ID? + }; return result; } - - private static GameDataPC9? CreateInternal(PKH pkh) - { - var side = GetNearestNeighbor(pkh); - if (side is null) - return null; - - var result = new GameDataPC9(); - result.InitializeFrom(side, pkh); - return result; - } - - private static IGameDataSide? GetNearestNeighbor(PKH pkh) - => pkh.DataPA9 ?? pkh.DataPK9 ?? pkh.DataPK8 ?? pkh.DataPB8 ?? pkh.DataPB7 ?? pkh.DataPA8 as IGameDataSide; - - public void InitializeFrom(IGameDataSide side, PKH pkh) - { - PopulateFromCore(pkh); - } - - private void PopulateFromCore(PKH pkh) - { - } } diff --git a/PKHeX.Core/PKM/HOME/PKH.cs b/PKHeX.Core/PKM/HOME/PKH.cs index 01ccf229b..3f568d313 100644 --- a/PKHeX.Core/PKM/HOME/PKH.cs +++ b/PKHeX.Core/PKM/HOME/PKH.cs @@ -57,7 +57,7 @@ private void ReadGameData1(Memory data) } } - private IGameDataSide ReadGameData1(Memory chunk, HomeGameDataFormat format) => format switch + private object ReadGameData1(Memory chunk, HomeGameDataFormat format) => format switch { HomeGameDataFormat.PB7 => DataPB7 = new GameDataPB7(chunk), HomeGameDataFormat.PK8 => DataPK8 = new GameDataPK8(chunk),