NeighUncensorPatcher.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Runtime.CompilerServices;
  8. using System.Runtime.InteropServices;
  9. using Mono.Cecil;
  10. using Mono.Cecil.Cil;
  11. using UnityEngine;
  12. namespace COM3D2.NeighUncensor.Patcher
  13. {
  14. public static class NeighUncensorPatcher
  15. {
  16. public static readonly string[] TargetAssemblyNames = { "Assembly-CSharp.dll" };
  17. public static void Patch(AssemblyDefinition ad)
  18. {
  19. var hookAd = AssemblyDefinition.ReadAssembly(Assembly.GetExecutingAssembly().Location);
  20. var hooks = hookAd.MainModule.GetType("COM3D2.NeighUncensor.Patcher.Hooks");
  21. var gameMain = ad.MainModule.GetType("GameMain");
  22. var onInit = gameMain.Methods.FirstOrDefault(m => m.Name == "OnInitialize");
  23. var ins = onInit.Body.Instructions.First();
  24. var il = onInit.Body.GetILProcessor();
  25. il.InsertBefore(
  26. ins,
  27. il.Create(OpCodes.Call,
  28. ad.MainModule.ImportReference(
  29. hooks.Methods.FirstOrDefault(m => m.Name == nameof(Hooks.FixShaders)))));
  30. }
  31. }
  32. public static class Hooks
  33. {
  34. // List of shaders the RQ of which to zero
  35. private static readonly string[] ShadersToCleanup = { "CM3D2/Mosaic", "CM3D2/Mosaic_en" };
  36. // We need to keep at least one instance of the shader alive so that it won't get unloaded
  37. private static readonly List<object> ShadersCache = new List<object>();
  38. public static void FixShaders()
  39. {
  40. try
  41. {
  42. var modules = Process.GetCurrentProcess().Modules;
  43. ProcessModule mono = null;
  44. foreach (ProcessModule module in modules)
  45. {
  46. if (!module.ModuleName.ToLowerInvariant().Contains("mono"))
  47. continue;
  48. mono = module;
  49. }
  50. if (mono == null)
  51. return;
  52. var addICall =
  53. Marshal.GetDelegateForFunctionPointer(GetProcAddress(mono.BaseAddress, "mono_add_internal_call"),
  54. typeof(AddICallDelegate)) as AddICallDelegate;
  55. addICall("COM3D2.NeighUncensor.Patcher.Hooks::FixShader",
  56. Marshal.GetFunctionPointerForDelegate(new FixShaderDelegate(FixShaderImpl)));
  57. CleanupMosaicShaders();
  58. }
  59. catch (Exception e)
  60. {
  61. File.WriteAllText("neigh_uncensor_error.log", e.ToString());
  62. }
  63. }
  64. private static void CleanupMosaicShaders()
  65. {
  66. foreach (string shaderName in ShadersToCleanup)
  67. {
  68. var s = Shader.Find(shaderName);
  69. if (s == null)
  70. continue;
  71. ShadersCache.Add(s);
  72. FixShader(s);
  73. }
  74. }
  75. public static unsafe void FixShaderImpl(IntPtr shaderObj)
  76. {
  77. var s = (byte*)shaderObj.ToPointer();
  78. var a = *(byte**)(s + 0x10);
  79. var b = *(byte**)(a + 0x38);
  80. var rq = (uint*)(b + 0x5C);
  81. *rq = 0u;
  82. }
  83. [MethodImpl(MethodImplOptions.InternalCall)]
  84. private static extern void FixShader(Shader s);
  85. [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
  86. private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
  87. private delegate void FixShaderDelegate(IntPtr shader);
  88. private delegate void AddICallDelegate([MarshalAs(UnmanagedType.LPStr)] string name, IntPtr addr);
  89. }
  90. }