diff --git a/NHSE.Core/Hashing/FileHashRevision.cs b/NHSE.Core/Hashing/FileHashRevision.cs index 2af08c8..8993de6 100644 --- a/NHSE.Core/Hashing/FileHashRevision.cs +++ b/NHSE.Core/Hashing/FileHashRevision.cs @@ -446,5 +446,59 @@ public static class FileHashRevision public static readonly FileHashInfo REV_180 = new(REV_170); #endregion + + #region REVISION 1.9.0 + + internal const int REV_190_MAIN = 0x86D560; + internal const int REV_190_PERSONAL = 0x64160; + internal const int REV_190_POSTBOX = REV_170_POSTBOX; + internal const int REV_190_PHOTO = REV_120_PHOTO; + internal const int REV_190_PROFILE = REV_110_PROFILE; + + public static readonly FileHashInfo REV_190 = new(new FileHashDetails[] + { + new(FN_MAIN, REV_170_MAIN, new FileHashRegion[] + { + + new(0x000110, 0x1e215c), + new(0x1e2270, 0x34582c), + new(0x527bb0, 0x03693c), + new(0x55e4f0, 0x02d70c), + new(0x58bd10, 0x03693c), + new(0x5c2650, 0x02d70c), + new(0x5efe70, 0x03693c), + new(0x6267b0, 0x02d70c), + new(0x653fd0, 0x03693c), + new(0x68a910, 0x02d70c), + new(0x6b8130, 0x03693c), + new(0x6eea70, 0x02d70c), + new(0x71c290, 0x03693c), + new(0x752bd0, 0x02d70c), + new(0x7803f0, 0x03693c), + new(0x7b6d30, 0x02d70c), + new(0x7e4550, 0x03693c), + new(0x81ae90, 0x02d70c), + new(0x8485a0, 0x024fbc), + }), + new(FN_PERSONAL, REV_170_PERSONAL, new FileHashRegion[] + { + new(0x00110, 0x3693c), + new(0x36a50, 0x2d70c), + }), + new(FN_POSTBOX, REV_170_POSTBOX, new FileHashRegion[] + { + new(0x000100, 0x4732c) + }), + new(FN_PHOTO, REV_170_PHOTO, new FileHashRegion[] + { + new(0x000100, 0x2C8BC) + }), + new(FN_PROFILE, REV_170_PROFILE, new FileHashRegion[] + { + new(0x000100, 0x6945C) + }), + }); + + #endregion } } diff --git a/NHSE.Core/Save/Files/Personal.cs b/NHSE.Core/Save/Files/Personal.cs index 008fbe2..f95ee3d 100644 --- a/NHSE.Core/Save/Files/Personal.cs +++ b/NHSE.Core/Save/Files/Personal.cs @@ -164,7 +164,7 @@ public GSaveDate ProfileTimestamp public bool ProfileIsMakeVillage { get => Data[Offsets.ProfileIsMakeVillage] != 0; - set => Data[Offsets.ProfileIsMakeVillage] = value ? 1 : 0; + set => Data[Offsets.ProfileIsMakeVillage] = (byte)(value ? 1 : 0); } #endregion diff --git a/NHSE.Core/Save/Meta/RevisionChecker.cs b/NHSE.Core/Save/Meta/RevisionChecker.cs index 5a8ad0b..b0a005a 100644 --- a/NHSE.Core/Save/Meta/RevisionChecker.cs +++ b/NHSE.Core/Save/Meta/RevisionChecker.cs @@ -23,6 +23,7 @@ public static class RevisionChecker new(REV_160_MAIN, REV_160_PERSONAL, REV_160_PHOTO, REV_160_POSTBOX, REV_160_PROFILE), // 1.6.0 new(REV_170_MAIN, REV_170_PERSONAL, REV_170_PHOTO, REV_170_POSTBOX, REV_170_PROFILE), // 1.7.0 new(REV_180_MAIN, REV_180_PERSONAL, REV_180_PHOTO, REV_180_POSTBOX, REV_180_PROFILE), // 1.8.0 + new(REV_190_MAIN, REV_190_PERSONAL, REV_190_PHOTO, REV_190_POSTBOX, REV_190_PROFILE), // 1.9.0 }; private static readonly FileHeaderInfo[] RevisionInfo = @@ -45,6 +46,7 @@ public static class RevisionChecker new() { Major = 0x70001, Minor = 0x70006, HeaderRevision = 0, Unk1 = 2, SaveRevision = 15, Unk2 = 2 }, // 1.6.0 new() { Major = 0x74001, Minor = 0x74005, HeaderRevision = 0, Unk1 = 2, SaveRevision = 16, Unk2 = 2 }, // 1.7.0 new() { Major = 0x78001, Minor = 0x78001, HeaderRevision = 0, Unk1 = 2, SaveRevision = 17, Unk2 = 2 }, // 1.8.0 + new() { Major = 0x7C001, Minor = 0x7C006, HeaderRevision = 0, Unk1 = 2, SaveRevision = 18, Unk2 = 2 }, // 1.9.0 }; public static readonly IReadOnlyList SizeInfo = new[] @@ -67,6 +69,7 @@ public static class RevisionChecker SizesByRevision[6], // 1.6.0 SizesByRevision[7], // 1.7.0 SizesByRevision[8], // 1.8.0 + SizesByRevision[9], // 1.9.0 }; public static readonly IReadOnlyList HashInfo = new[] @@ -88,7 +91,8 @@ public static class RevisionChecker REV_150, // 1.5.1 REV_160, // 1.6.0 REV_170, // 1.7.0 - REV_180, // 1.7.0 + REV_180, // 1.8.0 + REV_190, // 1.9.0 }; public static bool IsRevisionKnown(this FileHeaderInfo info) => info.GetKnownRevisionIndex() >= 0; diff --git a/NHSE.Core/Save/Offsets/MainSaveOffsets.cs b/NHSE.Core/Save/Offsets/MainSaveOffsets.cs index a2f5dbd..f51a530 100644 --- a/NHSE.Core/Save/Offsets/MainSaveOffsets.cs +++ b/NHSE.Core/Save/Offsets/MainSaveOffsets.cs @@ -10,6 +10,7 @@ public abstract class MainSaveOffsets public const int PlayerCount = 8; public const int VillagerCount = 10; public const int PatternCount = 50; + public const int PatternCount2 = 100; public const int PatternTailorCount = 8; public const int BuildingCount = 46; public const int RecycleBinCount = 40; @@ -70,6 +71,7 @@ public static MainSaveOffsets GetOffsets(FileHeaderInfo Info) 15 => new MainSaveOffsets16(), 16 => new MainSaveOffsets17(), 17 => new MainSaveOffsets18(), + 18 => new MainSaveOffsets19(), _ => throw new IndexOutOfRangeException("Unknown revision!" + Environment.NewLine + Info), }; } diff --git a/NHSE.Core/Save/Offsets/MainSaveOffsets19.cs b/NHSE.Core/Save/Offsets/MainSaveOffsets19.cs new file mode 100644 index 0000000..3fc578a --- /dev/null +++ b/NHSE.Core/Save/Offsets/MainSaveOffsets19.cs @@ -0,0 +1,53 @@ +namespace NHSE.Core +{ + /// + /// + /// + public class MainSaveOffsets19 : MainSaveOffsets + { + #region GSaveLand + public const int GSaveLandStart = 0x110; + public override int Animal => GSaveLandStart + 0x10; + + public override int LandMyDesign => GSaveLandStart + 0x1e2600; + public override int PatternsPRO => LandMyDesign + (PatternCount2 * DesignPattern.SIZE); + public override int PatternFlag => PatternsPRO + (PatternCount2 * DesignPatternPRO.SIZE); + public override int PatternTailor => PatternFlag + DesignPattern.SIZE; + + public const int GSaveWeather = GSaveLandStart + 0x1e23B0; + public override int WeatherArea => GSaveWeather + 0x14; // Hemisphere + public override int WeatherRandSeed => GSaveWeather + 0x18; + + public override int EventFlagLand => GSaveLandStart + 0x22d9a8; + + // GSaveMainField + public const int GSaveMainFieldStart = GSaveLandStart + 0x22e1a8; + public override int FieldItem => GSaveMainFieldStart + 0x00000; + public override int LandMakingMap => GSaveMainFieldStart + 0xAAA00; + public override int MainFieldStructure => GSaveMainFieldStart + 0xCF600; + public override int OutsideField => GSaveMainFieldStart + 0xCF998; + public override int MyDesignMap => GSaveMainFieldStart + 0xCFA34; + + public override int PlayerHouseList => GSaveLandStart + 0x308bd4; + public override int NpcHouseList => GSaveLandStart + 0x43abd4; + + public const int GSaveShop = GSaveLandStart + 0x43be1c; + public override int ShopKabu => GSaveShop + 0x2cb0; // part of shop; tailor increased size + public override int Museum => GSaveLandStart + 0x43f1d0; + public override int Visitor => GSaveLandStart + 0x4425d4; + public override int SaveFg => GSaveLandStart + 0x442804; + public override int BulletinBoard => GSaveLandStart + 0x443148; + public override int AirportThemeColor => GSaveLandStart + 0x523d50; + #endregion + + #region GSaveLandOther + public const int GSaveLandOtherStart = 0x527aa0; + + public override int LostItemBox => GSaveLandOtherStart + 0x3408c0; + public override int LastSavedTime => GSaveLandOtherStart + 0x345220; + #endregion + + public override int VillagerSize => Villager2.SIZE; + public override IVillager ReadVillager(byte[] data) => new Villager2(data); + } +} diff --git a/NHSE.Core/Save/Offsets/PersonalOffsets.cs b/NHSE.Core/Save/Offsets/PersonalOffsets.cs index 6b2bad2..e5cea4f 100644 --- a/NHSE.Core/Save/Offsets/PersonalOffsets.cs +++ b/NHSE.Core/Save/Offsets/PersonalOffsets.cs @@ -62,6 +62,7 @@ public static PersonalOffsets GetOffsets(FileHeaderInfo Info) 15 => new PersonalOffsets16(), 16 => new PersonalOffsets17(), 17 => new PersonalOffsets18(), + 18 => new PersonalOffsets19(), _ => throw new IndexOutOfRangeException("Unknown revision!" + Environment.NewLine + Info), }; } diff --git a/NHSE.Core/Save/Offsets/PersonalOffsets18.cs b/NHSE.Core/Save/Offsets/PersonalOffsets18.cs index 0a94a98..022f893 100644 --- a/NHSE.Core/Save/Offsets/PersonalOffsets18.cs +++ b/NHSE.Core/Save/Offsets/PersonalOffsets18.cs @@ -45,4 +45,4 @@ public sealed class PersonalOffsets18 : PersonalOffsets public override IReactionStore ReadReactions(byte[] data) => data.Slice(Manpu, GSavePlayerManpu15.SIZE).ToStructure(); public override void SetReactions(byte[] data, IReactionStore value) => ((GSavePlayerManpu15)value).ToBytes().CopyTo(data, Manpu); } -} \ No newline at end of file +} diff --git a/NHSE.Core/Save/Offsets/PersonalOffsets19.cs b/NHSE.Core/Save/Offsets/PersonalOffsets19.cs new file mode 100644 index 0000000..a37f8e2 --- /dev/null +++ b/NHSE.Core/Save/Offsets/PersonalOffsets19.cs @@ -0,0 +1,48 @@ +namespace NHSE.Core +{ + /// + /// + /// + /// Same as . + public sealed class PersonalOffsets19 : PersonalOffsets + { + private const int Player = 0x110; + + public override int PersonalId => Player + 0xAFA8; + public override int EventFlagsPlayer => Player + 0xAFE0; + + private const int GSaveLifeSupport = Player + 0xBFE0; + public override int CountAchievement => GSaveLifeSupport + 0xE98; // CountAchievement + + public override int NowPoint => GSaveLifeSupport + 0x5498; // Nook Miles + public override int TotalPoint => NowPoint + 8; // Total Nook Miles Earned + public override int Birthday => Player + 0x1228c; + + public override int ProfileMain => Player + 0x122a0; + public override int ProfilePhoto => ProfileMain + 0x14; + public override int ProfileBirthday => ProfileMain + 0x23058; + public override int ProfileFruit => ProfileMain + 0x2305C; + public override int ProfileTimestamp => ProfileMain + 0x230CC; + public override int ProfileIsMakeVillage => ProfileMain + 0x230D0; + + // end player + + private const int PlayerOther = 0x36a50; + + public override int Pockets1 => PlayerOther + 0x10; + public override int Pockets2 => Pockets1 + (8 * Pockets1Count) + 0x18; + public override int Wallet => Pockets2 + (8 * Pockets2Count) + 0x18; + public override int ItemChest => PlayerOther + 0x18C; + public override int ItemCollectBit => PlayerOther + 0xA058; + public override int ItemRemakeCollectBit => PlayerOther + 0xA7AC; + public override int Manpu => PlayerOther + 0xAF7C; + public override int Bank => PlayerOther + 0x22594; + public override int Recipes => Bank + 0x10; + + public override int MaxRecipeID => 0x308; + public override int MaxRemakeBitFlag => 0x7D0 * 32; + + public override IReactionStore ReadReactions(byte[] data) => data.Slice(Manpu, GSavePlayerManpu15.SIZE).ToStructure(); + public override void SetReactions(byte[] data, IReactionStore value) => ((GSavePlayerManpu15)value).ToBytes().CopyTo(data, Manpu); + } +} diff --git a/NHSE.Core/Structures/Villager/PlayerHouse.cs b/NHSE.Core/Structures/Villager/PlayerHouse.cs index 8eae291..de8d814 100644 --- a/NHSE.Core/Structures/Villager/PlayerHouse.cs +++ b/NHSE.Core/Structures/Villager/PlayerHouse.cs @@ -69,7 +69,7 @@ public Item DoorDecoItemName set => value.ToBytesClass().CopyTo(Data, 0x263D4); } - public bool PlayerHouseFlag { get => Data[0x263DC] != 0; set => Data[0x263DC] = value ? 1 : 0; } + public bool PlayerHouseFlag { get => Data[0x263DC] != 0; set => Data[0x263DC] = (byte)(value ? 1 : 0); } public Item PostItemName { diff --git a/NHSE.Tests/DumpTests.cs b/NHSE.Tests/DumpTests.cs index 815786d..379fe05 100644 --- a/NHSE.Tests/DumpTests.cs +++ b/NHSE.Tests/DumpTests.cs @@ -7,7 +7,7 @@ public static class DumpTests { private const string RepoPath = @"C:\Users\Kurt\Documents\GitHub"; private const string PatchDumpPath = @"D:\Kurt\Desktop\" + PatchFolderName; - private const string PatchFolderName = "v18"; + private const string PatchFolderName = "v19"; private const string MessageDumpFormat = @"Message\String_{0}"; [Fact]