Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add differentiation between LTS and non-LTS builds #1737

Merged
merged 8 commits into from
Jul 10, 2024
50 changes: 36 additions & 14 deletions UndertaleModLib/Models/UndertaleGeneralInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,21 @@ public enum FunctionClassification : ulong
/// </summary>
public UndertaleString Name { get; set; }

/// <summary>
/// Different GameMaker release branches. LTS has some but not all features of equivalent newer versions.
/// </summary>
public enum BranchType
{
Pre2022_0,
LTS2022_0,
Post2022_0
}

/// <summary>
/// The GameMaker release branch of the data file. May be set to <see cref="BranchType.Post2022_0"/> when features exempted from LTS are detected.
/// </summary>
public BranchType Branch = BranchType.Pre2022_0;

/// <summary>
/// The major version of the data file.
/// If greater than 1, serialization produces "2.0.0.0" due to the flag no longer updating in data.win
Expand Down Expand Up @@ -309,22 +324,22 @@ public enum FunctionClassification : ulong
/// </summary>
public bool InfoTimestampOffset { get; set; } = true;

public static (uint, uint, uint, uint) TestForCommonGMSVersions(UndertaleReader reader,
(uint, uint, uint, uint) readVersion)
public static (uint, uint, uint, uint, BranchType) TestForCommonGMSVersions(UndertaleReader reader,
(uint, uint, uint, uint, BranchType) readVersion)
{
(uint Major, uint Minor, uint Release, uint Build) detectedVer = readVersion;
(uint Major, uint Minor, uint Release, uint Build, BranchType Branch) detectedVer = readVersion;

// Some GMS2+ version detection. The rest is spread around, mostly in UndertaleChunks.cs
if (reader.AllChunkNames.Contains("PSEM")) // 2023.2
detectedVer = (2023, 2, 0, 0);
if (reader.AllChunkNames.Contains("PSEM")) // 2023.2, not present on LTS
detectedVer = (2023, 2, 0, 0, BranchType.Post2022_0);
else if (reader.AllChunkNames.Contains("FEAT")) // 2022.8
detectedVer = (2022, 8, 0, 0);
detectedVer = (2022, 8, 0, 0, BranchType.Pre2022_0);
else if (reader.AllChunkNames.Contains("FEDS")) // 2.3.6
detectedVer = (2, 3, 6, 0);
detectedVer = (2, 3, 6, 0, BranchType.Pre2022_0);
else if (reader.AllChunkNames.Contains("SEQN")) // 2.3
detectedVer = (2, 3, 0, 0);
detectedVer = (2, 3, 0, 0, BranchType.Pre2022_0);
else if (reader.AllChunkNames.Contains("TGIN")) // 2.2.1
detectedVer = (2, 2, 1, 0);
detectedVer = (2, 2, 1, 0, BranchType.Pre2022_0);

if (detectedVer.Major > 2 || (detectedVer.Major == 2 && detectedVer.Minor >= 3))
{
Expand Down Expand Up @@ -466,8 +481,8 @@ public void Unserialize(UndertaleReader reader)
if (reader.ReadOnlyGEN8)
return;

var detectedVer = TestForCommonGMSVersions(reader, (Major, Minor, Release, Build));
(Major, Minor, Release, Build) = detectedVer;
var detectedVer = TestForCommonGMSVersions(reader, (Major, Minor, Release, Build, Branch));
(Major, Minor, Release, Build, Branch) = detectedVer;

if (reader.undertaleData.GeneralInfo is not null)
{
Expand Down Expand Up @@ -590,9 +605,16 @@ public override string ToString()
sb.Append(" (GMS ");
else
sb.Append(" (GM ");
sb.Append(Major);
sb.Append('.');
sb.Append(Minor);
if (Branch == BranchType.LTS2022_0) // TODO: Is there some way to dynamically get this from the enum?
{
sb.Append("2022.0");
}
else
{
sb.Append(Major);
sb.Append('.');
sb.Append(Minor);
}
if (Release != 0)
{
sb.Append('.');
Expand Down
12 changes: 6 additions & 6 deletions UndertaleModLib/Models/UndertaleRoom.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2032,7 +2032,7 @@ public void Serialize(UndertaleWriter writer)
writer.WriteUndertaleObjectPointer(Sequences);
if (!writer.undertaleData.IsVersionAtLeast(2, 3, 2))
writer.WriteUndertaleObjectPointer(NineSlices);
if (writer.undertaleData.IsVersionAtLeast(2023, 2))
if (writer.undertaleData.IsNonLTSVersionAtLeast(2023, 2))
writer.WriteUndertaleObjectPointer(ParticleSystems);
}
writer.WriteUndertaleObject(LegacyTiles);
Expand All @@ -2042,7 +2042,7 @@ public void Serialize(UndertaleWriter writer)
writer.WriteUndertaleObject(Sequences);
if (!writer.undertaleData.IsVersionAtLeast(2, 3, 2))
writer.WriteUndertaleObject(NineSlices);
if (writer.undertaleData.IsVersionAtLeast(2023, 2))
if (writer.undertaleData.IsNonLTSVersionAtLeast(2023, 2))
writer.WriteUndertaleObject(ParticleSystems);
}
}
Expand All @@ -2057,7 +2057,7 @@ public void Unserialize(UndertaleReader reader)
Sequences = reader.ReadUndertaleObjectPointer<UndertalePointerList<SequenceInstance>>();
if (!reader.undertaleData.IsVersionAtLeast(2, 3, 2))
NineSlices = reader.ReadUndertaleObjectPointer<UndertalePointerList<SpriteInstance>>();
if (reader.undertaleData.IsVersionAtLeast(2023, 2))
if (reader.undertaleData.IsNonLTSVersionAtLeast(2023, 2))
ParticleSystems = reader.ReadUndertaleObjectPointer<UndertalePointerList<ParticleSystemInstance>>();
}
reader.ReadUndertaleObject(LegacyTiles);
Expand All @@ -2067,7 +2067,7 @@ public void Unserialize(UndertaleReader reader)
reader.ReadUndertaleObject(Sequences);
if (!reader.undertaleData.IsVersionAtLeast(2, 3, 2))
reader.ReadUndertaleObject(NineSlices);
if (reader.undertaleData.IsVersionAtLeast(2023, 2))
if (reader.undertaleData.IsNonLTSVersionAtLeast(2023, 2))
reader.ReadUndertaleObject(ParticleSystems);
}
}
Expand All @@ -2087,7 +2087,7 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader)
sequencesPtr = reader.ReadUInt32();
if (!reader.undertaleData.IsVersionAtLeast(2, 3, 2))
nineSlicesPtr = reader.ReadUInt32();
if (reader.undertaleData.IsVersionAtLeast(2023, 2))
if (reader.undertaleData.IsNonLTSVersionAtLeast(2023, 2))
partSystemsPtr = reader.ReadUInt32();
}

