Skip to content

Commit

Permalink
Improve EntityList.UpdateLists performance
Browse files Browse the repository at this point in the history
  • Loading branch information
DemoJameson committed May 6, 2023
1 parent f454522 commit cee71dd
Showing 1 changed file with 45 additions and 0 deletions.
45 changes: 45 additions & 0 deletions Celeste.Mod.mm/Patches/Monocle/EntityList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ internal void ClearEntities() {
[MonoModIgnore]
[PatchEntityListUpdate]
internal extern void Update();

[MonoModIgnore]
[PatchEntityListUpdateLists]
internal extern void UpdateLists();
}
public static class EntityListExt {

Expand All @@ -51,6 +55,12 @@ namespace MonoMod {
[MonoModCustomMethodAttribute(nameof(MonoModRules.PatchEntityListUpdate))]
class PatchEntityListUpdateAttribute : Attribute { }

/// <summary>
/// Improves performance by removing redundant Contains()
/// </summary>
[MonoModCustomMethodAttribute(nameof(MonoModRules.PatchEntityListUpdateLists))]
class PatchEntityListUpdateListsAttribute : Attribute { }

static partial class MonoModRules {

public static void PatchEntityListUpdate(ILContext context, CustomAttribute attrib) {
Expand All @@ -70,5 +80,40 @@ public static void PatchEntityListUpdate(ILContext context, CustomAttribute attr
cursor.MarkLabel(branchMatch);
}

public static void PatchEntityListUpdateLists(ILContext context, CustomAttribute attrib) {
ILCursor cursor = new ILCursor(context);

// if (!current.Contains(entity)) { if (current.Add(entity)) {
// current.Add(entity); -> entities.Add(entity);
// entities.Add(entity); }
// }
cursor.GotoNext(
instr => instr.MatchLdarg(0),
instr => instr.MatchLdfld(out _),
instr => instr.MatchLdloc(1),
instr => instr.OpCode == OpCodes.Callvirt && (instr.Operand as MethodReference).GetID().Contains("HashSet`1<Monocle.Entity>::Add"));
object hashAddOperand = cursor.Instrs[cursor.Index + 2].Next.Operand;
cursor.RemoveRange(5);
cursor.GotoPrev(instr => instr.OpCode == OpCodes.Callvirt && (instr.Operand as MethodReference).GetID().Contains("HashSet`1<Monocle.Entity>::Contains"));
cursor.Next.Operand = hashAddOperand;
cursor.Next.Next.OpCode = OpCodes.Brfalse_S;

// if (entities.Contains(entity)) { if (current.Remove(entity)) {
// current.Remove(entity); -> entities.Remove(entity);
// entities.Remove(entity); }
// }
cursor.GotoNext(
instr => instr.MatchLdarg(0),
instr => instr.MatchLdfld(out _),
instr => instr.MatchLdloc(3),
instr => instr.OpCode == OpCodes.Callvirt && (instr.Operand as MethodReference).GetID().Contains("HashSet`1<Monocle.Entity>::Remove"));
object currentOperand = cursor.Next.Next.Operand;
object hashRemoveOperand = cursor.Instrs[cursor.Index + 2].Next.Operand;
cursor.RemoveRange(5);
cursor.GotoPrev(instr => instr.OpCode == OpCodes.Callvirt && (instr.Operand as MethodReference).GetID().Contains("List`1<Monocle.Entity>::Contains"));
cursor.Prev.Previous.Operand = currentOperand;
cursor.Next.Operand = hashRemoveOperand;
}

}
}

0 comments on commit cee71dd

Please sign in to comment.