From 7628bb04684b08263a8096d7399eec0bdd45dc13 Mon Sep 17 00:00:00 2001 From: VladiStep Date: Sat, 18 Feb 2023 20:50:05 +0300 Subject: [PATCH] Fixed all count unserialization inaccuracies. --- .../Models/UndertaleAnimationCurve.cs | 2 +- .../Models/UndertaleFeatureFlags.cs | 2 +- .../Models/UndertaleGeneralInfo.cs | 15 +++++- UndertaleModLib/Models/UndertaleRoom.cs | 34 +++++--------- UndertaleModLib/Models/UndertaleSound.cs | 7 ++- UndertaleModLib/Models/UndertaleTags.cs | 2 +- UndertaleModLib/UndertaleChunkTypes.cs | 8 +--- UndertaleModLib/UndertaleChunks.cs | 46 +++++++++++++++---- UndertaleModLib/UndertaleIO.cs | 9 ++++ 9 files changed, 81 insertions(+), 44 deletions(-) diff --git a/UndertaleModLib/Models/UndertaleAnimationCurve.cs b/UndertaleModLib/Models/UndertaleAnimationCurve.cs index b74d431e9..7efd485fa 100644 --- a/UndertaleModLib/Models/UndertaleAnimationCurve.cs +++ b/UndertaleModLib/Models/UndertaleAnimationCurve.cs @@ -147,7 +147,7 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader) else reader.Position += 12 * count; - return count; + return 1 + count; } /// diff --git a/UndertaleModLib/Models/UndertaleFeatureFlags.cs b/UndertaleModLib/Models/UndertaleFeatureFlags.cs index 480f704ec..533eb87aa 100644 --- a/UndertaleModLib/Models/UndertaleFeatureFlags.cs +++ b/UndertaleModLib/Models/UndertaleFeatureFlags.cs @@ -29,7 +29,7 @@ public void Unserialize(UndertaleReader reader) /// public static uint UnserializeChildObjectCount(UndertaleReader reader) { - return 1 + UndertaleSimpleListString.UnserializeChildObjectCount(reader); + return UndertaleSimpleListString.UnserializeChildObjectCount(reader); } /// diff --git a/UndertaleModLib/Models/UndertaleGeneralInfo.cs b/UndertaleModLib/Models/UndertaleGeneralInfo.cs index 8a2d1e482..838ad8c33 100644 --- a/UndertaleModLib/Models/UndertaleGeneralInfo.cs +++ b/UndertaleModLib/Models/UndertaleGeneralInfo.cs @@ -462,8 +462,19 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader) reader.Bytecode14OrLower = bytecodeVer <= 14; reader.Position += 42; - reader.GMS2 = reader.ReadUInt32() >= 2; // "Major" >= 2 - reader.Position += (uint)(76 + (readDebugPort ? 4 : 0)); + + uint major = reader.ReadUInt32(); + reader.Position += 8; + uint build = reader.ReadUInt32(); + reader.Position += (uint)(64 + (readDebugPort ? 4 : 0)); + + reader.GMS2 = major >= 2; // "Major" >= 2 + + // UndertaleData.GetBuiltinSoundGroupID() + if (major > 1 || (build >= 1354 || (build >= 161 && build < 1000))) + reader.BuiltinSoundGroupID = 0; + else + reader.BuiltinSoundGroupID = 1; // "RoomOrder" return 1 + UndertaleSimpleResourcesList.UnserializeChildObjectCount(reader); diff --git a/UndertaleModLib/Models/UndertaleRoom.cs b/UndertaleModLib/Models/UndertaleRoom.cs index c0de84fb5..903600fa6 100644 --- a/UndertaleModLib/Models/UndertaleRoom.cs +++ b/UndertaleModLib/Models/UndertaleRoom.cs @@ -165,7 +165,7 @@ public enum RoomEntryFlags : uint /// public UndertaleSimpleList> Sequences { get; private set; } = new UndertaleSimpleList>(); - private static bool checkedForGMS2_2_2_302; + public static bool CheckedForGMS2_2_2_302; /// /// Calls for in order to update the room background color.
@@ -287,12 +287,18 @@ private static void CheckForGMS2_2_2_302(UndertaleReader reader) secondPtr = reader.ReadUInt32(); if (secondPtr - firstPtr == 48) + { reader.undertaleData.GMS2_2_2_302 = true; + + //"GameObject.ImageSpeed" + "...ImageIndex" + uint newSize = GameObject.ChildObjectsSize + 8; + reader.SetStaticChildObjectsSize(typeof(GameObject), newSize); + } } reader.Position = returnTo; - checkedForGMS2_2_2_302 = true; + CheckedForGMS2_2_2_302 = true; } /// @@ -372,7 +378,7 @@ public void Unserialize(UndertaleReader reader) Views = reader.ReadUndertaleObjectPointer>(); GameObjects = reader.ReadUndertaleObjectPointer>(); - if (!checkedForGMS2_2_2_302) + if (!CheckedForGMS2_2_2_302) CheckForGMS2_2_2_302(reader); Tiles = reader.ReadUndertaleObjectPointer>(); @@ -441,7 +447,7 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader) uint backgroundPtr = reader.ReadUInt32(); uint viewsPtr = reader.ReadUInt32(); uint gameObjsPtr = reader.ReadUInt32(); - if (!checkedForGMS2_2_2_302) + if (!CheckedForGMS2_2_2_302) CheckForGMS2_2_2_302(reader); uint tilesPtr = reader.ReadUInt32(); uint layersPtr = 0; @@ -456,20 +462,6 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader) sequencesPtr = reader.ReadUInt32(); } - if (reader.undertaleData.GMS2_2_2_302) - { - //"GameObject.ImageSpeed" + "...ImageIndex" - GameObject.ChildObjectsSize += 8; - } - - if (reader.BytecodeVersion >= 16) - { - // "GameObject._preCreateCode" - - GameObject.ChildObjectCount += 1; - GameObject.ChildObjectsSize += 4; - } - reader.Position = backgroundPtr; count += 1 + UndertalePointerList.UnserializeChildObjectCount(reader); reader.Position = viewsPtr; @@ -940,12 +932,11 @@ public void Dispose() public class GameObject : UndertaleObject, IRoomObject, INotifyPropertyChanged, IDisposable, IStaticChildObjCount, IStaticChildObjectsSize { - // It's an exception that these two variables are not readonly /// - public static uint ChildObjectCount = 2; + public static readonly uint ChildObjectCount = 2; /// - public static uint ChildObjectsSize = 36; + public static readonly uint ChildObjectsSize = 36; private UndertaleResourceById _objectDefinition = new(); private UndertaleResourceById _creationCode = new(); @@ -1682,7 +1673,6 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader) { uint count = 0; - count += 1; // "_background" uint tilesX = reader.ReadUInt32(); uint tilesY = reader.ReadUInt32(); reader.Position += tilesX * tilesY * 4; diff --git a/UndertaleModLib/Models/UndertaleSound.cs b/UndertaleModLib/Models/UndertaleSound.cs index 295705c76..0e8b5d4ee 100644 --- a/UndertaleModLib/Models/UndertaleSound.cs +++ b/UndertaleModLib/Models/UndertaleSound.cs @@ -170,7 +170,7 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader) AudioEntryFlags flags = (AudioEntryFlags)reader.ReadUInt32(); reader.Position += 20; - int audioGroupID = -1; + int audioGroupID; if (flags.HasFlag(AudioEntryFlags.Regular) && reader.BytecodeVersion >= 14) { @@ -178,9 +178,12 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader) count++; } else + { + audioGroupID = reader.BuiltinSoundGroupID; reader.Position += 4; // "Preload" + } - if (audioGroupID == -1) + if (audioGroupID == reader.BuiltinSoundGroupID) { reader.Position += 4; // "_audioFile" count++; diff --git a/UndertaleModLib/Models/UndertaleTags.cs b/UndertaleModLib/Models/UndertaleTags.cs index e2607731b..ef30e8626 100644 --- a/UndertaleModLib/Models/UndertaleTags.cs +++ b/UndertaleModLib/Models/UndertaleTags.cs @@ -65,7 +65,7 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader) { uint count = 0; - count += 1 + UndertaleSimpleListString.UnserializeChildObjectCount(reader); + count += UndertaleSimpleListString.UnserializeChildObjectCount(reader); count += 1 + UndertalePointerList.UnserializeChildObjectCount(reader); return count; diff --git a/UndertaleModLib/UndertaleChunkTypes.cs b/UndertaleModLib/UndertaleChunkTypes.cs index 560908eed..7f37dc720 100644 --- a/UndertaleModLib/UndertaleChunkTypes.cs +++ b/UndertaleModLib/UndertaleChunkTypes.cs @@ -227,11 +227,7 @@ internal override void UnserializeChunk(UndertaleReader reader) internal override uint UnserializeObjectCount(UndertaleReader reader) { - uint count = 1; - - count += UndertalePointerList.UnserializeChildObjectCount(reader); - - return count; + return UndertalePointerList.UnserializeChildObjectCount(reader); } public IList GetList() => List; @@ -307,7 +303,7 @@ internal override uint UnserializeObjectCount(UndertaleReader reader) throw new InvalidOperationException( "\"UndertaleAlignUpdatedListChunk\" supports the count unserialization only for backgrounds and strings."); - return 1 + count; + return count; } } diff --git a/UndertaleModLib/UndertaleChunks.cs b/UndertaleModLib/UndertaleChunks.cs index 2d7868c75..40d8984a3 100644 --- a/UndertaleModLib/UndertaleChunks.cs +++ b/UndertaleModLib/UndertaleChunks.cs @@ -261,6 +261,8 @@ internal override void SerializeChunk(UndertaleWriter writer) internal override uint UnserializeObjectCount(UndertaleReader reader) { + checkedFor2022_6 = false; + if (reader.GMS2_3) CheckFor2022_6(reader); @@ -446,6 +448,8 @@ internal override void UnserializeChunk(UndertaleReader reader) internal override uint UnserializeObjectCount(UndertaleReader reader) { + checkedFor2022_2 = false; + if (reader.BytecodeVersion >= 17) CheckForGM2022_2(reader); @@ -511,6 +515,8 @@ internal override void UnserializeChunk(UndertaleReader reader) internal override uint UnserializeObjectCount(UndertaleReader reader) { + checkedFor2022_5 = false; + if (reader.undertaleData.GMS2_3) CheckFor2022_5(reader); @@ -532,8 +538,23 @@ internal override void UnserializeChunk(UndertaleReader reader) internal override uint UnserializeObjectCount(UndertaleReader reader) { + checkedFor2022_1 = false; + UndertaleRoom.CheckedForGMS2_2_2_302 = false; + CheckForEffectData(reader); + if (reader.BytecodeVersion >= 16) + { + // "GameObject._preCreateCode" + + Type gameObjType = typeof(GameObject); + + uint newValue = GameObject.ChildObjectCount + 1; + reader.SetStaticChildCount(gameObjType, newValue); + newValue = GameObject.ChildObjectsSize + 4; + reader.SetStaticChildObjectsSize(gameObjType, newValue); + } + return base.UnserializeObjectCount(reader); } @@ -685,7 +706,7 @@ internal override uint UnserializeObjectCount(UndertaleReader reader) return 0; if (reader.undertaleData.UnsupportedBytecodeVersion) - return 1 + reader.ReadUInt32(); + return reader.ReadUInt32(); reader.GMS2BytecodeAddresses = new((int)reader.ReadUInt32()); reader.Position -= 4; @@ -757,7 +778,7 @@ internal override void UnserializeChunk(UndertaleReader reader) else varLength = 12; List.Clear(); - List.Capacity = (int)(Length / varLength) - 1; + List.Capacity = (int)(Length / varLength); while (reader.Position + varLength <= startPosition + Length) List.Add(reader.ReadUndertaleObject()); } @@ -770,8 +791,13 @@ internal override uint UnserializeObjectCount(UndertaleReader reader) if (reader.undertaleData.UnsupportedBytecodeVersion) return 0; - int varLength = reader.Bytecode14OrLower ? 12 : 20; - return Length / (uint)varLength - 1; + if (!reader.Bytecode14OrLower) + { + reader.Position += 12; + return (Length - 12) / 20; + } + else + return Length / 12; } } @@ -1010,6 +1036,8 @@ internal override void UnserializeChunk(UndertaleReader reader) internal override uint UnserializeObjectCount(UndertaleReader reader) { + checkedFor2022_3 = false; + CheckFor2022_3And5(reader); // Texture blobs are already included in the count @@ -1040,7 +1068,7 @@ internal override uint UnserializeObjectCount(UndertaleReader reader) { // Though "UndertaleEmbeddedAudio" has dynamic child objects size, // there's still no need to unserialize the count for each object. - return 1 + reader.ReadUInt32(); + return reader.ReadUInt32(); } } @@ -1134,6 +1162,8 @@ internal override void UnserializeChunk(UndertaleReader reader) internal override uint UnserializeObjectCount(UndertaleReader reader) { + checkedFor2022_8 = false; + if (!reader.GMS2) throw new InvalidOperationException(); @@ -1219,7 +1249,7 @@ internal override void UnserializeChunk(UndertaleReader reader) internal override uint UnserializeObjectCount(UndertaleReader reader) { - uint count = 1; + checkedForGMS2_3_1 = false; // Padding while (reader.Position % 4 != 0) @@ -1232,9 +1262,7 @@ internal override uint UnserializeObjectCount(UndertaleReader reader) if (!reader.undertaleData.GMS2_3_1) CheckForGMS2_3_1(reader); - count += base.UnserializeObjectCount(reader); - - return count; + return base.UnserializeObjectCount(reader); } } diff --git a/UndertaleModLib/UndertaleIO.cs b/UndertaleModLib/UndertaleIO.cs index df678414f..548d9865a 100644 --- a/UndertaleModLib/UndertaleIO.cs +++ b/UndertaleModLib/UndertaleIO.cs @@ -209,6 +209,7 @@ public void SubmitMessage(string message) public bool GMS2_3 = false; public byte BytecodeVersion = 0; public bool Bytecode14OrLower = false; + public int BuiltinSoundGroupID = -1; public UndertaleChunk ReadUndertaleChunk() { @@ -467,6 +468,14 @@ public uint GetStaticChildObjectsSize(Type objType) return res; } + public void SetStaticChildCount(Type objType, uint count) + { + staticObjCountDict[objType] = count; + } + public void SetStaticChildObjectsSize(Type objType, uint size) + { + staticObjSizeDict[objType] = size; + } public Dictionary GetOffsetMap() {