Patcher.cs 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  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 importCm = ad.MainModule.GetType("ImportCM");
  51. var createTexture = importCm.Methods.FirstOrDefault(m => m.Name == "CreateTexture" && m.Parameters.Count == 1);
  52. var hookType = hookAd.MainModule.GetType("COM3D2.CacheEditMenu.Hooks");
  53. var getMenuItemSetUpPrefix = hookType.Methods.FirstOrDefault(m => m.Name == "Prefix");
  54. var getMenuItemSetUpPostfix = hookType.Methods.FirstOrDefault(m => m.Name == "Postfix");
  55. var createTexturePrefix = hookType.Methods.FirstOrDefault(m => m.Name == "CreateTexturePrefix");
  56. PatchHelper(getMenuItemSetUp, getMenuItemSetUpPrefix, getMenuItemSetUpPostfix, 0, 1);
  57. PatchHelper(createTexture, createTexturePrefix, null, 0);
  58. var buffer = new byte[4096];
  59. using(var s = typeof(Patcher).Assembly.GetManifestResourceStream(
  60. "COM3D2.CacheEditMenu.Patcher.COM3D2.CacheEditMenu.dll"))
  61. using (var ms = new MemoryStream())
  62. {
  63. int read;
  64. while ((read = s.Read(buffer, 0, buffer.Length)) > 0)
  65. ms.Write(buffer, 0, read);
  66. Assembly.Load(ms.ToArray());
  67. }
  68. }
  69. }
  70. }