diff --git a/UndertaleModCli/Program.UMTLibInherited.cs b/UndertaleModCli/Program.UMTLibInherited.cs index 24c407bb1..8da953b49 100644 --- a/UndertaleModCli/Program.UMTLibInherited.cs +++ b/UndertaleModCli/Program.UMTLibInherited.cs @@ -449,7 +449,7 @@ public string GetDisassemblyText(UndertaleCode code) try { - return code != null ? code.Disassemble(Data.Variables, Data.CodeLocals.For(code)) : ""; + return code != null ? code.Disassemble(Data.Variables, Data.CodeLocals?.For(code)) : ""; } catch (Exception e) { @@ -752,7 +752,7 @@ void ImportCode(string codeName, string gmlCode, bool isGML = true, bool doParse else if (code.ParentEntry is not null) return; - if (Data?.GeneralInfo.BytecodeVersion > 14 && Data.CodeLocals.ByName(codeName) == null) + if (Data.CodeLocals is not null && Data.CodeLocals.ByName(codeName) is null) { UndertaleCodeLocals locals = new UndertaleCodeLocals(); locals.Name = code.Name; diff --git a/UndertaleModCli/Program.cs b/UndertaleModCli/Program.cs index b7a59b1c1..8a4f28e24 100644 --- a/UndertaleModCli/Program.cs +++ b/UndertaleModCli/Program.cs @@ -584,7 +584,8 @@ private void CliQuickInfo() if (!Data.IsYYC()) { Console.WriteLine($"{Data.Code.Count} Code Entries, {Data.Variables.Count} Variables, {Data.Functions.Count} Functions"); - Console.WriteLine($"{Data.CodeLocals.Count} Code locals, {Data.Strings.Count} Strings, {Data.EmbeddedTextures.Count} Embedded Textures"); + var codeLocalsInfo = Data.CodeLocals is not null ? $"{Data.CodeLocals.Count} Code locals, " : ""; + Console.WriteLine($"{codeLocalsInfo}{Data.Strings.Count} Strings, {Data.EmbeddedTextures.Count} Embedded Textures"); } else { diff --git a/UndertaleModLib/Compiler/AssemblyWriter.cs b/UndertaleModLib/Compiler/AssemblyWriter.cs index 9667c9738..7d5ffad8d 100644 --- a/UndertaleModLib/Compiler/AssemblyWriter.cs +++ b/UndertaleModLib/Compiler/AssemblyWriter.cs @@ -107,7 +107,7 @@ public List Finish() bool defineArguments = true; if (compileContext.OriginalCode != null) { - UndertaleCodeLocals locals = compileContext.Data?.CodeLocals.For(compileContext.OriginalCode); + UndertaleCodeLocals locals = compileContext.Data?.CodeLocals?.For(compileContext.OriginalCode); if (locals != null) { // Update the code locals of the UndertaleCode diff --git a/UndertaleModLib/Decompiler/Assembler.cs b/UndertaleModLib/Decompiler/Assembler.cs index 2d811dfb3..5f38a3ed0 100644 --- a/UndertaleModLib/Decompiler/Assembler.cs +++ b/UndertaleModLib/Decompiler/Assembler.cs @@ -526,7 +526,7 @@ private static UndertaleInstruction.Reference ParseVariableRe // Locate variable from either local variables, or VARI chunk UndertaleVariable locatedVariable; string variableName = str[strPosition..].ToString(); - if (variInstanceType == UndertaleInstruction.InstanceType.Local) + if (variInstanceType == UndertaleInstruction.InstanceType.Local && data?.CodeLocals is not null) { locatedVariable = localvars.ContainsKey(variableName) ? localvars[variableName] : null; } diff --git a/UndertaleModLib/Models/UndertaleGameObject.cs b/UndertaleModLib/Models/UndertaleGameObject.cs index 8e21f3ed1..756a186e9 100644 --- a/UndertaleModLib/Models/UndertaleGameObject.cs +++ b/UndertaleModLib/Models/UndertaleGameObject.cs @@ -302,16 +302,19 @@ public UndertaleCode EventHandlerFor(EventType type, uint subtype, UndertaleData action.CodeId = code; data.Code.Add(code); - UndertaleCodeLocals.LocalVar argsLocal = new UndertaleCodeLocals.LocalVar(); - argsLocal.Name = data.Strings.MakeString("arguments"); - argsLocal.Index = 0; - - var locals = new UndertaleCodeLocals() + if (data.CodeLocals is not null) { - Name = name - }; - locals.Locals.Add(argsLocal); - data.CodeLocals.Add(locals); + UndertaleCodeLocals.LocalVar argsLocal = new UndertaleCodeLocals.LocalVar(); + argsLocal.Name = data.Strings.MakeString("arguments"); + argsLocal.Index = 0; + + var locals = new UndertaleCodeLocals() + { + Name = name + }; + locals.Locals.Add(argsLocal); + data.CodeLocals.Add(locals); + } } return code; } diff --git a/UndertaleModLib/UndertaleChunks.cs b/UndertaleModLib/UndertaleChunks.cs index c80846906..cfb99813c 100644 --- a/UndertaleModLib/UndertaleChunks.cs +++ b/UndertaleModLib/UndertaleChunks.cs @@ -1367,9 +1367,58 @@ public class UndertaleChunkFUNC : UndertaleChunk public UndertaleSimpleList Functions = new UndertaleSimpleList(); public UndertaleSimpleList CodeLocals = new UndertaleSimpleList(); + private static bool checkedFor2024_8; + + private void CheckFor2024_8(UndertaleReader reader) + { + if (reader.undertaleData.IsVersionAtLeast(2024, 8) + || reader.Bytecode14OrLower || Length == 0) // Irrelevant or non-deductible + { + checkedFor2024_8 = true; + return; + } + + long returnPos = reader.Position; + + // The CodeLocals list was removed in 2024.8, so we check if Functions + // is the only thing in here. + uint funcCount = reader.ReadUInt32(); + // Skip over the (Simple)List + // (3*4 is the size of an UndertaleFunction object) + reader.Position += 3 * 4 * funcCount; + if (reader.Position == returnPos + Length) + { + // Whatever, let's consider this a win + reader.undertaleData.SetGMS2Version(2024, 8); + reader.Position = returnPos; + checkedFor2024_8 = true; + return; + } + + // Then align the position + int specAlign = reader.undertaleData.PaddingAlignException; + while ((reader.AbsPosition & ((specAlign == -1 ? 16 : specAlign) - 1)) != 0) + { + if (reader.ReadByte() != 0) + { + // If we hit a non-zero byte, it can't be padding + reader.Position = returnPos; + checkedFor2024_8 = true; + return; + } + } + + // Then check if we're at the end of the chunk + if (reader.Position == returnPos + Length) + reader.undertaleData.SetGMS2Version(2024, 8); + + reader.Position = returnPos; + checkedFor2024_8 = true; + } + internal override void SerializeChunk(UndertaleWriter writer) { - if (Functions == null && CodeLocals == null) + if (Functions is null && CodeLocals is null) return; UndertaleInstruction.Reference.SerializeReferenceChain(writer, writer.undertaleData.Code, Functions); @@ -1382,12 +1431,16 @@ internal override void SerializeChunk(UndertaleWriter writer) else { writer.WriteUndertaleObject(Functions); - writer.WriteUndertaleObject(CodeLocals); + if (!writer.undertaleData.IsVersionAtLeast(2024, 8)) + writer.WriteUndertaleObject(CodeLocals); } } internal override void UnserializeChunk(UndertaleReader reader) { + if (!checkedFor2024_8) + CheckFor2024_8(reader); + if (Length == 0 && reader.undertaleData.GeneralInfo?.BytecodeVersion > 14) // YYC, 14 < bytecode <= 16, chunk is empty but exists { Functions = null; @@ -1404,16 +1457,23 @@ internal override void UnserializeChunk(UndertaleReader reader) Functions.SetCapacity(Length / 12); while (reader.Position + 12 <= startPosition + Length) Functions.Add(reader.ReadUndertaleObject()); + CodeLocals = null; } else { Functions = reader.ReadUndertaleObject>(); - CodeLocals = reader.ReadUndertaleObject>(); + if (!reader.undertaleData.IsVersionAtLeast(2024, 8)) + CodeLocals = reader.ReadUndertaleObject>(); + else + CodeLocals = null; } } internal override uint UnserializeObjectCount(UndertaleReader reader) { + checkedFor2024_8 = false; + CheckFor2024_8(reader); + if (Length == 0 && reader.undertaleData.GeneralInfo?.BytecodeVersion > 14) return 0; @@ -1422,7 +1482,8 @@ internal override uint UnserializeObjectCount(UndertaleReader reader) if (!reader.Bytecode14OrLower) { count += 1 + UndertaleSimpleList.UnserializeChildObjectCount(reader); - count += 1 + UndertaleSimpleList.UnserializeChildObjectCount(reader); + if (!reader.undertaleData.IsVersionAtLeast(2024, 8)) + count += 1 + UndertaleSimpleList.UnserializeChildObjectCount(reader); } else count = Length / 12; @@ -2173,7 +2234,8 @@ private void CheckPsemVersion(UndertaleReader reader) // Fortunately, consistent padding means we need no parsing here if (Length == 0xF8) { - reader.undertaleData.SetGMS2Version(2023, 8); + if (!reader.undertaleData.IsVersionAtLeast(2023, 8)) + reader.undertaleData.SetGMS2Version(2023, 8); } else if (Length == 0xD8) { @@ -2203,7 +2265,8 @@ private void CheckPsemVersion(UndertaleReader reader) uint secondPtr = reader.ReadUInt32(); if (secondPtr - firstPtr == 0xEC) { - reader.undertaleData.SetGMS2Version(2023, 8); + if (!reader.undertaleData.IsVersionAtLeast(2023, 8)) + reader.undertaleData.SetGMS2Version(2023, 8); } else if (secondPtr - firstPtr == 0xC0) { diff --git a/UndertaleModLib/UndertaleDataExtensionMethods.cs b/UndertaleModLib/UndertaleDataExtensionMethods.cs index 0e0bb9a1e..7667d7add 100644 --- a/UndertaleModLib/UndertaleDataExtensionMethods.cs +++ b/UndertaleModLib/UndertaleDataExtensionMethods.cs @@ -174,10 +174,12 @@ public static UndertaleVariable EnsureDefined(this IList list public static UndertaleVariable DefineLocal(this IList list, IList originalReferencedLocalVars, int localId, string name, IList strg, UndertaleData data) { - bool bytecode14 = (data?.GeneralInfo?.BytecodeVersion <= 14); - if (bytecode14) + bool bytecode14 = data?.GeneralInfo?.BytecodeVersion <= 14; + if (bytecode14 || data?.CodeLocals is null) { - UndertaleVariable search = list.Where((x) => x.Name.Content == name).FirstOrDefault(); + UndertaleVariable search = list.Where((x) => + x.Name.Content == name && (bytecode14 || x.InstanceType == UndertaleInstruction.InstanceType.Local) + ).FirstOrDefault(); if (search != null) return search; } diff --git a/UndertaleModTests/GameLoadingTests.cs b/UndertaleModTests/GameLoadingTests.cs index 766c7d072..9c4a159f2 100644 --- a/UndertaleModTests/GameLoadingTests.cs +++ b/UndertaleModTests/GameLoadingTests.cs @@ -75,7 +75,7 @@ public void DisassembleAndReassembleAllScripts() string disasm; try { - disasm = code.Disassemble(data.Variables, data.CodeLocals.For(code)); + disasm = code.Disassemble(data.Variables, data.CodeLocals?.For(code)); } catch (Exception e) { diff --git a/UndertaleModTool/Editors/UndertaleCodeEditor.xaml.cs b/UndertaleModTool/Editors/UndertaleCodeEditor.xaml.cs index 6fb6d52ea..379084f13 100644 --- a/UndertaleModTool/Editors/UndertaleCodeEditor.xaml.cs +++ b/UndertaleModTool/Editors/UndertaleCodeEditor.xaml.cs @@ -528,7 +528,7 @@ private void DisassembleCode(UndertaleCode code, bool first) try { var data = mainWindow.Data; - text = code.Disassemble(data.Variables, data.CodeLocals.For(code)); + text = code.Disassemble(data.Variables, data.CodeLocals?.For(code)); CurrentLocals.Clear(); } @@ -841,7 +841,7 @@ private void PopulateCurrentLocals(UndertaleData data, UndertaleCode code) CurrentLocals.Clear(); // Look up locals for given code entry's name, for syntax highlighting - var locals = data.CodeLocals.ByName(code.Name.Content); + var locals = data.CodeLocals?.ByName(code.Name.Content); if (locals != null) { foreach (var local in locals.Locals) diff --git a/UndertaleModTool/ImportCodeSystem.cs b/UndertaleModTool/ImportCodeSystem.cs index 7e8a55a8b..d7965c38d 100644 --- a/UndertaleModTool/ImportCodeSystem.cs +++ b/UndertaleModTool/ImportCodeSystem.cs @@ -225,7 +225,7 @@ void ImportCode(string codeName, string gmlCode, bool IsGML = true, bool doParse else if (code.ParentEntry is not null) return; - if (Data?.GeneralInfo.BytecodeVersion > 14 && Data.CodeLocals.ByName(codeName) == null) + if (Data.CodeLocals is not null && Data.CodeLocals.ByName(codeName) is null) { UndertaleCodeLocals locals = new UndertaleCodeLocals(); locals.Name = code.Name; diff --git a/UndertaleModTool/MainWindow.xaml.cs b/UndertaleModTool/MainWindow.xaml.cs index e1ae95a99..2e96bde16 100644 --- a/UndertaleModTool/MainWindow.xaml.cs +++ b/UndertaleModTool/MainWindow.xaml.cs @@ -1163,12 +1163,16 @@ private async Task SaveFile(string filename, bool suppressDebug = false) { debugData.SourceCode.Add(new UndertaleScriptSource() { SourceCode = debugData.Strings.MakeString(outputs[i]) }); debugData.DebugInfo.Add(outputsOffsets[i]); - debugData.LocalVars.Add(Data.CodeLocals[i]); - if (debugData.Strings.IndexOf(Data.CodeLocals[i].Name) < 0) - debugData.Strings.Add(Data.CodeLocals[i].Name); - foreach (var local in Data.CodeLocals[i].Locals) - if (debugData.Strings.IndexOf(local.Name) < 0) - debugData.Strings.Add(local.Name); + // FIXME: Probably should write something regardless. + if (Data.CodeLocals is not null) + { + debugData.LocalVars.Add(Data.CodeLocals[i]); + if (debugData.Strings.IndexOf(Data.CodeLocals[i].Name) < 0) + debugData.Strings.Add(Data.CodeLocals[i].Name); + foreach (var local in Data.CodeLocals[i].Locals) + if (debugData.Strings.IndexOf(local.Name) < 0) + debugData.Strings.Add(local.Name); + } } using (UndertaleWriter writer = new UndertaleWriter(new FileStream(Path.ChangeExtension(FilePath, ".yydebug"), FileMode.Create, FileAccess.Write))) @@ -2087,7 +2091,7 @@ private void MenuItem_Add_Click(object sender, RoutedEventArgs e) string prefix = Data.IsVersionAtLeast(2, 3) ? "gml_GlobalScript_" : "gml_Script_"; code.Name = Data.Strings.MakeString(prefix + newName); Data.Code.Add(code); - if (Data?.GeneralInfo.BytecodeVersion > 14) + if (Data.CodeLocals is not null) { UndertaleCodeLocals locals = new UndertaleCodeLocals(); locals.Name = code.Name; @@ -2100,7 +2104,7 @@ private void MenuItem_Add_Click(object sender, RoutedEventArgs e) } (obj as UndertaleScript).Code = code; } - if ((obj is UndertaleCode) && (Data.GeneralInfo.BytecodeVersion > 14)) + if (obj is UndertaleCode && Data.CodeLocals is not null) { UndertaleCodeLocals locals = new UndertaleCodeLocals(); locals.Name = (obj as UndertaleCode).Name; diff --git a/UndertaleModTool/ProfileSystem.cs b/UndertaleModTool/ProfileSystem.cs index 60cdd261e..3bc7cca1c 100644 --- a/UndertaleModTool/ProfileSystem.cs +++ b/UndertaleModTool/ProfileSystem.cs @@ -47,7 +47,7 @@ public string GetDisassemblyText(UndertaleCode code) try { - return code != null ? code.Disassemble(Data.Variables, Data.CodeLocals.For(code)) : ""; + return code != null ? code.Disassemble(Data.Variables, Data.CodeLocals?.For(code)) : ""; } catch (Exception e) { diff --git a/UndertaleModTool/Scripts/Builtin Scripts/HeCanBeEverywhere.csx b/UndertaleModTool/Scripts/Builtin Scripts/HeCanBeEverywhere.csx index 35d3ed454..678e5e6d7 100644 --- a/UndertaleModTool/Scripts/Builtin Scripts/HeCanBeEverywhere.csx +++ b/UndertaleModTool/Scripts/Builtin Scripts/HeCanBeEverywhere.csx @@ -260,7 +260,7 @@ for (int i = 0; i < obj_shop1_Draw.Instructions.Count; i++) } } obj_shop1_Draw.UpdateAddresses(); -obj_shop1_Draw.Replace(Assembler.Assemble(obj_shop1_Draw.Disassemble(Data.Variables, Data.CodeLocals.For(obj_shop1_Draw)), Data)); // TODO: no idea why this is needed +obj_shop1_Draw.Replace(Assembler.Assemble(obj_shop1_Draw.Disassemble(Data.Variables, Data.CodeLocals?.For(obj_shop1_Draw)), Data)); // TODO: no idea why this is needed Data.GameObjects.ByName("obj_time").EventHandlerFor(EventType.KeyPress, EventSubtypeKey.vk_f6, Data).ReplaceGML(@" if (global.debug == 1) diff --git a/UndertaleModTool/Scripts/Builtin Scripts/SearchASM.csx b/UndertaleModTool/Scripts/Builtin Scripts/SearchASM.csx index dbe9c21c8..ced1a839a 100644 --- a/UndertaleModTool/Scripts/Builtin Scripts/SearchASM.csx +++ b/UndertaleModTool/Scripts/Builtin Scripts/SearchASM.csx @@ -81,7 +81,7 @@ void DumpCode(UndertaleCode code) try { var lineNumber = 1; - StringReader assemblyText = new(code != null ? code.Disassemble(Data.Variables, Data.CodeLocals.For(code)) : ""); + StringReader assemblyText = new(code != null ? code.Disassemble(Data.Variables, Data.CodeLocals?.For(code)) : ""); bool nameWritten = false; string lineInt; while ((lineInt = assemblyText.ReadLine()) is not null) diff --git a/UndertaleModTool/Scripts/Resource Repackers/GameObjectCopy.csx b/UndertaleModTool/Scripts/Resource Repackers/GameObjectCopy.csx index 58f1090a5..035a08c0a 100644 --- a/UndertaleModTool/Scripts/Resource Repackers/GameObjectCopy.csx +++ b/UndertaleModTool/Scripts/Resource Repackers/GameObjectCopy.csx @@ -161,7 +161,7 @@ for (var j = 0; j < splitStringsList.Count; j++) nativeACT.CodeId.ArgumentsCount = donorACT.CodeId.ArgumentsCount; nativeACT.CodeId.Offset = donorACT.CodeId.Offset; nativeACT.CodeId.WeirdLocalFlag = donorACT.CodeId.WeirdLocalFlag; - if (Data?.GeneralInfo.BytecodeVersion > 14) + if (Data.CodeLocals is not null) { UndertaleCodeLocals nativelocals = Data.CodeLocals.ByName(donorACT.CodeId?.Name?.Content); UndertaleCodeLocals donorlocals = DonorData.CodeLocals.ByName(donorACT.CodeId?.Name?.Content); diff --git a/UndertaleModTool/Scripts/Resource Repackers/GameObjectCopyInternal.csx b/UndertaleModTool/Scripts/Resource Repackers/GameObjectCopyInternal.csx index 8e7519509..c2fcfee1e 100644 --- a/UndertaleModTool/Scripts/Resource Repackers/GameObjectCopyInternal.csx +++ b/UndertaleModTool/Scripts/Resource Repackers/GameObjectCopyInternal.csx @@ -114,7 +114,7 @@ for (var j = 0; j < splitStringsList.Count; j++) nativeACT.CodeId.ArgumentsCount = donorACT.CodeId.ArgumentsCount; nativeACT.CodeId.Offset = donorACT.CodeId.Offset; nativeACT.CodeId.WeirdLocalFlag = donorACT.CodeId.WeirdLocalFlag; - if (Data?.GeneralInfo.BytecodeVersion > 14) + if (Data.CodeLocals is not null) { UndertaleCodeLocals donorlocals = Data.CodeLocals.ByName(donorACT.CodeId?.Name?.Content); UndertaleCodeLocals nativelocals = new UndertaleCodeLocals(); diff --git a/UndertaleModTool/Scripts/Resource Repackers/ImportASM_2_3.csx b/UndertaleModTool/Scripts/Resource Repackers/ImportASM_2_3.csx index 1a78c246c..0429b8490 100644 --- a/UndertaleModTool/Scripts/Resource Repackers/ImportASM_2_3.csx +++ b/UndertaleModTool/Scripts/Resource Repackers/ImportASM_2_3.csx @@ -117,7 +117,7 @@ await Task.Run(() => { code.Name = Data.Strings.MakeString(codeName); Data.Code.Add(code); } - if ((Data?.GeneralInfo.BytecodeVersion > 14) && (Data.CodeLocals.ByName(codeName) == null)) + if (Data.CodeLocals is not null && Data.CodeLocals.ByName(codeName) is null) { UndertaleCodeLocals locals = new UndertaleCodeLocals(); locals.Name = code.Name; diff --git a/UndertaleModTool/Scripts/Resource Repackers/ImportGML_2_3.csx b/UndertaleModTool/Scripts/Resource Repackers/ImportGML_2_3.csx index cdb4a1761..a7a2ba660 100644 --- a/UndertaleModTool/Scripts/Resource Repackers/ImportGML_2_3.csx +++ b/UndertaleModTool/Scripts/Resource Repackers/ImportGML_2_3.csx @@ -118,7 +118,7 @@ await Task.Run(() => { code.Name = Data.Strings.MakeString(codeName); Data.Code.Add(code); } - if ((Data?.GeneralInfo.BytecodeVersion > 14) && (Data.CodeLocals.ByName(codeName) == null)) + if (Data.CodeLocals is not null && Data.CodeLocals.ByName(codeName) is null) { UndertaleCodeLocals locals = new UndertaleCodeLocals(); locals.Name = code.Name; diff --git a/UndertaleModTool/Scripts/Resource Unpackers/ExportASM.csx b/UndertaleModTool/Scripts/Resource Unpackers/ExportASM.csx index dc07e2b88..d25e605bb 100644 --- a/UndertaleModTool/Scripts/Resource Unpackers/ExportASM.csx +++ b/UndertaleModTool/Scripts/Resource Unpackers/ExportASM.csx @@ -39,7 +39,7 @@ void DumpCode(UndertaleCode code) string path = Path.Combine(codeFolder, code.Name.Content + ".asm"); try { - File.WriteAllText(path, (code != null ? code.Disassemble(Data.Variables, Data.CodeLocals.For(code)) : "")); + File.WriteAllText(path, (code != null ? code.Disassemble(Data.Variables, Data.CodeLocals?.For(code)) : "")); } catch (Exception e) { diff --git a/UndertaleModTool/Scripts/Technical Scripts/ConvertFrom17to16_for_2.3.csx b/UndertaleModTool/Scripts/Technical Scripts/ConvertFrom17to16_for_2.3.csx index 792917279..42420b99f 100644 --- a/UndertaleModTool/Scripts/Technical Scripts/ConvertFrom17to16_for_2.3.csx +++ b/UndertaleModTool/Scripts/Technical Scripts/ConvertFrom17to16_for_2.3.csx @@ -77,6 +77,8 @@ applying any changes to the game."; Data.FORM.Chunks.Remove("TAGS"); if (Data.FORM.Chunks.ContainsKey("EMBI")) Data.FORM.Chunks.Remove("EMBI"); + if (Data.FORM.FUNC.CodeLocals is null) + Data.FORM.FUNC.CodeLocals = new UndertaleSimpleList(); Data.SetGMS2Version(2); //Data.IsTPAG4ByteAligned = false; for (int i = 0; i < Data.Code.Count; i++) diff --git a/UndertaleModTool/Scripts/Technical Scripts/ExportAndConvert_2_3_ASM.csx b/UndertaleModTool/Scripts/Technical Scripts/ExportAndConvert_2_3_ASM.csx index 16078c9dd..0009b0503 100644 --- a/UndertaleModTool/Scripts/Technical Scripts/ExportAndConvert_2_3_ASM.csx +++ b/UndertaleModTool/Scripts/Technical Scripts/ExportAndConvert_2_3_ASM.csx @@ -52,7 +52,7 @@ void DumpCode() foreach (UndertaleCode code_orig in Data.Code) { code_orig.Offset = 0; - if (Data.CodeLocals.ByName(code_orig.Name.Content) == null) + if (Data.CodeLocals is not null && Data.CodeLocals.ByName(code_orig.Name.Content) == null) { UndertaleCodeLocals locals = new UndertaleCodeLocals(); locals.Name = code_orig.Name; @@ -90,7 +90,7 @@ void DumpCode() string x = ""; try { - string disasm_code = code_orig.Disassemble(Data.Variables, Data.CodeLocals.For(code_orig)); + string disasm_code = code_orig.Disassemble(Data.Variables, Data.CodeLocals?.For(code_orig)); //ScriptMessage(code_orig.Name.Content); //ScriptMessage("1 " + disasm_code); int ix = -1; @@ -120,7 +120,7 @@ void DumpCode() string str_path_to_use = Path.Combine(codeFolder, code_orig.Name.Content + ".asm"); string code_output = ""; if (code_orig != null) - code_output = code_orig.Disassemble(Data.Variables, Data.CodeLocals.For(code_orig)); + code_output = code_orig.Disassemble(Data.Variables, Data.CodeLocals?.For(code_orig)); File.WriteAllText(str_path_to_use, code_output); } catch (Exception e) @@ -144,7 +144,7 @@ void DumpCode() string str_path_to_use = Path.Combine(codeFolder, "Duplicates", code_orig.Name.Content + ".asm"); string code_output = ""; if (code_orig != null) - code_output = code_orig.Disassemble(Data.Variables, Data.CodeLocals.For(code_orig)); + code_output = code_orig.Disassemble(Data.Variables, Data.CodeLocals?.For(code_orig)); File.WriteAllText(str_path_to_use, code_output); } catch (Exception e) diff --git a/UndertaleModTool/Scripts/Technical Scripts/RestoreMissingCodeLocals.csx b/UndertaleModTool/Scripts/Technical Scripts/RestoreMissingCodeLocals.csx index 1dbb5e1bf..1f00a6672 100644 --- a/UndertaleModTool/Scripts/Technical Scripts/RestoreMissingCodeLocals.csx +++ b/UndertaleModTool/Scripts/Technical Scripts/RestoreMissingCodeLocals.csx @@ -1,6 +1,7 @@ -if (Data?.GeneralInfo.BytecodeVersion < 15) +EnsureDataLoaded(); +if (Data.CodeLocals is null) { - ScriptMessage("Cannot run on this game, bytecode >= 15 required!"); + ScriptMessage("Cannot run on this game, bytecode >= 15 and GM <= 2024.8 required!"); return; } int newCount = 0; diff --git a/UndertaleModTool/Scripts/Technical Scripts/TestExportAllCode.csx b/UndertaleModTool/Scripts/Technical Scripts/TestExportAllCode.csx index ed70e8522..a4e5dbd0f 100644 --- a/UndertaleModTool/Scripts/Technical Scripts/TestExportAllCode.csx +++ b/UndertaleModTool/Scripts/Technical Scripts/TestExportAllCode.csx @@ -170,7 +170,7 @@ if (File.Exists(path_error2)) string asmPath = Path.Combine(asmFolder, code.Name.Content + ".asm"); try { - File.WriteAllText(asmPath, (code != null ? code.Disassemble(Data.Variables, Data.CodeLocals.For(code)) : "")); + File.WriteAllText(asmPath, (code != null ? code.Disassemble(Data.Variables, Data.CodeLocals?.For(code)) : "")); } catch (Exception e) { diff --git a/UndertaleModTool/Windows/FindReferencesTypesDialog/UndertaleResourceReferenceMap.cs b/UndertaleModTool/Windows/FindReferencesTypesDialog/UndertaleResourceReferenceMap.cs index 2c4d15249..0c10fa851 100644 --- a/UndertaleModTool/Windows/FindReferencesTypesDialog/UndertaleResourceReferenceMap.cs +++ b/UndertaleModTool/Windows/FindReferencesTypesDialog/UndertaleResourceReferenceMap.cs @@ -10,6 +10,7 @@ namespace UndertaleModTool.Windows public class TypesForVersion { public (uint Major, uint Minor, uint Release) Version { get; set; } + public (uint Major, uint Minor, uint Release) BeforeVersion { get; set; } = (uint.MaxValue, uint.MaxValue, uint.MaxValue); public (Type, string)[] Types { get; set; } } @@ -173,6 +174,7 @@ public static class UndertaleResourceReferenceMap { // Bytecode version 15 Version = (15, uint.MaxValue, uint.MaxValue), + BeforeVersion = (2024, 8, 0), Types = new[] { (typeof(UndertaleCodeLocals), "Code locals") @@ -431,7 +433,13 @@ public static (Type, string)[] GetTypeMapForVersion(Type type, UndertaleData dat else isAtLeast = typeForVer.Version.CompareTo(version) <= 0; - if (isAtLeast) + bool isAboveMost = false; + if (typeForVer.BeforeVersion.Minor == uint.MaxValue) + isAboveMost = typeForVer.BeforeVersion.Major <= bytecodeVersion; + else + isAboveMost = typeForVer.BeforeVersion.CompareTo(version) <= 0; + + if (isAtLeast && !isAboveMost) outTypes = typeForVer.Types.UnionBy(outTypes, x => x.Item1); } diff --git a/UndertaleModTool/Windows/FindReferencesTypesDialog/UndertaleResourceReferenceMethodsMap.cs b/UndertaleModTool/Windows/FindReferencesTypesDialog/UndertaleResourceReferenceMethodsMap.cs index 8e1cc5158..18d976d19 100644 --- a/UndertaleModTool/Windows/FindReferencesTypesDialog/UndertaleResourceReferenceMethodsMap.cs +++ b/UndertaleModTool/Windows/FindReferencesTypesDialog/UndertaleResourceReferenceMethodsMap.cs @@ -32,6 +32,7 @@ public HashSetTypesOverride(bool containsEverything = false, bool isYYC = false) public class PredicateForVersion { public (uint Major, uint Minor, uint Release) Version { get; set; } + public (uint Major, uint Minor, uint Release) BeforeVersion { get; set; } = (uint.MaxValue, uint.MaxValue, uint.MaxValue); public Func> Predicate { get; set; } } @@ -616,6 +617,7 @@ IEnumerable GetExtnFunctions() { // Bytecode version 15 Version = (15, uint.MaxValue, uint.MaxValue), + BeforeVersion = (2024, 8, 0), Predicate = (objSrc, types, checkOne) => { if (!types.Contains(typeof(UndertaleCodeLocals))) @@ -1421,7 +1423,13 @@ public static Dictionary> GetReferencesOfObject(object obj, else isAtLeast = predicateForVer.Version.CompareTo(ver) <= 0; - if (isAtLeast) + bool isAboveMost = false; + if (predicateForVer.BeforeVersion.Minor == uint.MaxValue) + isAboveMost = predicateForVer.BeforeVersion.Major <= data.GeneralInfo.BytecodeVersion; + else + isAboveMost = predicateForVer.BeforeVersion.CompareTo(ver) <= 0; + + if (isAtLeast && !isAboveMost) { var result = predicateForVer.Predicate(obj, types, checkOne); if (result is null)