Expand All @@ -2104,7 +2104,7 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader)
reader.AbsPosition = nineSlicesPtr;
count += 1 + UndertalePointerList<SpriteInstance>.UnserializeChildObjectCount(reader);
}
if (reader.undertaleData.IsVersionAtLeast(2023, 2))
if (reader.undertaleData.IsNonLTSVersionAtLeast(2023, 2))
{
reader.AbsPosition = partSystemsPtr;
count += 1 + UndertalePointerList<ParticleSystemInstance>.UnserializeChildObjectCount(reader);
Expand Down
12 changes: 6 additions & 6 deletions UndertaleModLib/Models/UndertaleTextureGroupInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,14 @@ public void Serialize(UndertaleWriter writer)

writer.WriteUndertaleObjectPointer(TexturePages);
writer.WriteUndertaleObjectPointer(Sprites);
if (!writer.undertaleData.IsVersionAtLeast(2023, 1))
if (!writer.undertaleData.IsNonLTSVersionAtLeast(2023, 1))
writer.WriteUndertaleObjectPointer(SpineSprites);
writer.WriteUndertaleObjectPointer(Fonts);
writer.WriteUndertaleObjectPointer(Tilesets);

writer.WriteUndertaleObject(TexturePages);
writer.WriteUndertaleObject(Sprites);
if (!writer.undertaleData.IsVersionAtLeast(2023, 1))
if (!writer.undertaleData.IsNonLTSVersionAtLeast(2023, 1))
writer.WriteUndertaleObject(SpineSprites);
writer.WriteUndertaleObject(Fonts);
writer.WriteUndertaleObject(Tilesets);
Expand All @@ -161,15 +161,15 @@ public void Unserialize(UndertaleReader reader)
// Read the pointers
TexturePages = reader.ReadUndertaleObjectPointer<UndertaleSimpleResourcesList<UndertaleEmbeddedTexture, UndertaleChunkTXTR>>();
Sprites = reader.ReadUndertaleObjectPointer<UndertaleSimpleResourcesList<UndertaleSprite, UndertaleChunkSPRT>>();
if (!reader.undertaleData.IsVersionAtLeast(2023, 1))
if (!reader.undertaleData.IsNonLTSVersionAtLeast(2023, 1))
SpineSprites = reader.ReadUndertaleObjectPointer<UndertaleSimpleResourcesList<UndertaleSprite, UndertaleChunkSPRT>>();
Fonts = reader.ReadUndertaleObjectPointer<UndertaleSimpleResourcesList<UndertaleFont, UndertaleChunkFONT>>();
Tilesets = reader.ReadUndertaleObjectPointer<UndertaleSimpleResourcesList<UndertaleBackground, UndertaleChunkBGND>>();

// Read the objects, throwing an error if the pointers are invalid
reader.ReadUndertaleObject(TexturePages);
reader.ReadUndertaleObject(Sprites);
if (!reader.undertaleData.IsVersionAtLeast(2023, 1))
if (!reader.undertaleData.IsNonLTSVersionAtLeast(2023, 1))
reader.ReadUndertaleObject(SpineSprites);
reader.ReadUndertaleObject(Fonts);
reader.ReadUndertaleObject(Tilesets);
Expand All @@ -188,7 +188,7 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader)
uint texPagesPtr = reader.ReadUInt32();
uint spritesPtr = reader.ReadUInt32();
uint spineSpritesPtr = 0;
if (!reader.undertaleData.IsVersionAtLeast(2023, 1))
if (!reader.undertaleData.IsNonLTSVersionAtLeast(2023, 1))
spineSpritesPtr = reader.ReadUInt32();
uint fontsPtr = reader.ReadUInt32();
uint tilesetsPtr = reader.ReadUInt32();
Expand All @@ -201,7 +201,7 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader)
count += 1 + UndertaleSimpleResourcesList<UndertaleSprite, UndertaleChunkSPRT>
.UnserializeChildObjectCount(reader);

