about summary refs log tree commit diff
path: root/pkgs/games
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/games')
-rw-r--r--pkgs/games/build-support/monogame-patcher/patcher.cs63
1 files changed, 61 insertions, 2 deletions
diff --git a/pkgs/games/build-support/monogame-patcher/patcher.cs b/pkgs/games/build-support/monogame-patcher/patcher.cs
index 16878831..c1502ba1 100644
--- a/pkgs/games/build-support/monogame-patcher/patcher.cs
+++ b/pkgs/games/build-support/monogame-patcher/patcher.cs
@@ -99,11 +99,70 @@ class FixFileStreams : Command {
     }
 }
 
+[Verb("replace-call", HelpText="Replace calls to types.")]
+class ReplaceCallCmd : GenericOptions {
+    [Value(0, Min=2, Max=2, HelpText="Call to replace.")]
+    public IEnumerable<string> replaceCall { get; set; }
+
+    [Value(2, Required=true, MetaName = "type", HelpText = "Types to patch.")]
+    public IEnumerable<string> typesToPatch { get; set; }
+
+};
+
+class ReplaceCall : Command {
+    private string search;
+    private string replace;
+
+    public ReplaceCall(ReplaceCallCmd options) : base(options) {
+        this.search = options.replaceCall.ToList()[0];
+        this.replace = options.replaceCall.ToList()[1];
+
+        var filtered = this.module.Types
+            .Where(p => options.typesToPatch.Contains(p.Name));
+
+        foreach (var toPatch in filtered)
+            patch_type(toPatch);
+
+        this.save();
+    }
+
+    private void patch_method(MethodDefinition md) {
+        var il = md.Body.GetILProcessor();
+
+        var found = md.Body.Instructions
+            .Where(i => i.OpCode == OpCodes.Call)
+            .Where(i => i.Operand.ToString() == this.search);
+
+        var ctorType = this.module.AssemblyReferences.Select(
+            x => new {
+                // XXX: Don't hardcode UnityEngine.Application!
+                type = this.module.AssemblyResolver.Resolve(x)
+                    .MainModule.GetType("UnityEngine.Application")
+            }
+        ).Where(x => x.type != null).Select(x => x.type).First();
+
+        var newMethod = ctorType.GetMethods()
+            .Single(x => x.ToString() == this.replace);
+        var refMethod = this.module.ImportReference(newMethod);
+
+        foreach (Instruction i in found.ToList())
+            il.Replace(i, il.Create(OpCodes.Call, refMethod));
+    }
+
+    private void patch_type(TypeDefinition td) {
+        foreach (var nested in td.NestedTypes) patch_type(nested);
+        foreach (MethodDefinition md in td.Methods) patch_method(md);
+    }
+}
+
 public class patcher {
 
     public static int Main(string[] args) {
-        Parser.Default.ParseArguments<GenericOptions, FixFileStreamsCmd>(args)
-            .WithParsed<FixFileStreamsCmd>(opts => new FixFileStreams(opts));
+        Parser.Default.ParseArguments<
+            GenericOptions, FixFileStreamsCmd, ReplaceCallCmd
+        >(args)
+            .WithParsed<FixFileStreamsCmd>(opts => new FixFileStreams(opts))
+            .WithParsed<ReplaceCallCmd>(opts => new ReplaceCall(opts));
         return 0;
     }
 }