Skip to content
25 changes: 3 additions & 22 deletions UndertaleModLib/Models/UndertaleGameObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -221,18 +213,7 @@ public void Unserialize(UndertaleReader reader)
Solid = reader.ReadBoolean();
Depth = reader.ReadInt32();
Persistent = reader.ReadBoolean();
_parentId = new UndertaleResourceById<UndertaleGameObject, UndertaleChunkOBJT>();
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<UndertaleResourceById<UndertaleGameObject, UndertaleChunkOBJT>>();
_textureMaskId = reader.ReadUndertaleObject<UndertaleResourceById<UndertaleSprite, UndertaleChunkSPRT>>();
UsesPhysics = reader.ReadBoolean();
IsSensor = reader.ReadBoolean();
Expand Down Expand Up @@ -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<UndertalePointerList<Event>>.UnserializeChildObjectCount(reader);
count += 3 + 1 + UndertalePointerList<UndertalePointerList<Event>>.UnserializeChildObjectCount(reader);

return count;
}
Expand Down
26 changes: 21 additions & 5 deletions UndertaleModLib/Models/UndertaleGeneralInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<UndertaleSimpleResourcesList<UndertaleRoom, UndertaleChunkROOM>>();
Expand Down Expand Up @@ -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<UndertaleRoom, UndertaleChunkROOM>.UnserializeChildObjectCount(reader);
Expand Down
46 changes: 38 additions & 8 deletions UndertaleModLib/UndertaleChunks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,16 @@ internal override void UnserializeChunk(UndertaleReader reader)
public class UndertaleChunkFONT : UndertaleListChunk<UndertaleFont>
{
public override string Name => "FONT";

/// <summary>
/// Padding bytes at the end of the chunk.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public byte[] Padding;

private static bool checkedFor2022_2;
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
9 changes: 5 additions & 4 deletions UndertaleModLib/UndertaleIO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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");
}
Expand Down Expand Up @@ -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);
}
Expand Down