if (!reader.undertaleData.IsVersionAtLeast(2023, 1))
if (!reader.undertaleData.IsNonLTSVersionAtLeast(2023, 1))
{
reader.AbsPosition = spineSpritesPtr;
count += 1 + UndertaleSimpleResourcesList<UndertaleSprite, UndertaleChunkSPRT>
Expand Down
24 changes: 17 additions & 7 deletions UndertaleModLib/UndertaleChunks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ internal override void UnserializeChunk(UndertaleReader reader)
return;
}
}

if (reader.undertaleData.IsVersionAtLeast(2023, 1) &&
reader.undertaleData.GeneralInfo.Branch == UndertaleGeneralInfo.BranchType.Pre2022_0)
{
reader.undertaleData.SetLTS(true);
}
}

internal override uint UnserializeObjectCount(UndertaleReader reader)
Expand Down Expand Up @@ -164,9 +170,9 @@ public void UnserializeGeneralData(UndertaleReader reader)
Object.Release = reader.ReadUInt32();
Object.Build = reader.ReadUInt32();

var readVer = (Object.Major, Object.Minor, Object.Release, Object.Build);
var readVer = (Object.Major, Object.Minor, Object.Release, Object.Build, Object.Branch);
var detectedVer = UndertaleGeneralInfo.TestForCommonGMSVersions(reader, readVer);
(Object.Major, Object.Minor, Object.Release, Object.Build) = detectedVer;
(Object.Major, Object.Minor, Object.Release, Object.Build, Object.Branch) = detectedVer;
}
}

