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

UA: Add rough check for CodeLocals' removal from FUNC in 2024.8 #1937

Draft
wants to merge 11 commits into
base: underanalyzer
Choose a base branch
from
4 changes: 2 additions & 2 deletions UndertaleModCli/Program.UMTLibInherited.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion UndertaleModCli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,8 @@
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
{
Expand Down Expand Up @@ -731,7 +732,7 @@
/// Evaluates and executes given C# code.
/// </summary>
/// <param name="code">The C# string to execute</param>
/// <param name="scriptFile">The path to the script file where <see cref="code"/> was executed from.

Check warning on line 735 in UndertaleModCli/Program.cs

View workflow job for this annotation

GitHub Actions / publish_cli (ubuntu-latest, Debug, false)

XML comment has cref attribute 'code' that could not be resolved

Check warning on line 735 in UndertaleModCli/Program.cs

View workflow job for this annotation

GitHub Actions / publish_cli (ubuntu-latest, Debug, false)

XML comment has cref attribute 'code' that could not be resolved

Check warning on line 735 in UndertaleModCli/Program.cs

View workflow job for this annotation

GitHub Actions / publish_cli (macOS-latest, Debug, false)

XML comment has cref attribute 'code' that could not be resolved

Check warning on line 735 in UndertaleModCli/Program.cs

View workflow job for this annotation

GitHub Actions / publish_cli (macOS-latest, Debug, false)

XML comment has cref attribute 'code' that could not be resolved

Check warning on line 735 in UndertaleModCli/Program.cs

View workflow job for this annotation

GitHub Actions / publish_cli (windows-latest, Debug, false)

XML comment has cref attribute 'code' that could not be resolved

Check warning on line 735 in UndertaleModCli/Program.cs

View workflow job for this annotation

GitHub Actions / publish_cli (windows-latest, Debug, false)

XML comment has cref attribute 'code' that could not be resolved
/// Leave as null, if it wasn't executed from a script file</param>
private void RunCSharpCode(string code, string scriptFile = null)
{
Expand Down
2 changes: 1 addition & 1 deletion UndertaleModLib/Compiler/AssemblyWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public List<UndertaleInstruction> 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
Expand Down
2 changes: 1 addition & 1 deletion UndertaleModLib/Decompiler/Assembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ private static UndertaleInstruction.Reference<UndertaleVariable> 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;
}
Expand Down
21 changes: 12 additions & 9 deletions UndertaleModLib/Models/UndertaleGameObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
75 changes: 69 additions & 6 deletions UndertaleModLib/UndertaleChunks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1367,9 +1367,58 @@ public class UndertaleChunkFUNC : UndertaleChunk
public UndertaleSimpleList<UndertaleFunction> Functions = new UndertaleSimpleList<UndertaleFunction>();
public UndertaleSimpleList<UndertaleCodeLocals> CodeLocals = new UndertaleSimpleList<UndertaleCodeLocals>();

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<UndertaleFunction>.SerializeReferenceChain(writer, writer.undertaleData.Code, Functions);
Expand All @@ -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;
Expand All @@ -1404,16 +1457,23 @@ internal override void UnserializeChunk(UndertaleReader reader)
Functions.SetCapacity(Length / 12);
while (reader.Position + 12 <= startPosition + Length)
Functions.Add(reader.ReadUndertaleObject<UndertaleFunction>());
CodeLocals = null;
}
else
{
Functions = reader.ReadUndertaleObject<UndertaleSimpleList<UndertaleFunction>>();
CodeLocals = reader.ReadUndertaleObject<UndertaleSimpleList<UndertaleCodeLocals>>();
if (!reader.undertaleData.IsVersionAtLeast(2024, 8))
CodeLocals = reader.ReadUndertaleObject<UndertaleSimpleList<UndertaleCodeLocals>>();
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;

Expand All @@ -1422,7 +1482,8 @@ internal override uint UnserializeObjectCount(UndertaleReader reader)
if (!reader.Bytecode14OrLower)
{
count += 1 + UndertaleSimpleList<UndertaleFunction>.UnserializeChildObjectCount(reader);
count += 1 + UndertaleSimpleList<UndertaleCodeLocals>.UnserializeChildObjectCount(reader);
if (!reader.undertaleData.IsVersionAtLeast(2024, 8))
count += 1 + UndertaleSimpleList<UndertaleCodeLocals>.UnserializeChildObjectCount(reader);
}
else
count = Length / 12;
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down
8 changes: 5 additions & 3 deletions UndertaleModLib/UndertaleDataExtensionMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,12 @@ public static UndertaleVariable EnsureDefined(this IList<UndertaleVariable> list

public static UndertaleVariable DefineLocal(this IList<UndertaleVariable> list, IList<UndertaleVariable> originalReferencedLocalVars, int localId, string name, IList<UndertaleString> 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;
}
Expand Down
2 changes: 1 addition & 1 deletion UndertaleModTests/GameLoadingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
4 changes: 2 additions & 2 deletions UndertaleModTool/Editors/UndertaleCodeEditor.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion UndertaleModTool/ImportCodeSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
20 changes: 12 additions & 8 deletions UndertaleModTool/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1163,12 +1163,16 @@
{
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)))
Expand Down Expand Up @@ -2087,7 +2091,7 @@
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;
Expand All @@ -2100,7 +2104,7 @@
}
(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;
Expand Down Expand Up @@ -3069,7 +3073,7 @@
};
SetProgressBar();

using (WebClient webClient = new())

Check warning on line 3076 in UndertaleModTool/MainWindow.xaml.cs

View workflow job for this annotation

GitHub Actions / build_gui (windows-latest, Debug, false, false)

'WebClient.WebClient()' is obsolete: 'WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead.' (https://aka.ms/dotnet-warnings/SYSLIB0014)

Check warning on line 3076 in UndertaleModTool/MainWindow.xaml.cs

View workflow job for this annotation

GitHub Actions / build_gui (windows-latest, Debug, false, false)

'WebClient.WebClient()' is obsolete: 'WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead.' (https://aka.ms/dotnet-warnings/SYSLIB0014)

Check warning on line 3076 in UndertaleModTool/MainWindow.xaml.cs

View workflow job for this annotation

GitHub Actions / build_gui (windows-latest, Debug, false, true)

'WebClient.WebClient()' is obsolete: 'WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead.' (https://aka.ms/dotnet-warnings/SYSLIB0014)

Check warning on line 3076 in UndertaleModTool/MainWindow.xaml.cs

View workflow job for this annotation

GitHub Actions / build_gui (windows-latest, Debug, false, true)

'WebClient.WebClient()' is obsolete: 'WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead.' (https://aka.ms/dotnet-warnings/SYSLIB0014)
{
bool end = false;
bool ended = false;
Expand Down
2 changes: 1 addition & 1 deletion UndertaleModTool/ProfileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion UndertaleModTool/Scripts/Builtin Scripts/SearchASM.csx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion UndertaleModTool/Scripts/Resource Unpackers/ExportASM.csx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<UndertaleCodeLocals>();
Data.SetGMS2Version(2);
//Data.IsTPAG4ByteAligned = false;
for (int i = 0; i < Data.Code.Count; i++)
Expand Down
Loading
Loading