about summary refs log tree commit diff
path: root/pkgs/games/build-support
diff options
context:
space:
mode:
authoraszlig <aszlig@nix.build>2018-07-16 23:43:20 +0200
committeraszlig <aszlig@nix.build>2018-07-19 06:35:09 +0200
commitcf54036a6adf6977300c611c50f7daf2445a0589 (patch)
treeaa717f9344a4040e70abd49b473fcfb4395e01df /pkgs/games/build-support
parentc9dfe485e9b922b35c9412e6c4fdbe119f17f4b5 (diff)
monogame-patcher: Add a replace-call subcommand
It's a very early version which I did for a Unity3d game and it
*desperately* needs a cleanup.

An example command line:

  monogame-patcher replace-call -i Assembly-CSharp.dll \
    'System.String UnityEngine.Application::get_dataPath()' \
    'System.String UnityEngine.Application::get_persistentDataPath()' \
    IniParser SaveMeta

Right now the replace-call subcommand has UnityEngine.Application
hardcoded, so this won't work for other types than
UnityEngine.Application.

However, I'm going to refactor the whole patcher very soon and add some
tests, so this whole mess will be cleaned up.

Signed-off-by: aszlig <aszlig@nix.build>
Diffstat (limited to 'pkgs/games/build-support')
-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;
     }
 }