Expand Down Expand Up @@ -514,8 +520,9 @@ private void CheckForGM2023_6(UndertaleReader reader)
{
// This is basically the same as the 2022.2 check, but adapted for the LineHeight value instead of Ascender.

// We already know whether the version is more or less than 2023.2 due to PSEM. Checking a shorter range narrows possibility of error.
if (!reader.undertaleData.IsVersionAtLeast(2023, 2) || reader.undertaleData.IsVersionAtLeast(2023, 6))
// We already know whether the version is more or less than 2022.8 due to FEAT. Checking a shorter range narrows possibility of error.
// PSEM (2023.2) is not used, as it would return a false negative on LTS (2022.9+ equivalent with no particles).
if (!reader.undertaleData.IsVersionAtLeast(2022, 8) || reader.undertaleData.IsVersionAtLeast(2023, 6))
{
checkedFor2023_6 = true;
return;
Expand Down Expand Up @@ -1510,7 +1517,7 @@ public class UndertaleChunkTGIN : UndertaleListChunk<UndertaleTextureGroupInfo>
private void CheckFor2022_9And2023(UndertaleReader reader)
{
if (!reader.undertaleData.IsVersionAtLeast(2, 3)
|| reader.undertaleData.IsVersionAtLeast(2022, 9))
|| reader.undertaleData.IsNonLTSVersionAtLeast(2023, 1))
{
checkedFor2022_9 = true;
return;
Expand All @@ -1533,7 +1540,8 @@ private void CheckFor2022_9And2023(UndertaleReader reader)
if (ptr < tginPtr || ptr >= secondTginPtr)
{
isGM2022_9 = true;
reader.undertaleData.SetGMS2Version(2022, 9);
if (!reader.undertaleData.IsVersionAtLeast(2022, 9))
reader.undertaleData.SetGMS2Version(2022, 9);
}
}

Expand All @@ -1554,7 +1562,9 @@ private void CheckFor2022_9And2023(UndertaleReader reader)
// The count can't be greater than the pointer.
// (the list could be either "Tilesets" or "Fonts").
if (reader.ReadUInt32() <= fourthPtr)
reader.undertaleData.SetGMS2Version(2023, 1);
{
reader.undertaleData.SetGMS2Version(2023, 1, 0, 0, false);
}
}

reader.AbsPosition = returnPosition;
Expand Down
40 changes: 39 additions & 1 deletion UndertaleModLib/UndertaleData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,8 @@ private bool TestGMS1Version(uint stableBuild, uint betaBuild, bool allowGMS2 =
/// <param name="minor">The minor version.</param>
/// <param name="release">The release version.</param>
/// <param name="build">The build version.</param>
public void SetGMS2Version(uint major, uint minor = 0, uint release = 0, uint build = 0)
/// <param name="isLTS">If included, alter the data branch between LTS and non-LTS.</param>
public void SetGMS2Version(uint major, uint minor = 0, uint release = 0, uint build = 0, bool? isLTS = null)
{
if (major != 2 && major != 2022 && major != 2023 && major != 2024)
throw new NotSupportedException("Attempted to set a version of GameMaker " + major + " using SetGMS2Version");
Expand All @@ -476,6 +477,21 @@ public void SetGMS2Version(uint major, uint minor = 0, uint release = 0, uint bu
GeneralInfo.Minor = minor;
GeneralInfo.Release = release;
GeneralInfo.Build = build;

if (isLTS is not null)
{
SetLTS((bool)isLTS);
}
}

/// <summary>
/// Sets the branch type in GeneralInfo to the appropriate LTS or non-LTS version based on
Jacky720 marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
/// <param name="isLTS">If included, alter the data branch between LTS and non-LTS.</param>
public void SetLTS(bool isLTS)
{
// Insert additional logic as needed for new branches using IsVersionAtLeast
GeneralInfo.Branch = isLTS ? UndertaleGeneralInfo.BranchType.LTS2022_0 : UndertaleGeneralInfo.BranchType.Post2022_0;
}

/// <summary>
Expand Down Expand Up @@ -509,6 +525,28 @@ public bool IsVersionAtLeast(uint major, uint minor = 0, uint release = 0, uint
return true; // The version is exactly what supplied.
}

/// <summary>
/// Reports whether the version of the data file is the same or higher than a specified version, and off the LTS branch that lacks some features.
/// </summary>
/// <param name="major">The major version.</param>
/// <param name="minor">The minor version.</param>
/// <param name="release">The release version.</param>
/// <param name="build">The build version.</param>
/// <returns>Whether the version of the data file is the same or higher than a specified version. Always false for LTS.</returns>
public bool IsNonLTSVersionAtLeast(uint major, uint minor = 0, uint release = 0, uint build = 0)
{
if (GeneralInfo is null)
{
Debug.WriteLine("\"UndertaleData.IsNonLTSVersionAtLeast()\" error - \"GeneralInfo\" is null.");
return false;
}

if (GeneralInfo.Branch < UndertaleGeneralInfo.BranchType.Post2022_0)
return false;

return IsVersionAtLeast(major, minor, release, build);
}

/// <summary>
/// TODO: needs to be documented on what this does.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion UndertaleModTool/Editors/UndertaleRoomEditor.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1364,7 +1364,7 @@ public void Command_Paste(object sender, ExecutedRoutedEventArgs e)
if (!data.IsVersionAtLeast(2, 3, 2))
layer.AssetsData.NineSlices ??= new UndertalePointerList<SpriteInstance>();
// likewise
if (data.IsVersionAtLeast(2023, 2))
if (data.IsNonLTSVersionAtLeast(2023, 2))
layer.AssetsData.ParticleSystems ??= new UndertalePointerList<ParticleSystemInstance>();
}
else if (layer.LayerType == LayerType.Tiles)
Expand Down
Loading