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

"UndertaleCode" improvements. #1585

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 103 additions & 1 deletion UndertaleModLib/Models/UndertaleCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ public interface ReferencedObject
int NameStringID { get; set; }
}

public class Reference<T> : UndertaleObject where T : class, UndertaleObject, ReferencedObject
public class Reference<T> : UndertaleObject, ICloneable where T : class, UndertaleObject, ReferencedObject
{
public uint NextOccurrenceOffset { get; set; } = 0xdead;
public VariableType Type { get; set; }
Expand Down Expand Up @@ -268,6 +268,21 @@ public void Unserialize(UndertaleReader reader)
Type = (VariableType)((int32Value >> 24) & 0xF8);
}

/// <summary>
/// Creates a new <see cref="Reference{T}"/> that is a copy of this <see cref="Reference{T}"/>.
/// </summary>
/// <returns>A new <see cref="Reference{T}"/> that is a copy of this <see cref="Reference{T}"/>.</returns>
public Reference<T> Clone()
{
return new Reference<T>()
{
NextOccurrenceOffset = this.NextOccurrenceOffset,
Target = this.Target,
Type = this.Type
};
}
object ICloneable.Clone() => Clone();

/// <inheritdoc />
public override string ToString()
{
Expand Down Expand Up @@ -843,6 +858,30 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader)
return 0;
}

/// <summary>
/// Creates a new <see cref="UndertaleInstruction"/> that is a copy of this instruction.
/// </summary>
/// <returns>A new <see cref="UndertaleInstruction"/> that is a copy of this instruction.</returns>
public UndertaleInstruction Clone()
{
return new UndertaleInstruction()
{
Kind = this.Kind,
ComparisonKind = this.ComparisonKind,
Type1 = this.Type1,
Type2 = this.Type2,
TypeInst = this.TypeInst,
Value = this.Value is ICloneable cloneable ? cloneable.Clone() : this.Value,
Destination = this.Destination?.Clone(),
Function = this.Function?.Clone(),
JumpOffset = this.JumpOffset,
JumpOffsetPopenvExitMagic = this.JumpOffsetPopenvExitMagic,
ArgumentsCount = this.ArgumentsCount,
Extra = this.Extra,
SwapExtra = this.SwapExtra
};
}

/// <inheritdoc />
public override string ToString()
{
Expand Down Expand Up @@ -1343,6 +1382,69 @@ public void Replace(IList<UndertaleInstruction> instructions)
Append(instructions);
}

/// <summary>
/// Insert instructions at specified index in this code entry.
/// </summary>
/// <param name="instructions">The instructions to insert.</param>
/// <param name="index">The index of insertion.</param>
public void Insert(IList<UndertaleInstruction> instructions, int index)
{
uint offsetU = 0;
uint address = Instructions[index].Address;
foreach (UndertaleInstruction instr in instructions)
offsetU += instr.CalculateInstructionSize();

int offset = (int)offsetU;

for (int i = 0; i < Instructions.Count; i++)
{
if (UndertaleInstruction.GetInstructionType(Instructions[i].Kind) == UndertaleInstruction.InstructionType.GotoInstruction)
{
if (i < index && Instructions[i].Address + Instructions[i].JumpOffset > address)
{
Instructions[i] = Instructions[i].Clone();
Instructions[i].JumpOffset += offset;
}
else if (i > index && Instructions[i].Address + Instructions[i].JumpOffset <= address)
{
Instructions[i] = Instructions[i].Clone();
Instructions[i].JumpOffset -= offset;
}
}
}

Instructions.InsertRange(index + 1, instructions);
}
/// <summary>
/// Insert an instruction at specified index in this code entry.
/// </summary>
/// <param name="instruction">The instruction to insert.</param>
/// <param name="index">The index of insertion.</param>
public void Insert(UndertaleInstruction instruction, int index)
{
uint address = Instructions[index].Address;
int offset = (int)instruction.CalculateInstructionSize();

for (int i = 0; i < Instructions.Count; i++)
{
if (UndertaleInstruction.GetInstructionType(Instructions[i].Kind) == UndertaleInstruction.InstructionType.GotoInstruction)
{
if (i < index && Instructions[i].Address + Instructions[i].JumpOffset > address)
{
Instructions[i] = Instructions[i].Clone();
Instructions[i].JumpOffset += offset;
}
else if (i > index && Instructions[i].Address + Instructions[i].JumpOffset <= address)
{
Instructions[i] = Instructions[i].Clone();
Instructions[i].JumpOffset -= offset;
}
}
}

Instructions.Insert(index + 1, instruction);
}

/// <summary>
/// Append GML instructions at the end of this code entry.
/// </summary>
Expand Down
12 changes: 11 additions & 1 deletion UndertaleModLib/UndertaleIO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public interface UndertaleResourceRef : UndertaleObject
int SerializeById(UndertaleWriter writer);
}

public class UndertaleResourceById<T, ChunkT> : UndertaleResourceRef, IStaticChildObjectsSize, IDisposable where T : UndertaleResource, new() where ChunkT : UndertaleListChunk<T>
public class UndertaleResourceById<T, ChunkT> : UndertaleResourceRef, IStaticChildObjectsSize, ICloneable, IDisposable where T : UndertaleResource, new() where ChunkT : UndertaleListChunk<T>
{
/// <inheritdoc cref="IStaticChildObjectsSize.ChildObjectsSize" />
public static readonly uint ChildObjectsSize = 4;
Expand Down Expand Up @@ -120,6 +120,16 @@ public override string ToString()
return (Resource?.ToString() ?? "(null)") + GetMarkerSuffix();
}

/// <summary>
/// Creates a new <see cref="UndertaleResourceById{T, ChunkT}"/> that is a copy of this <see cref="UndertaleResourceById{T, ChunkT}"/>.
/// </summary>
/// <returns>A new <see cref="UndertaleResourceById{T, ChunkT}"/> that is a copy of this <see cref="UndertaleResourceById{T, ChunkT}"/>.</returns>
public UndertaleResourceById<T, ChunkT> Clone()
{
return new UndertaleResourceById<T, ChunkT>(Resource, CachedId);
}
object ICloneable.Clone() => Clone();

/// <inheritdoc/>
public void Dispose()
{
Expand Down
Loading