diff --git a/BenchmarkTest/BenchmarkTest.csproj b/BenchmarkTest/BenchmarkTest.csproj new file mode 100644 index 0000000..f569f93 --- /dev/null +++ b/BenchmarkTest/BenchmarkTest.csproj @@ -0,0 +1,18 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + + + diff --git a/BenchmarkTest/DecompileBenchmark.cs b/BenchmarkTest/DecompileBenchmark.cs new file mode 100644 index 0000000..e83979f --- /dev/null +++ b/BenchmarkTest/DecompileBenchmark.cs @@ -0,0 +1,41 @@ +using BenchmarkDotNet.Attributes; +using UndertaleModLib; +using UndertaleModLib.Decompiler; +using UndertaleModLib.Models; + +namespace BenchmarkTest; + +[MemoryDiagnoser] +public class DecompileBenchmark +{ + public UndertaleData data; + public GlobalDecompileContext decompileContext; + + [GlobalSetup] + public void GlobalSetup() + { + using (FileStream fs = new FileInfo(@"/home/narr/Dokumente/am2r 1.5.5/assets/game.unx_older").OpenRead()) + { + data = UndertaleIO.Read(fs); + } + decompileContext = new GlobalDecompileContext(data, false); + } + + [Benchmark] + public void AppendVariableToEveryEntry() + { + void AppendGML(UndertaleCode code, string appendedText) + { + var codeText = Decompiler.Decompile(code, decompileContext); + codeText = codeText + appendedText + "\n"; + code.ReplaceGML(codeText, data); + } + + foreach (UndertaleCode codeentry in data.Code.SkipLast((int)(data.Code.Count * 0.99))) + { + if (codeentry.Name.Content == "gml_Object_oRm_a5c11lock_Collision_267") continue; + + AppendGML(codeentry, "var this_variable_is_not_used_and_thus_completely_uselesss = 1; if (!this_variable_is_not_used_and_thus_completely_uselesss) this_variable_is_not_used_and_thus_completely_uselesss = 1"); + } + } +} diff --git a/BenchmarkTest/Program.cs b/BenchmarkTest/Program.cs new file mode 100644 index 0000000..334df3d --- /dev/null +++ b/BenchmarkTest/Program.cs @@ -0,0 +1,7 @@ +// See https://aka.ms/new-console-template for more information + +using BenchmarkDotNet.Running; +using BenchmarkTest; + +Console.WriteLine("Hello, World!"); +BenchmarkRunner.Run(); diff --git a/YAMS-LIB/ExtensionMethods.cs b/YAMS-LIB/ExtensionMethods.cs index d2a07aa..f952f64 100644 --- a/YAMS-LIB/ExtensionMethods.cs +++ b/YAMS-LIB/ExtensionMethods.cs @@ -25,7 +25,18 @@ public static string GetGMLCode(this UndertaleCode code) public static void ReplaceGMLInCode(this UndertaleCode code, string textToReplace, string replacementText, bool ignoreErrors = false) { - var codeText = Decompiler.Decompile(code, decompileContext); + string codeText; + + if (Patcher.CodeCache.TryGetValue(code, out string? value)) + { + codeText = value; + } + else + { + codeText = Decompiler.Decompile(code, decompileContext); + Patcher.CodeCache.Add(code, codeText); + } + if (!codeText.Contains(textToReplace)) { if (ignoreErrors) @@ -34,26 +45,52 @@ public static void ReplaceGMLInCode(this UndertaleCode code, string textToReplac throw new ApplicationException($"The text \"{textToReplace}\" was not found in \"{code.Name.Content}\"!"); } codeText = codeText.Replace(textToReplace, replacementText); - code.ReplaceGML(codeText, gmData); + Patcher.CodeCache[code] = codeText; } public static void PrependGMLInCode(this UndertaleCode code, string prependedText) { - var codeText = Decompiler.Decompile(code, decompileContext); + string codeText; + if (Patcher.CodeCache.TryGetValue(code, out string? value)) + { + codeText = value; + } + else + { + codeText = Decompiler.Decompile(code, decompileContext); + Patcher.CodeCache.Add(code, codeText); + } codeText = prependedText + "\n" + codeText; - code.ReplaceGML(codeText, gmData); + Patcher.CodeCache[code] = codeText; } public static void AppendGMLInCode(this UndertaleCode code, string appendedText) { - var codeText = Decompiler.Decompile(code, decompileContext); + string codeText; + if (Patcher.CodeCache.TryGetValue(code, out string? value)) + { + codeText = value; + } + else + { + codeText = Decompiler.Decompile(code, decompileContext); + Patcher.CodeCache.Add(code, codeText); + } codeText = codeText + appendedText + "\n"; - code.ReplaceGML(codeText, gmData); + Patcher.CodeCache[code] = codeText; } public static void SubstituteGMLCode(this UndertaleCode code, string newGMLCode) { - code.ReplaceGML(newGMLCode, gmData); + Patcher.CodeCache[code] = newGMLCode; + } + + public static void FlushCode() + { + foreach ((var codeName, var codeText) in Patcher.CodeCache) + { + codeName.ReplaceGML(codeText, gmData); + } } public static UndertaleRoom.Tile CreateRoomTile(int x, int y, int depth, UndertaleBackground tileset, uint sourceX, uint sourceY, uint width = 16, uint height = 16, uint? id = null) diff --git a/YAMS-LIB/Program.cs b/YAMS-LIB/Program.cs index ded077f..668ce3e 100644 --- a/YAMS-LIB/Program.cs +++ b/YAMS-LIB/Program.cs @@ -21,6 +21,8 @@ public class Patcher internal static GlobalDecompileContext? decompileContext; internal static bool isHorde = false; + internal static Dictionary CodeCache = new Dictionary(1024); + private static string CreateVersionString() { Assembly assembly = Assembly.GetExecutingAssembly(); @@ -49,13 +51,17 @@ public static void Main(string am2rPath, string outputAm2rPath, string jsonPath) SeedObject? seedObject = JsonSerializer.Deserialize(File.ReadAllText(jsonPath)); - // Read 1.5.x data - gmData = new UndertaleData(); + Stopwatch sw = new Stopwatch(); + sw.Start(); + // Read 1.5.x data using (FileStream fs = new FileInfo(am2rPath).OpenRead()) { gmData = UndertaleIO.Read(fs); } + sw.Stop(); + var afterRead = sw.Elapsed; + sw.Start(); Console.WriteLine("Read data file."); decompileContext = new GlobalDecompileContext(gmData, false); @@ -628,10 +634,18 @@ public static void Main(string am2rPath, string outputAm2rPath, string jsonPath) Multiworld.Apply(gmData, decompileContext, seedObject); AddBossMWTracking.Apply(gmData, decompileContext, seedObject); + // Write back to disk + ExtensionMethods.FlushCode(); + sw.Stop(); + var beforeWrite = sw.Elapsed; + sw.Start(); using (FileStream fs = new FileInfo(outputAm2rPath).OpenWrite()) { UndertaleIO.Write(fs, gmData, Console.WriteLine); } + sw.Stop(); + Console.WriteLine($"Total Time: {sw.Elapsed}"); + Console.WriteLine($"Patching Time Only: {beforeWrite-afterRead}"); } } diff --git a/YAMS-LIB/patches/DecoupleItemsFromLocations.cs b/YAMS-LIB/patches/DecoupleItemsFromLocations.cs index 4b8d386..6d06780 100644 --- a/YAMS-LIB/patches/DecoupleItemsFromLocations.cs +++ b/YAMS-LIB/patches/DecoupleItemsFromLocations.cs @@ -38,31 +38,31 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC gmData.Code.ByName(code).ReplaceGMLInCode("global.item[0]", "global.hasBombs"); } - UndertaleGameObject? elderSeptogg = gmData.GameObjects.ByName("oElderSeptogg"); + const string elderSeptoggName = "oElderSeptogg"; foreach (var gameObject in new[] { - gmData.Rooms.ByName("rm_a0h11").GameObjects.First(go => go.X == 480 && go.Y == 768 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a0h25").GameObjects.First(go => go.X == 120 && go.Y == 816 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a0h25").GameObjects.First(go => go.X == 168 && go.Y == 256 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a0h29").GameObjects.First(go => go.X == 384 && go.Y == 312 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a1h05").GameObjects.First(go => go.X == 1184 && go.Y == 832 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a3h04").GameObjects.First(go => go.X == 528 && go.Y == 1344 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a3h04").GameObjects.First(go => go.X == 1728 && go.Y == 1248 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a3a07").GameObjects.First(go => go.X == 112 && go.Y == 240 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a3b02").GameObjects.First(go => go.X == 192 && go.Y == 896 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a3b08").GameObjects.First(go => go.X == 224 && go.Y == 352 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a0h17").GameObjects.First(go => go.X == 96 && go.Y == 352 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a4b02a").GameObjects.First(go => go.X == 120 && go.Y == 816 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a4b10").GameObjects.First(go => go.X == 144 && go.Y == 624 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a4b10").GameObjects.First(go => go.X == 512 && go.Y == 256 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a4b11").GameObjects.First(go => go.X == 224 && go.Y == 2288 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a5c13").GameObjects.First(go => go.X == 96 && go.Y == 704 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a5c14").GameObjects.First(go => go.X == 1056 && go.Y == 288 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a5c17").GameObjects.First(go => go.X == 192 && go.Y == 288 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a5c18").GameObjects.First(go => go.X == 128 && go.Y == 192 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a5c18").GameObjects.First(go => go.X == 480 && go.Y == 192 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a5c21").GameObjects.First(go => go.X == 160 && go.Y == 384 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), - gmData.Rooms.ByName("rm_a5c21").GameObjects.First(go => go.X == 96 && go.Y == 560 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content), + gmData.Rooms.ByName("rm_a0h11").GameObjects.First(go => go.X == 480 && go.Y == 768 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a0h25").GameObjects.First(go => go.X == 120 && go.Y == 816 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a0h25").GameObjects.First(go => go.X == 168 && go.Y == 256 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a0h29").GameObjects.First(go => go.X == 384 && go.Y == 312 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a1h05").GameObjects.First(go => go.X == 1184 && go.Y == 832 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a3h04").GameObjects.First(go => go.X == 528 && go.Y == 1344 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a3h04").GameObjects.First(go => go.X == 1728 && go.Y == 1248 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a3a07").GameObjects.First(go => go.X == 112 && go.Y == 240 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a3b02").GameObjects.First(go => go.X == 192 && go.Y == 896 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a3b08").GameObjects.First(go => go.X == 224 && go.Y == 352 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a0h17").GameObjects.First(go => go.X == 96 && go.Y == 352 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a4b02a").GameObjects.First(go => go.X == 120 && go.Y == 816 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a4b10").GameObjects.First(go => go.X == 144 && go.Y == 624 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a4b10").GameObjects.First(go => go.X == 512 && go.Y == 256 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a4b11").GameObjects.First(go => go.X == 224 && go.Y == 2288 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a5c13").GameObjects.First(go => go.X == 96 && go.Y == 704 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a5c14").GameObjects.First(go => go.X == 1056 && go.Y == 288 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a5c17").GameObjects.First(go => go.X == 192 && go.Y == 288 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a5c18").GameObjects.First(go => go.X == 128 && go.Y == 192 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a5c18").GameObjects.First(go => go.X == 480 && go.Y == 192 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a5c21").GameObjects.First(go => go.X == 160 && go.Y == 384 && go.ObjectDefinition.Name.Content == elderSeptoggName), + gmData.Rooms.ByName("rm_a5c21").GameObjects.First(go => go.X == 96 && go.Y == 560 && go.ObjectDefinition.Name.Content == elderSeptoggName), }) { gameObject.CreationCode.ReplaceGMLInCode("global.item[0]", "global.hasBombs"); @@ -77,7 +77,7 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC subscreenMenuStep.ReplaceGMLInCode("global.item[2] == 0", "!global.hasSpiderball"); foreach (UndertaleCode code in gmData.Code.Where(c => (c.Name.Content.StartsWith("gml_Script_scr_septoggs_") && c.Name.Content.Contains('2')) || - c.Name.Content == gmData.Rooms.ByName("rm_a0h25").GameObjects.First(go => go.X == 120 && go.Y == 816 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content).CreationCode.Name.Content) + c.Name.Content == gmData.Rooms.ByName("rm_a0h25").GameObjects.First(go => go.X == 120 && go.Y == 816 && go.ObjectDefinition.Name.Content == elderSeptoggName).CreationCode.Name.Content) ) { code.ReplaceGMLInCode("global.item[2]", "global.hasSpiderball"); @@ -95,7 +95,7 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC foreach (UndertaleCode? code in gmData.Code.Where(c => (c.Name.Content.StartsWith("gml_Script_scr_septoggs_") && c.Name.Content.Contains('4')) || c.Name.Content == "gml_Room_rm_a3b08_Create" || - c == gmData.Rooms.ByName("rm_a5c17").GameObjects.First(go => go.X == 192 && go.Y == 288 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content).CreationCode) + c == gmData.Rooms.ByName("rm_a5c17").GameObjects.First(go => go.X == 192 && go.Y == 288 && go.ObjectDefinition.Name.Content == elderSeptoggName).CreationCode) ) { code.ReplaceGMLInCode("global.item[4]", "global.hasHijump"); @@ -120,7 +120,7 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC foreach (UndertaleCode? code in gmData.Code.Where(c => (c.Name.Content.StartsWith("gml_Script_scr_septoggs_") && c.Name.Content.Contains('6')) || gmData.Rooms.ByName("rm_a5a03").GameObjects.Where(go => go.X is >= 96 and <= 112 && go.Y is >= 240 and <= 288 && go.ObjectDefinition.Name.Content == "oBlockStep").Select(go => go.CreationCode).Contains(c) || - c == gmData.Rooms.ByName("rm_a0h25").GameObjects.First(go => go.X == 120 && go.Y == 816 && go.ObjectDefinition.Name.Content == elderSeptogg.Name.Content).CreationCode) + c == gmData.Rooms.ByName("rm_a0h25").GameObjects.First(go => go.X == 120 && go.Y == 816 && go.ObjectDefinition.Name.Content == elderSeptoggName).CreationCode) ) { code.ReplaceGMLInCode("global.item[6]", "global.hasSpacejump"); @@ -210,7 +210,7 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC } """); subscreenMenuStep.ReplaceGMLInCode(""" - if (global.curropt == 7 && (!global.hasIbeam)) + if (global.curropt == 7 && !global.hasIbeam) global.curropt += 1 """, """ if (global.curropt == 7 && (!global.hasIbeam)) @@ -219,7 +219,7 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC global.curropt += 1 """); subscreenMenuStep.ReplaceGMLInCode(""" - if (global.curropt == 7 && (!global.hasIbeam)) + if (global.curropt == 7 && !global.hasIbeam) global.curropt -= 1 """, """ if (global.curropt == 8 && (!global.hasMorph)) diff --git a/YAMS-LIB/patches/StartingItems.cs b/YAMS-LIB/patches/StartingItems.cs index 34a8eb6..944274f 100644 --- a/YAMS-LIB/patches/StartingItems.cs +++ b/YAMS-LIB/patches/StartingItems.cs @@ -1,3 +1,4 @@ +using System.Text; using UndertaleModLib; using UndertaleModLib.Decompiler; using UndertaleModLib.Models; @@ -9,12 +10,13 @@ public class StartingItems public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileContext, SeedObject seedObject) { UndertaleCode? characterVarsCode = gmData.Code.ByName("gml_Script_load_character_vars"); + StringBuilder textToAppend = new StringBuilder(); // Set starting items bool alreadyAddedMissiles = false; bool alreadyAddedSupers = false; bool alreadyAddedPBombs = false; - characterVarsCode.AppendGMLInCode("global.collectedItems = \"items:\""); + textToAppend.AppendLine("global.collectedItems = \"items:\";"); int howMuchDna = 0; foreach ((ItemEnum item, int quantity) in seedObject.StartingItems) { @@ -22,8 +24,8 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC switch (item) { case ItemEnum.EnergyTank: - characterVarsCode.AppendGMLInCode($"global.etanks = {quantity};"); - characterVarsCode.AppendGMLInCode($"global.playerhealth = {seedObject.Patches.EnergyPerTank + seedObject.Patches.EnergyPerTank * quantity - 1};"); + textToAppend.AppendLine($"global.etanks = {quantity};"); + textToAppend.AppendLine($"global.playerhealth = {seedObject.Patches.EnergyPerTank + seedObject.Patches.EnergyPerTank * quantity - 1};"); break; case ItemEnum.LockedMissile: case ItemEnum.Missile: @@ -36,7 +38,7 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC if (item == ItemEnum.LockedMissile && seedObject.StartingItems.TryGetValue(ItemEnum.Missile, out int missileQuantity)) finalQuantity += missileQuantity; - characterVarsCode.AppendGMLInCode($"global.missiles = {finalQuantity};"); + textToAppend.AppendLine($"global.missiles = {finalQuantity};"); alreadyAddedMissiles = true; break; case ItemEnum.LockedSuperMissile: @@ -50,7 +52,7 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC if (item == ItemEnum.LockedSuperMissile && seedObject.StartingItems.TryGetValue(ItemEnum.SuperMissile, out int superQuantity)) finalQuantity += superQuantity; - characterVarsCode.AppendGMLInCode($"global.smissiles = {finalQuantity};"); + textToAppend.AppendLine($"global.smissiles = {finalQuantity};"); alreadyAddedSupers = true; break; @@ -62,7 +64,7 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC if (item == ItemEnum.LockedPBomb && seedObject.StartingItems.TryGetValue(ItemEnum.PBomb, out int pBombQuantity)) finalQuantity += pBombQuantity; - characterVarsCode.AppendGMLInCode($"global.pbombs = {finalQuantity};"); + textToAppend.AppendLine($"global.pbombs = {finalQuantity};"); alreadyAddedPBombs = true; break; case ItemEnum.MissileLauncher: @@ -77,114 +79,114 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC break; case ItemEnum.Bombs: - characterVarsCode.AppendGMLInCode($"global.hasBombs = {quantity};"); + textToAppend.AppendLine($"global.hasBombs = {quantity};"); break; case ItemEnum.Powergrip: - characterVarsCode.AppendGMLInCode($"global.hasPowergrip = {quantity};"); + textToAppend.AppendLine($"global.hasPowergrip = {quantity};"); break; case ItemEnum.Spiderball: - characterVarsCode.AppendGMLInCode($"global.hasSpiderball = {quantity};"); + textToAppend.AppendLine($"global.hasSpiderball = {quantity};"); break; case ItemEnum.Springball: - characterVarsCode.AppendGMLInCode($"global.hasJumpball = {quantity};"); + textToAppend.AppendLine($"global.hasJumpball = {quantity};"); break; case ItemEnum.Hijump: - characterVarsCode.AppendGMLInCode($"global.hasHijump = {quantity};"); + textToAppend.AppendLine($"global.hasHijump = {quantity};"); break; case ItemEnum.Varia: - characterVarsCode.AppendGMLInCode($"global.hasVaria = {quantity};"); + textToAppend.AppendLine($"global.hasVaria = {quantity};"); break; case ItemEnum.Spacejump: - characterVarsCode.AppendGMLInCode($"global.hasSpacejump = {quantity};"); + textToAppend.AppendLine($"global.hasSpacejump = {quantity};"); break; case ItemEnum.ProgressiveJump: - if (quantity >= 1) characterVarsCode.AppendGMLInCode("global.hasHijump = 1;"); + if (quantity >= 1) textToAppend.AppendLine("global.hasHijump = 1;"); - if (quantity >= 2) characterVarsCode.AppendGMLInCode("global.hasSpacejump = 1;"); + if (quantity >= 2) textToAppend.AppendLine("global.hasSpacejump = 1;"); break; case ItemEnum.Speedbooster: - characterVarsCode.AppendGMLInCode($"global.hasSpeedbooster = {quantity};"); + textToAppend.AppendLine($"global.hasSpeedbooster = {quantity};"); break; case ItemEnum.Screwattack: - characterVarsCode.AppendGMLInCode($"global.hasScrewattack = {quantity};"); + textToAppend.AppendLine($"global.hasScrewattack = {quantity};"); break; case ItemEnum.Gravity: - characterVarsCode.AppendGMLInCode($"global.hasGravity = {quantity};"); + textToAppend.AppendLine($"global.hasGravity = {quantity};"); break; case ItemEnum.ProgressiveSuit: - if (quantity >= 1) characterVarsCode.AppendGMLInCode("global.hasVaria = 1;"); + if (quantity >= 1) textToAppend.AppendLine("global.hasVaria = 1;"); - if (quantity >= 2) characterVarsCode.AppendGMLInCode( "global.hasGravity = 1;"); + if (quantity >= 2) textToAppend.AppendLine( "global.hasGravity = 1;"); break; case ItemEnum.Power: // Stubbed for now, may get a purpose in the future break; case ItemEnum.Charge: - characterVarsCode.AppendGMLInCode($"global.hasCbeam = {quantity};"); + textToAppend.AppendLine($"global.hasCbeam = {quantity};"); break; case ItemEnum.Ice: - characterVarsCode.AppendGMLInCode($"global.hasIbeam = {quantity};"); + textToAppend.AppendLine($"global.hasIbeam = {quantity};"); break; case ItemEnum.Wave: - characterVarsCode.AppendGMLInCode($"global.hasWbeam = {quantity};"); + textToAppend.AppendLine($"global.hasWbeam = {quantity};"); break; case ItemEnum.Spazer: - characterVarsCode.AppendGMLInCode($"global.hasSbeam = {quantity};"); + textToAppend.AppendLine($"global.hasSbeam = {quantity};"); break; case ItemEnum.Plasma: - characterVarsCode.AppendGMLInCode($"global.hasPbeam = {quantity};"); + textToAppend.AppendLine($"global.hasPbeam = {quantity};"); break; case ItemEnum.Morphball: - characterVarsCode.AppendGMLInCode($"global.hasMorph = {quantity};"); + textToAppend.AppendLine($"global.hasMorph = {quantity};"); break; case ItemEnum.Flashlight: - characterVarsCode.AppendGMLInCode($"global.flashlightLevel = {quantity};"); + textToAppend.AppendLine($"global.flashlightLevel = {quantity};"); break; case ItemEnum.Blindfold: - characterVarsCode.AppendGMLInCode($"global.flashlightLevel = -{quantity};"); + textToAppend.AppendLine($"global.flashlightLevel = -{quantity};"); break; case ItemEnum.SpeedBoosterUpgrade: - characterVarsCode.AppendGMLInCode($"global.speedBoosterFramesReduction = {quantity}"); + textToAppend.AppendLine($"global.speedBoosterFramesReduction = {quantity};"); break; case ItemEnum.WalljumpBoots: - characterVarsCode.AppendGMLInCode($"global.hasWJ = {quantity}"); + textToAppend.AppendLine($"global.hasWJ = {quantity};"); break; case ItemEnum.InfiniteBombPropulsion: - characterVarsCode.AppendGMLInCode($"global.hasIBJ = {quantity}"); + textToAppend.AppendLine($"global.hasIBJ = {quantity};"); break; case ItemEnum.LongBeam: - characterVarsCode.AppendGMLInCode($"global.hasLongBeam = {quantity}"); + textToAppend.AppendLine($"global.hasLongBeam = {quantity};"); break; case ItemEnum.Nothing: break; default: throw new ArgumentOutOfRangeException(); } - characterVarsCode.AppendGMLInCode($"global.collectedItems += \"{item.GetEnumMemberValue()}|{quantity},\""); + textToAppend.AppendLine($"global.collectedItems += \"{item.GetEnumMemberValue()}|{quantity},\";"); } // After we have gotten our starting items, adjust the DNA counter - characterVarsCode.PrependGMLInCode($"global.dna = (46 - {seedObject.Patches.RequiredDNAmount}) + {howMuchDna}"); + characterVarsCode.PrependGMLInCode($"global.dna = (46 - {seedObject.Patches.RequiredDNAmount}) + {howMuchDna};"); // Check whether option has been set for non-main launchers or if starting with them, if yes enable the main launchers in character var if (!seedObject.Patches.RequireMissileLauncher || seedObject.StartingItems.ContainsKey(ItemEnum.MissileLauncher)) { - characterVarsCode.AppendGMLInCode("global.missileLauncher = 1"); + textToAppend.AppendLine("global.missileLauncher = 1;"); } if (!seedObject.Patches.RequireSuperLauncher || seedObject.StartingItems.ContainsKey(ItemEnum.SuperMissileLauncher)) { - characterVarsCode.AppendGMLInCode("global.SMissileLauncher = 1"); + textToAppend.AppendLine("global.SMissileLauncher = 1;"); } if (!seedObject.Patches.RequirePBLauncher || seedObject.StartingItems.ContainsKey(ItemEnum.PBombLauncher)) { - characterVarsCode.AppendGMLInCode("global.PBombLauncher = 1"); + textToAppend.AppendLine("global.PBombLauncher = 1;"); } // Make all item activation dependent on whether the main item is enabled. - characterVarsCode.AppendGMLInCode(""" + textToAppend.AppendLine(""" global.morphball = global.hasMorph; global.jumpball = global.hasJumpball; global.powergrip = global.hasPowergrip; @@ -200,11 +202,13 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC global.sbeam = global.hasSbeam; global.cbeam = global.hasCbeam; - global.maxhealth = global.playerhealth - global.maxmissiles = global.missiles - global.maxsmissiles = global.smissiles + global.maxhealth = global.playerhealth; + global.maxmissiles = global.missiles; + global.maxsmissiles = global.smissiles; global.maxpbombs = global.pbombs; """); - characterVarsCode.AppendGMLInCode("global.currentsuit = 0; if (global.hasGravity) global.currentsuit = 2; else if (global.hasVaria) global.currentsuit = 1;"); + textToAppend.AppendLine("global.currentsuit = 0; if (global.hasGravity) global.currentsuit = 2; else if (global.hasVaria) global.currentsuit = 1;"); + + characterVarsCode.AppendGMLInCode(textToAppend.ToString()); } } diff --git a/YAMS-LIB/patches/misc/DontRespawnBombBlocks.cs b/YAMS-LIB/patches/misc/DontRespawnBombBlocks.cs index 45ffff1..b01e0ce 100644 --- a/YAMS-LIB/patches/misc/DontRespawnBombBlocks.cs +++ b/YAMS-LIB/patches/misc/DontRespawnBombBlocks.cs @@ -19,7 +19,7 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC // The bomb block puzzle in te room before varia don't need to have their special handling from am2random var rm_a2a06 = gmData.Rooms.ByName("rm_a2a06"); rm_a2a06.GameObjects.First(go => go.X == 608 && go.Y == 112 && go.ObjectDefinition.Name.Content == "oBlockBomb").CreationCode.ReplaceGMLInCode( - "if (oControl.mod_randomgamebool == 1 && global.hasBombs == 0 && (!global.hasJumpball) && global.hasGravity == 0)", + "if (oControl.mod_randomgamebool == 1 && global.hasBombs == 0 && !global.hasJumpball && global.hasGravity == 0)", "if (false)"); rm_a2a06.GameObjects.First(go => go.X == 624 && go.Y == 48 && go.ObjectDefinition.Name.Content == "oBlockBomb").CreationCode.ReplaceGMLInCode( "if (oControl.mod_randomgamebool == 1 && global.hasBombs == 0 && global.hasGravity == 0)", diff --git a/YAMS-LIB/patches/qol/ShowFullyUnexploredMap.cs b/YAMS-LIB/patches/qol/ShowFullyUnexploredMap.cs index c7f44b5..bfb2160 100644 --- a/YAMS-LIB/patches/qol/ShowFullyUnexploredMap.cs +++ b/YAMS-LIB/patches/qol/ShowFullyUnexploredMap.cs @@ -40,12 +40,12 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC // Don't ever draw the debug pipe tiles gmData.Code.ByName("gml_Script_draw_mapblock").ReplaceGMLInCode($$""" - if (argument7 == "H"{{(isHorde ? " || argument8 == \"H\"" : "")}}) - draw_sprite(sMapSP, 12, argument0, argument1) - if (argument7 == "V") - draw_sprite(sMapSP, 13, argument0, argument1) - if (argument7 == "C") - draw_sprite(sMapSP, 14, argument0, argument1) + if (argument7 == "H"{{(isHorde ? " || argument8 == \"H\"" : "")}}) + draw_sprite(sMapSP, 12, argument0, argument1) + if (argument7 == "V") + draw_sprite(sMapSP, 13, argument0, argument1) + if (argument7 == "C") + draw_sprite(sMapSP, 14, argument0, argument1) """, ""); // Also show item pickups and metroids diff --git a/diff.txt b/diff.txt new file mode 100644 index 0000000..1a17044 --- /dev/null +++ b/diff.txt @@ -0,0 +1,40 @@ +diff --git a/UndertaleModLib/Compiler/Compiler.cs b/UndertaleModLib/Compiler/Compiler.cs +index 3fa2ae6b..72e3d7c9 100644 +--- a/UndertaleModLib/Compiler/Compiler.cs ++++ b/UndertaleModLib/Compiler/Compiler.cs +@@ -142,8 +142,11 @@ namespace UndertaleModLib.Compiler + for (int i = 0; i < list.Count; i++) + { + string name = list[i].Name?.Content; +- if (name != null) +- assetIds[name] = i; ++ if (name is not null) ++ { ++ assetIds.Add(name, i); ++ } ++ //assetIds[name] = i; + } + } + } +@@ -154,6 +157,8 @@ namespace UndertaleModLib.Compiler + public delegate void MainThreadFunc(); + public delegate void MainThreadDelegate(MainThreadFunc f); + ++ private static Dictionary codeToContextMapping = new Dictionary(); ++ + // A simple matching convenience + public static bool In(this T obj, params T[] args) + { +@@ -169,7 +174,11 @@ namespace UndertaleModLib.Compiler + + public static CompileContext CompileGMLText(string input, UndertaleData data, UndertaleCode code) + { +- return CompileGMLText(input, new CompileContext(data, code)); ++ bool isInMapping = codeToContextMapping.TryGetValue(data, out CompileContext ctx); ++ var returnedContext = CompileGMLText(input, ctx ?? new CompileContext(data, code)); ++ if (!isInMapping) ++ codeToContextMapping.Add(data, returnedContext); ++ return returnedContext; + } + + public static CompileContext CompileGMLText(string input, CompileContext context, bool redoAssets = false)