Patcher.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. using System.IO;
  2. using System.Linq;
  3. using System.Reflection;
  4. using Mono.Cecil;
  5. using Mono.Cecil.Cil;
  6. namespace COM3D2.CacheEditMenu.Patcher
  7. {
  8. public static class Patcher
  9. {
  10. public static readonly string[] TargetAssemblyNames = { "Assembly-CSharp.dll" };
  11. public static readonly string SybarisPath = Path.GetDirectoryName(typeof(Patcher).Assembly.Location);
  12. private static void PatchHelper(MethodDefinition target, MethodReference prefix, MethodReference postix, params int[] ldargs)
  13. {
  14. var il = target.Body.GetILProcessor();
  15. var resultVar = target.ReturnType.FullName != "System.Void" ? new VariableDefinition(target.Module.ImportReference(target.ReturnType)) : null;
  16. if(resultVar != null)
  17. target.Body.Variables.Add(resultVar);
  18. var ins = target.Body.Instructions[0];
  19. if(resultVar != null)
  20. il.InsertBefore(ins, il.Create(OpCodes.Ldloca, resultVar));
  21. foreach (var ldarg in ldargs)
  22. il.InsertBefore(ins, il.Create(OpCodes.Ldarg, ldarg));
  23. il.InsertBefore(ins, il.Create(OpCodes.Call, target.Module.ImportReference(prefix)));
  24. il.InsertBefore(ins, il.Create(OpCodes.Brtrue, ins));
  25. if(resultVar != null)
  26. il.InsertBefore(ins, il.Create(OpCodes.Ldloc, resultVar));
  27. il.InsertBefore(ins, il.Create(OpCodes.Ret));
  28. if (postix == null)
  29. return;
  30. ins = il.Create(OpCodes.Nop);
  31. foreach (var bodyInstruction in target.Body.Instructions.Where(bodyInstruction => bodyInstruction.OpCode == OpCodes.Ret).Skip(1))
  32. {
  33. bodyInstruction.OpCode = OpCodes.Br;
  34. bodyInstruction.Operand = ins;
  35. }
  36. il.Append(ins);
  37. ins = il.Create(OpCodes.Ret);
  38. il.Append(ins);
  39. foreach (var ldarg in ldargs)
  40. il.InsertBefore(ins, il.Create(OpCodes.Ldarg, ldarg));
  41. il.InsertBefore(ins, il.Create(OpCodes.Call, target.Module.ImportReference(postix)));
  42. }
  43. public static void Patch(AssemblyDefinition ad)
  44. {
  45. var hookAd = AssemblyDefinition.ReadAssembly(
  46. typeof(Patcher).Assembly.GetManifestResourceStream(
  47. "COM3D2.CacheEditMenu.Patcher.COM3D2.CacheEditMenu.dll"));
  48. var sceneEdit = ad.MainModule.GetType("SceneEdit");
  49. var getMenuItemSetUp = sceneEdit.Methods.FirstOrDefault(m => m.Name == "GetMenuItemSetUP");
  50. var initMenuItemScript = sceneEdit.Methods.FirstOrDefault(m => m.Name == "InitMenuItemScript");
  51. // var importCm = ad.MainModule.GetType("ImportCM");
  52. // var createTexture = importCm.Methods.FirstOrDefault(m => m.Name == "CreateTexture" && m.Parameters.Count == 1);
  53. var hookType = hookAd.MainModule.GetType("COM3D2.CacheEditMenu.Hooks");
  54. var getMenuItemSetUpPrefix = hookType.Methods.FirstOrDefault(m => m.Name == "Prefix");
  55. var getMenuItemSetUpPostfix = hookType.Methods.FirstOrDefault(m => m.Name == "Postfix");
  56. var createTexturePrefix = hookType.Methods.FirstOrDefault(m => m.Name == "CreateTexturePrefix");
  57. PatchHelper(getMenuItemSetUp, getMenuItemSetUpPrefix, getMenuItemSetUpPostfix, 0, 1);
  58. var il = initMenuItemScript.Body.GetILProcessor();
  59. foreach (var ins in il.Body.Instructions.ToList())
  60. {
  61. if (ins.OpCode == OpCodes.Call &&
  62. ((MethodReference)ins.Operand).Name == "CreateTexture")
  63. il.InsertBefore(ins, il.Create(OpCodes.Call, ad.MainModule.ImportReference(createTexturePrefix)));
  64. }
  65. var buffer = new byte[4096];
  66. using(var s = typeof(Patcher).Assembly.GetManifestResourceStream(
  67. "COM3D2.CacheEditMenu.Patcher.COM3D2.CacheEditMenu.dll"))
  68. using (var ms = new MemoryStream())
  69. {
  70. int read;
  71. while ((read = s.Read(buffer, 0, buffer.Length)) > 0)
  72. ms.Write(buffer, 0, read);
  73. Assembly.Load(ms.ToArray());
  74. }
  75. }
  76. }
  77. }