Skip to content

Commit

Permalink
Optimized code chunk unserialization.
Browse files Browse the repository at this point in the history
  • Loading branch information
VladiStep committed Feb 19, 2023
1 parent eb001ad commit 2c55f33
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 17 deletions.
14 changes: 14 additions & 0 deletions UndertaleModCli/Program.UMTLibInherited.cs
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,9 @@ public string GetDecompiledText(string codeName, GlobalDecompileContext context
/// <inheritdoc/>
public string GetDecompiledText(UndertaleCode code, GlobalDecompileContext context = null)
{
if (code.ParentEntry is not null)
return $"// This code entry is a reference to an anonymous function within \"{code.ParentEntry.Name.Content}\", decompile that instead.";

GlobalDecompileContext decompileContext = context is null ? new(Data, false) : context;
try
{
Expand All @@ -437,6 +440,9 @@ public string GetDisassemblyText(string codeName)
/// <inheritdoc/>
public string GetDisassemblyText(UndertaleCode code)
{
if (code.ParentEntry is not null)
return $"; This code entry is a reference to an anonymous function within \"{code.ParentEntry.Name.Content}\", disassemble that instead.";

try
{
return code != null ? code.Disassemble(Data.Variables, Data.CodeLocals.For(code)) : "";
Expand Down Expand Up @@ -639,6 +645,8 @@ public void ReplaceTextInGML(string codeName, string keyword, string replacement
public void ReplaceTextInGML(UndertaleCode code, string keyword, string replacement, bool caseSensitive = false, bool isRegex = false, GlobalDecompileContext context = null)
{
if (code == null) throw new ArgumentNullException(nameof(code));
if (code.ParentEntry is not null)
return;

EnsureDataLoaded();

Expand Down Expand Up @@ -748,6 +756,9 @@ void ImportCode(string codeName, string gmlCode, bool isGML = true, bool doParse
code.Name = Data.Strings.MakeString(codeName);
Data.Code.Add(code);
}
else if (code.ParentEntry is not null)
return;

if (Data?.GeneralInfo.BytecodeVersion > 14 && Data.CodeLocals.ByName(codeName) == null)
{
UndertaleCodeLocals locals = new UndertaleCodeLocals();
Expand Down Expand Up @@ -1155,6 +1166,9 @@ public string GetGUIDFromCodeName(string codeName)
void SafeImport(string codeName, string gmlCode, bool isGML, bool destroyASM = true, bool checkDecompiler = false, bool throwOnError = false)
{
UndertaleCode code = Data.Code.ByName(codeName);
if (code?.ParentEntry is not null)
return;

try
{
if (isGML)
Expand Down
54 changes: 47 additions & 7 deletions UndertaleModLib/Models/UndertaleCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,8 @@ public class UndertaleCode : UndertaleNamedResource, UndertaleObjectWithBlobs, I

public uint Length { get; set; }

public static int CurrCodeIndex { get; set; }


/// <summary>
/// The amount of local variables this code entry has. <br/>
Expand Down Expand Up @@ -1110,6 +1112,8 @@ public void Unserialize(UndertaleReader reader)
else if (reader.Bytecode14OrLower)
{
Instructions.Clear();
Instructions.Capacity = reader.InstructionArraysLengths[CurrCodeIndex];

uint here = reader.Position;
uint stop = here + Length;
while (reader.Position < stop)
Expand All @@ -1132,14 +1136,21 @@ public void Unserialize(UndertaleReader reader)
}
int BytecodeRelativeAddress = reader.ReadInt32();
_bytecodeAbsoluteAddress = (uint)((int)reader.Position - 4 + BytecodeRelativeAddress);
uint here = reader.Position;
reader.Position = _bytecodeAbsoluteAddress;

if (Length > 0 && reader.GMS2_3 && reader.GetOffsetMap().TryGetValue(_bytecodeAbsoluteAddress, out var i))
{
ParentEntry = (i as UndertaleInstruction).Entry;
ParentEntry.ChildEntries.Add(this);

Offset = reader.ReadUInt32();
return;
}

uint here = reader.Position;
reader.Position = _bytecodeAbsoluteAddress;

Instructions.Clear();
Instructions.Capacity = reader.InstructionArraysLengths[CurrCodeIndex];
while (reader.Position < _bytecodeAbsoluteAddress + Length)
{
uint a = (reader.Position - _bytecodeAbsoluteAddress) / 4;
Expand All @@ -1149,9 +1160,12 @@ public void Unserialize(UndertaleReader reader)
}
if (ParentEntry == null && Instructions.Count != 0)
Instructions[0].Entry = this;

reader.Position = here;
Offset = reader.ReadUInt32();
}

CurrCodeIndex++;
}

/// <inheritdoc cref="UndertaleObject.UnserializeChildObjectCount(UndertaleReader)"/>
Expand All @@ -1169,10 +1183,16 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader)

// Get instructions count
uint instrCount = 0;
uint instrSubCount = 0;
while (reader.Position < stop)
instrCount += 1 + UndertaleInstruction.UnserializeChildObjectCount(reader);
{
instrCount++;
instrSubCount += UndertaleInstruction.UnserializeChildObjectCount(reader);
}

count += instrCount;
reader.InstructionArraysLengths[CurrCodeIndex] = (int)instrCount;

count += instrCount + instrSubCount;
}
else
{
Expand All @@ -1192,17 +1212,25 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader)
uint here = reader.Position;
reader.Position = bytecodeAbsoluteAddress;

// Get instructions count
// Get instructions counts
uint instrCount = 0;
uint instrSubCount = 0;
while (reader.Position < bytecodeAbsoluteAddress + length)
instrCount += 1 + UndertaleInstruction.UnserializeChildObjectCount(reader);
{
instrCount++;
instrSubCount += UndertaleInstruction.UnserializeChildObjectCount(reader);
}

reader.InstructionArraysLengths[CurrCodeIndex] = (int)instrCount;

reader.Position = here;
reader.Position += 4; // "Offset"

count += instrCount;
count += instrCount + instrSubCount;
}

CurrCodeIndex++;

return count;
}

Expand Down Expand Up @@ -1266,6 +1294,9 @@ public IList<UndertaleVariable> FindReferencedLocalVars()
/// <param name="instructions">The instructions to append.</param>
public void Append(IList<UndertaleInstruction> instructions)
{
if (ParentEntry is not null)
return;

Instructions.AddRange(instructions);
UpdateAddresses();
}
Expand All @@ -1276,6 +1307,9 @@ public void Append(IList<UndertaleInstruction> instructions)
/// <param name="instructions">The new instructions for this code entry.</param>
public void Replace(IList<UndertaleInstruction> instructions)
{
if (ParentEntry is not null)
return;

Instructions.Clear();
Append(instructions);
}
Expand All @@ -1288,6 +1322,9 @@ public void Replace(IList<UndertaleInstruction> instructions)
/// <exception cref="Exception"> if the GML code does not compile or if there's an error writing the code to the profile entry.</exception>
public void AppendGML(string gmlCode, UndertaleData data)
{
if (ParentEntry is not null)
return;

CompileContext context = Compiler.Compiler.CompileGMLText(gmlCode, data, this);
if (!context.SuccessfulCompile || context.HasError)
{
Expand Down Expand Up @@ -1323,6 +1360,9 @@ public void AppendGML(string gmlCode, UndertaleData data)
/// <exception cref="Exception">If the GML code does not compile or if there's an error writing the code to the profile entry.</exception>
public void ReplaceGML(string gmlCode, UndertaleData data)
{
if (ParentEntry is not null)
return;

CompileContext context = Compiler.Compiler.CompileGMLText(gmlCode, data, this);
if (!context.SuccessfulCompile || context.HasError)
{
Expand Down
10 changes: 9 additions & 1 deletion UndertaleModLib/UndertaleChunks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,11 @@ internal override void UnserializeChunk(UndertaleReader reader)
List = null;
return;
}

UndertaleCode.CurrCodeIndex = 0;
base.UnserializeChunk(reader);

reader.InstructionArraysLengths = null;
}

internal override uint UnserializeObjectCount(UndertaleReader reader)
Expand All @@ -708,9 +712,13 @@ internal override uint UnserializeObjectCount(UndertaleReader reader)
if (reader.undertaleData.UnsupportedBytecodeVersion)
return reader.ReadUInt32();

reader.GMS2BytecodeAddresses = new((int)reader.ReadUInt32());
int codeCount = (int)reader.ReadUInt32();
reader.Position -= 4;

reader.GMS2BytecodeAddresses = new(codeCount);
reader.InstructionArraysLengths = new int[codeCount];
UndertaleCode.CurrCodeIndex = 0;

uint count = base.UnserializeObjectCount(reader);
reader.GMS2BytecodeAddresses.Clear();

Expand Down
1 change: 1 addition & 0 deletions UndertaleModLib/UndertaleIO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ public override bool ReadBoolean()
private readonly Dictionary<Type, uint> staticObjCountDict = new();
private readonly Dictionary<Type, uint> staticObjSizeDict = new();
public HashSet<uint> GMS2BytecodeAddresses;
public int[] InstructionArraysLengths;

private readonly BindingFlags publicStaticFlags
= BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
Expand Down
9 changes: 9 additions & 0 deletions UndertaleModTool/ImportCodeSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ public void ReplaceTextInGML(string codeName, string keyword, string replacement
}
public void ReplaceTextInGML(UndertaleCode code, string keyword, string replacement, bool caseSensitive = false, bool isRegex = false, GlobalDecompileContext context = null)
{
if (code.ParentEntry is not null)
return;

EnsureDataLoaded();

string passBack = "";
Expand Down Expand Up @@ -201,6 +204,9 @@ void ImportCode(string codeName, string gmlCode, bool IsGML = true, bool doParse
code.Name = Data.Strings.MakeString(codeName);
Data.Code.Add(code);
}
else if (code.ParentEntry is not null)
return;

if (Data?.GeneralInfo.BytecodeVersion > 14 && Data.CodeLocals.ByName(codeName) == null)
{
UndertaleCodeLocals locals = new UndertaleCodeLocals();
Expand Down Expand Up @@ -410,6 +416,9 @@ void ImportCode(string codeName, string gmlCode, bool IsGML = true, bool doParse
void SafeImport(string codeName, string gmlCode, bool IsGML, bool destroyASM = true, bool CheckDecompiler = false, bool throwOnError = false)
{
UndertaleCode code = Data.Code.ByName(codeName);
if (code?.ParentEntry is not null)
return;

try
{
if (IsGML)
Expand Down
6 changes: 6 additions & 0 deletions UndertaleModTool/ProfileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public string GetDecompiledText(string codeName, GlobalDecompileContext context
}
public string GetDecompiledText(UndertaleCode code, GlobalDecompileContext context = null)
{
if (code.ParentEntry is not null)
return $"// This code entry is a reference to an anonymous function within \"{code.ParentEntry.Name.Content}\", decompile that instead.";

GlobalDecompileContext DECOMPILE_CONTEXT = context is null ? new(Data, false) : context;
try
{
Expand All @@ -36,6 +39,9 @@ public string GetDecompiledText(UndertaleCode code, GlobalDecompileContext conte

public string GetDisassemblyText(UndertaleCode code)
{
if (code.ParentEntry is not null)
return $"; This code entry is a reference to an anonymous function within \"{code.ParentEntry.Name.Content}\", disassemble that instead.";

try
{
return code != null ? code.Disassemble(Data.Variables, Data.CodeLocals.For(code)) : "";
Expand Down
8 changes: 6 additions & 2 deletions UndertaleModTool/Scripts/Resource Unpackers/ExportASM.csx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

EnsureDataLoaded();

Expand All @@ -16,7 +17,10 @@ if (Directory.Exists(codeFolder))

Directory.CreateDirectory(codeFolder);

SetProgressBar(null, "Code Entries", 0, Data.Code.Count);
List<UndertaleCode> toDump = Data.Code.Where(c => c.ParentEntry is null)
.ToList();

SetProgressBar(null, "Code Entries", 0, toDump.Count);
StartProgressBarUpdater();

await DumpCode();
Expand All @@ -34,7 +38,7 @@ string GetFolder(string path)

async Task DumpCode()
{
await Task.Run(() => Parallel.ForEach(Data.Code, DumpCode));
await Task.Run(() => Parallel.ForEach(toDump, DumpCode));
}

void DumpCode(UndertaleCode code)
Expand Down
14 changes: 9 additions & 5 deletions UndertaleModTool/Scripts/Technical Scripts/ExportAllCode2_3.csx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

EnsureDataLoaded();

Expand All @@ -28,7 +29,10 @@ if (Directory.Exists(codeFolder))

Directory.CreateDirectory(codeFolder);

SetProgressBar(null, "Code Entries", 0, Data.Code.Count);
List<UndertaleCode> toDump = Data.Code.Where(c => c.ParentEntry is null)
.ToList();

SetProgressBar(null, "Code Entries", 0, toDump.Count);
StartProgressBarUpdater();

int failed = 0;
Expand All @@ -48,16 +52,16 @@ void DumpCode()
//Because 2.3 code names get way too long, we're gonna convert it to an index based system, starting with a lookup system
string index_path = Path.Combine(codeFolder, "LookUpTable.txt");
string index_text = "This is zero indexed, index 0 starts at line 2.";
for (var i = 0; i < Data.Code.Count; i++)
for (var i = 0; i < toDump.Count; i++)
{
UndertaleCode code = Data.Code[i];
UndertaleCode code = toDump[i];
index_text += "\n";
index_text += code.Name.Content;
}
File.WriteAllText(index_path, index_text);
for (var i = 0; i < Data.Code.Count; i++)
for (var i = 0; i < toDump.Count; i++)
{
UndertaleCode code = Data.Code[i];
UndertaleCode code = toDump[i];
string path = Path.Combine(codeFolder, i.ToString() + ".gml");
try
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

EnsureDataLoaded();

Expand All @@ -16,7 +17,10 @@ if (Directory.Exists(codeFolder))

Directory.CreateDirectory(codeFolder);

SetProgressBar(null, "Code Entries", 0, Data.Code.Count);
List<UndertaleCode> toDump = Data.Code.Where(c => c.ParentEntry is null)
.ToList();

SetProgressBar(null, "Code Entries", 0, toDump.Count);
StartProgressBarUpdater();

int failed = 0;
Expand All @@ -34,7 +38,7 @@ string GetFolder(string path)

void DumpCode()
{
foreach(UndertaleCode code in Data.Code)
foreach(UndertaleCode code in toDump)
{
string path = Path.Combine(codeFolder, code.Name.Content + ".gml");
if (code.ParentEntry == null)
Expand Down

0 comments on commit 2c55f33

Please sign in to comment.