From ee567a7d15ea1101a074e045d98c657b2386383f Mon Sep 17 00:00:00 2001 From: Kurt Date: Sat, 20 Nov 2021 23:54:27 -0800 Subject: [PATCH] Add systemtime, (underground item, poketch, both no GUI) systemtime to be integrated to trainer info editor later --- PKHeX.Core/Saves/SAV8BS.cs | 45 ++++++++++++++- .../Saves/Substructures/Gen8/BS/Poketch8b.cs | 45 +++++++++++++++ .../Substructures/Gen8/BS/SystemData8b.cs | 57 +++++++++++++++++++ .../Gen8/BS/UndergroundItemList8b.cs | 49 ++++++++++++++++ 4 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 PKHeX.Core/Saves/Substructures/Gen8/BS/Poketch8b.cs create mode 100644 PKHeX.Core/Saves/Substructures/Gen8/BS/SystemData8b.cs create mode 100644 PKHeX.Core/Saves/Substructures/Gen8/BS/UndergroundItemList8b.cs diff --git a/PKHeX.Core/Saves/SAV8BS.cs b/PKHeX.Core/Saves/SAV8BS.cs index bc60b303d..6ce680f19 100644 --- a/PKHeX.Core/Saves/SAV8BS.cs +++ b/PKHeX.Core/Saves/SAV8BS.cs @@ -7,7 +7,7 @@ namespace PKHeX.Core public class SAV8BS : SaveFile, ISaveFileRevision, ITrainerStatRecord { // Save Data Attributes - protected internal override string ShortSummary => $"{OT} ({Version}) - {Played.LastSavedTime}"; + protected internal override string ShortSummary => $"{OT} ({Version}) - {System.LastSavedTime}"; public override string Extension => string.Empty; public override IReadOnlyList PKMExtensions => Array.FindAll(PKM.Extensions, f => @@ -20,21 +20,59 @@ public SAV8BS(byte[] data, bool exportable = true) : base(data, exportable) { Work = new FlagWork8b(this, 0x00004); Items = new MyItem8b(this, 0x0563C); + Underground = new UndergroundItemList8b(this, 0x111BC); + // saveItemShortcut PartyInfo = new Party8b(this, 0x14098); BoxLayout = new BoxLayout8b(this, 0x148AA); + // Box[] + + // PLAYER_DATA: Config = new ConfigSave8b(this, 0x79B74); // size: 0x40 MyStatus = new MyStatus8b(this, 0x79BB4); // size: 0x50 Played = new PlayTime8b(this, 0x79C04); // size: 0x04 Contest = new Contest8b(this, 0x79C08); // size: 0x720 + Zukan = new Zukan8b(this, 0x7A328); // size: 0x30B8 // 0x7D3E0 - Trainer Battle Data (bool,bool)[707] // 0x7E9F8 - Menu selections (TopMenuItemTypeInt32, bool IsNew)[8], TopMenuItemTypeInt32 LastSelected // 0x7EA3C - _FIELDOBJ_SAVE Objects[1000] (sizeof (0x44, 17 int fields), total size 0x109A0 Records = new Record8b(this, 0x8F3DC); // size: 0x78 // 0x8F454 - ENC_SV_DATA - + // PLAYER_SAVE_DATA + // SaveBallDecoData + // SaveSealData[] + // _RANDOM_GROUP + // KinomiGrowSaveData -- berry trees + // PoffinSaveData -- poffins + // BTLTOWER_SAVEWORK -- BP counts and battle tower stats + System = new SystemData8b(this, 0x95DAC); + Poketch = new Poketch8b(this, 0); // todo Daycare = new Daycare8b(this, 0x96080); // 0x2C0 // 0x96340 - _DENDOU_SAVEDATA + // BadgeSaveData + // BoukenNote + // TV_DATA + // UgSaveData + // GMS_DATA + // PLAYER_NETWORK_DATA + // UnionSaveData + // CON_PHOTO_LANG_DATA -- contest photo language data + // ZUKAN_PERSONAL_RND_DATA + // CON_PHOTO_EXT_DATA[] + // GMS_POINT_HISTORY_EXT_DATA[] + // UgCountRecord + // ReBuffnameData + // 0xE9818 -- 0x10 byte[] MD5 hash of all savedata; + + // v1.1 additions + // 0xE9828 -- RECORD_ADD_DATA: 0x30-sized[12] (0x120 bytes) + // MysteryGiftSaveData + // ZUKAN_PERSONAL_RND_DATA -- Spinda PID storage (17 * 2) + // POKETCH_POKETORE_COUNT_ARRAY -- (u16 species, u16 unused, i32 count, i32 reserved, i32 reserved) = 0x10bytes + // PLAYREPORT_DATA -- reporting player progress online? + // MT_DATA mtData; -- 0x400 bytes + // DENDOU_SAVE_ADD -- language tracking of members (hall of fame?) + Initialize(); } @@ -140,6 +178,7 @@ public override bool ChecksumsValid // public Box8 BoxInfo { get; } public FlagWork8b Work { get; } public MyItem8b Items { get; } + public UndergroundItemList8b Underground { get; } public Party8b PartyInfo { get; } // public MyItem Items { get; } public BoxLayout8b BoxLayout { get; } @@ -150,6 +189,8 @@ public override bool ChecksumsValid // public Misc8 Misc { get; } public Zukan8b Zukan { get; } public Record8b Records { get; } + public SystemData8b System { get; } + public Poketch8b Poketch { get; } public Daycare8b Daycare { get; } #endregion diff --git a/PKHeX.Core/Saves/Substructures/Gen8/BS/Poketch8b.cs b/PKHeX.Core/Saves/Substructures/Gen8/BS/Poketch8b.cs new file mode 100644 index 000000000..6f25f3464 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen8/BS/Poketch8b.cs @@ -0,0 +1,45 @@ +using System.ComponentModel; + +namespace PKHeX.Core +{ + /// + /// Details about the Poketch corner app. + /// + /// size: ??? + [TypeConverter(typeof(ExpandableObjectConverter))] + public sealed class Poketch8b : SaveBlock + { + public const int APP_REGIST_MAX = 20; + public const int POKETCH_MAP_MARK_MAX = 6; + public const int POKETCH_DOTART_DATA_BYTESIZE = 192; + public const int POKETCH_POKE_HISTORY_COUNT_MAX = 12; + public const int POKETCH_PEDOMETER_MAX = 99999; + public const int POKETCH_CALENDER_MONTH_MAX = 12; + + public Poketch8b(SaveFile sav, int offset) : base(sav) => Offset = offset; + + public enum PoketchApp8b + { + DWATCH = 0, + CALC = 1, + MEMO = 2, + PEDOMETER = 3, + POKELIST = 4, + NATSUKI_CHECK = 5, + DOWSING = 6, + SODATEYA_CAMERA = 7, + POKEMON_HISTORY = 8, + COUNTER = 9, + AWATCH = 10, + MAP_MARKING = 11, + COINTOSS = 12, + CALENDER = 13, + DOTART = 14, + ROULETTE = 15, + POKEMON_COUNTER = 16, + KITCHEN_TIMER = 17, + COLOR_CHANGER = 18, + HIDEN_WAZA = 19, + } + } +} diff --git a/PKHeX.Core/Saves/Substructures/Gen8/BS/SystemData8b.cs b/PKHeX.Core/Saves/Substructures/Gen8/BS/SystemData8b.cs new file mode 100644 index 000000000..8b527cc08 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen8/BS/SystemData8b.cs @@ -0,0 +1,57 @@ +using System; +using System.ComponentModel; + +namespace PKHeX.Core +{ + /// + /// Details about the Poketch corner app. + /// + /// size: ??? + [TypeConverter(typeof(ExpandableObjectConverter))] + public sealed class SystemData8b : SaveBlock + { + // Structure: + // (u32 count, u64 FILETIME) Start Time + // (u32 count, u64 FILETIME) Latest Save Time + // (u32 count, u64 FILETIME) Penalty Timeout Time + // (u32 count, u64 FILETIME) Last Daily Event Time + // byte[???] Snapshot + // u32 "fd_bgmEvnet" + // s64[6] reserved + private const int SIZE_GMTIME = 12; + + public SystemData8b(SaveFile sav, int offset) : base(sav) => Offset = offset; + + public uint CountStart { get => BitConverter.ToUInt32(Data, Offset + 0 + (0 * SIZE_GMTIME)); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0 + (0 * SIZE_GMTIME)); } + public long TicksStart { get => BitConverter. ToInt64(Data, Offset + 4 + (0 * SIZE_GMTIME)); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 4 + (0 * SIZE_GMTIME)); } + public uint CountLatest { get => BitConverter.ToUInt32(Data, Offset + 0 + (1 * SIZE_GMTIME)); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0 + (1 * SIZE_GMTIME)); } + public long TicksLatest { get => BitConverter. ToInt64(Data, Offset + 4 + (1 * SIZE_GMTIME)); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 4 + (1 * SIZE_GMTIME)); } + public uint CountPenalty { get => BitConverter.ToUInt32(Data, Offset + 0 + (2 * SIZE_GMTIME)); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0 + (2 * SIZE_GMTIME)); } + public long TicksPenalty { get => BitConverter. ToInt64(Data, Offset + 4 + (2 * SIZE_GMTIME)); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 4 + (2 * SIZE_GMTIME)); } + public uint CountDaily { get => BitConverter.ToUInt32(Data, Offset + 0 + (3 * SIZE_GMTIME)); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0 + (3 * SIZE_GMTIME)); } + public long TicksDaily { get => BitConverter. ToInt64(Data, Offset + 4 + (3 * SIZE_GMTIME)); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 4 + (3 * SIZE_GMTIME)); } + + // byte[] nxSnapshot + // u32 fd_bgmEvnet + + // THESE ARE IN UTC + public DateTime TimestampStart { get => DateTime.FromFileTimeUtc(TicksStart); set => TicksStart = value.ToFileTimeUtc(); } + public DateTime TimestampLatest { get => DateTime.FromFileTimeUtc(TicksLatest); set => TicksLatest = value.ToFileTimeUtc(); } + public DateTime TimestampPenalty { get => DateTime.FromFileTimeUtc(TicksPenalty); set => TicksPenalty = value.ToFileTimeUtc(); } + public DateTime TimestampDaily { get => DateTime.FromFileTimeUtc(TicksDaily); set => TicksDaily = value.ToFileTimeUtc(); } + + public DateTime LocalTimestampStart { get => TimestampStart .ToLocalTime(); set => TimestampStart = value.ToUniversalTime(); } + public DateTime LocalTimestampLatest { get => TimestampLatest .ToLocalTime(); set => TimestampLatest = value.ToUniversalTime(); } + public DateTime LocalTimestampPenalty { get => TimestampPenalty.ToLocalTime(); set => TimestampPenalty = value.ToUniversalTime(); } + public DateTime LocalTimestampDaily { get => TimestampDaily .ToLocalTime(); set => TimestampDaily = value.ToUniversalTime(); } + + public string LastSavedTime + { + get + { + var stamp = LocalTimestampLatest; + return $"{stamp.Year:0000}-{stamp.Month:00}-{stamp.Day:00} {stamp.Hour:00}ː{stamp.Minute:00}ː{stamp.Second:00}"; // not : + } + } + } +} diff --git a/PKHeX.Core/Saves/Substructures/Gen8/BS/UndergroundItemList8b.cs b/PKHeX.Core/Saves/Substructures/Gen8/BS/UndergroundItemList8b.cs new file mode 100644 index 000000000..716a5cf6c --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen8/BS/UndergroundItemList8b.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; + +namespace PKHeX.Core +{ + public sealed class UndergroundItemList8b : SaveBlock + { + public const int ItemSaveSize = 999; + public const int ItemMaxCount = 999; + public const int StatueMaxCount = 99; + + public UndergroundItemList8b(SAV8BS sav, int offset) : base(sav) => Offset = offset; + + public IReadOnlyList ReadItems() + { + var result = new UndergroundItem8b[ItemSaveSize]; + for (int i = 0; i < result.Length; i++) + result[i] = new UndergroundItem8b(Data, Offset, i); + return result; + } + } + + public class UndergroundItem8b + { + private const int SIZE = 0xC; + public readonly int Index; // not serialized + + public int Count { get; set; } + public bool HideNewFlag { get; set; } + public bool IsFavoriteFlag { get; set; } + + public UndergroundItem8b(byte[] data, int baseOffset, int index) + { + Index = index; + var offset = baseOffset + (SIZE * index); + Count = BitConverter.ToInt32(data, offset + 0); + HideNewFlag = BitConverter.ToUInt32(data, offset + 4) == 1; + IsFavoriteFlag = BitConverter.ToUInt32(data, offset + 8) == 1; + } + + public void Write(byte[] data, int baseOffset) + { + var offset = baseOffset + (SIZE * Index); + BitConverter.GetBytes(Count).CopyTo(data, offset + 0); + BitConverter.GetBytes(HideNewFlag ? 1u : 0u).CopyTo(data, offset + 4); + BitConverter.GetBytes(IsFavoriteFlag ? 1u : 0u).CopyTo(data, offset + 8); + } + } +}