diff --git a/UndertaleModLib/Models/UndertaleGameObject.cs b/UndertaleModLib/Models/UndertaleGameObject.cs index a94028af0..a201aab02 100644 --- a/UndertaleModLib/Models/UndertaleGameObject.cs +++ b/UndertaleModLib/Models/UndertaleGameObject.cs @@ -180,15 +180,7 @@ public void Serialize(UndertaleWriter writer) writer.Write(Solid); writer.Write(Depth); writer.Write(Persistent); - // This apparently has a different notation than everything else... - if (_parentId.Resource == null) - { - writer.Write(-100); - } - else - { - writer.WriteUndertaleObject(_parentId); - } + writer.WriteUndertaleObject(_parentId); writer.WriteUndertaleObject(_textureMaskId); writer.Write(UsesPhysics); writer.Write(IsSensor); @@ -221,18 +213,7 @@ public void Unserialize(UndertaleReader reader) Solid = reader.ReadBoolean(); Depth = reader.ReadInt32(); Persistent = reader.ReadBoolean(); - _parentId = new UndertaleResourceById(); - int parent = reader.ReadInt32(); - if (parent == -100) - { - _parentId.UnserializeById(reader, -1); - } - else - { - if (parent < 0 && parent != -1) // Technically can be -100 (undefined), -2 (other), or -1 (self). Other makes no sense here though - throw new Exception("Invalid value for parent - should be -100 or object id, got " + parent); - _parentId.UnserializeById(reader, parent); - } + _parentId = reader.ReadUndertaleObject>(); _textureMaskId = reader.ReadUndertaleObject>(); UsesPhysics = reader.ReadBoolean(); IsSensor = reader.ReadBoolean(); @@ -270,7 +251,7 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader) int physicsShapeVertexCount = reader.ReadInt32(); reader.Position += 12 + (uint)physicsShapeVertexCount * UndertalePhysicsVertex.ChildObjectsSize; - count += 2 + 1 + UndertalePointerList>.UnserializeChildObjectCount(reader); + count += 3 + 1 + UndertalePointerList>.UnserializeChildObjectCount(reader); return count; } diff --git a/UndertaleModLib/Models/UndertaleGeneralInfo.cs b/UndertaleModLib/Models/UndertaleGeneralInfo.cs index fb502e56c..c6f6ced64 100644 --- a/UndertaleModLib/Models/UndertaleGeneralInfo.cs +++ b/UndertaleModLib/Models/UndertaleGeneralInfo.cs @@ -496,9 +496,20 @@ public void Unserialize(UndertaleReader reader) LicenseMD5 = reader.ReadBytes(16); Timestamp = reader.ReadUInt64(); DisplayName = reader.ReadUndertaleString(); - ActiveTargets = reader.ReadUInt64(); - FunctionClassifications = (FunctionClassification)reader.ReadUInt64(); - SteamAppID = reader.ReadInt32(); + if (BytecodeVersion >= 14) + { + ActiveTargets = reader.ReadUInt64(); + FunctionClassifications = (FunctionClassification)reader.ReadUInt64(); + } + else if (BytecodeVersion >= 12) + { + FunctionClassifications = (FunctionClassification)reader.ReadUInt64(); + ActiveTargets = reader.ReadUInt64(); // FIXME: What actually is this? + } + else + FunctionClassifications = (FunctionClassification)reader.ReadUInt64(); + if (BytecodeVersion >= 13) + SteamAppID = reader.ReadInt32(); if (BytecodeVersion >= 14) DebuggerPort = reader.ReadUInt32(); RoomOrder = reader.ReadUndertaleObject>(); @@ -550,9 +561,14 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader) { reader.Position++; // "IsDebuggerDisabled" byte bytecodeVer = reader.ReadByte(); - bool readDebugPort = bytecodeVer >= 14; - reader.Position += (uint)(122 + (readDebugPort ? 4 : 0)); + reader.Position += 110; + if (bytecodeVer >= 12) + reader.Position += 8; // "ActiveTargets" + if (bytecodeVer >= 13) + reader.Position += 4; // "SteamAppID" + if (bytecodeVer >= 14) + reader.Position += 4; // "DebuggerPort" // "RoomOrder" return 1 + UndertaleSimpleResourcesList.UnserializeChildObjectCount(reader); diff --git a/UndertaleModLib/UndertaleChunks.cs b/UndertaleModLib/UndertaleChunks.cs index 55466bc2d..58a457138 100644 --- a/UndertaleModLib/UndertaleChunks.cs +++ b/UndertaleModLib/UndertaleChunks.cs @@ -674,6 +674,16 @@ internal override void UnserializeChunk(UndertaleReader reader) public class UndertaleChunkFONT : UndertaleListChunk { public override string Name => "FONT"; + + /// + /// Padding bytes at the end of the chunk. + /// + /// + /// Appeared at some point after bytecode version 6, according to the existing copy of GMS 1.0.98. + /// Before bytecode version 12 (observed in bytecode 11), this contained unknown data of varying length. + /// Afterwards, this contains UTF-16 codepoints representing ASCII's 0x00-0xFF, and is consistently + /// 512 bytes long. + /// public byte[] Padding; private static bool checkedFor2022_2; @@ -795,14 +805,22 @@ internal override void SerializeChunk(UndertaleWriter writer) { base.SerializeChunk(writer); - if (Padding == null) + if (writer.undertaleData.GeneralInfo.BytecodeVersion > 6) { - for (ushort i = 0; i < 0x80; i++) - writer.Write(i); - for (ushort i = 0; i < 0x80; i++) - writer.Write((ushort)0x3f); - } else - writer.Write(Padding); + if (Padding == null) + { + // TODO: Before bytecode 12 the size of Padding is variable. + // (though we don't properly support them in other places yet) + for (ushort i = 0; i < 0x80; i++) + writer.Write(i); + for (ushort i = 0; i < 0x80; i++) + writer.Write((ushort)0x3f); + } + else + { + writer.Write(Padding); + } + } } internal override void UnserializeChunk(UndertaleReader reader) @@ -815,7 +833,19 @@ internal override void UnserializeChunk(UndertaleReader reader) base.UnserializeChunk(reader); - Padding = reader.ReadBytes(512); + if (reader.undertaleData.GeneralInfo.BytecodeVersion > 6) + { + if (reader.undertaleData.GeneralInfo.BytecodeVersion >= 12) + { + Padding = reader.ReadBytes(512); + } + else + { + // FIXME: how did GMAC the calculate the size of padding? + int remainingBytes = (int)(Length - (reader.Position - 8)); + Padding = reader.ReadBytes(remainingBytes); + } + } } internal override uint UnserializeObjectCount(UndertaleReader reader) diff --git a/UndertaleModLib/UndertaleIO.cs b/UndertaleModLib/UndertaleIO.cs index 2af5236fa..1319aa36a 100644 --- a/UndertaleModLib/UndertaleIO.cs +++ b/UndertaleModLib/UndertaleIO.cs @@ -76,7 +76,7 @@ public int SerializeById(UndertaleWriter writer) if (CachedId < 0) throw new IOException("Unregistered object"); } - else + else if (CachedId != -100) { if (typeof(ChunkT) == typeof(UndertaleChunkAGRP)) CachedId = 0; @@ -89,7 +89,8 @@ public int SerializeById(UndertaleWriter writer) public void UnserializeById(UndertaleReader reader, int id) { - if (id < -1) + // In rare cases -100 (undefined in GML) is used instead of -1 + if (id < -1 && id != -100) throw new IOException("Invalid value for resource ID (" + typeof(ChunkT).Name + "): " + id); CachedId = id; reader.RequestResourceUpdate(this); @@ -650,7 +651,7 @@ public void ToHere() public void Align(int alignment, byte paddingbyte = 0x00) { - while ((AbsPosition & (alignment - 1)) != paddingbyte) + while ((AbsPosition & (alignment - 1)) != 0) { DebugUtil.Assert(ReadByte() == paddingbyte, "Invalid alignment padding"); } @@ -860,7 +861,7 @@ public void ThrowIfUnwrittenObjects() public void Align(int alignment, byte paddingbyte = 0x00) { - while ((Position & (alignment - 1)) != paddingbyte) + while ((Position & (alignment - 1)) != 0) { Write(paddingbyte); }