public override MethodBase DetourTo(MethodBase replacement) { DebugCheck(); DynamicMethodDefinition newreplacementdmd = CopyOriginal(); HarmonyManipulator.Manipulate(Original, Original.GetPatchInfo(), new ILContext(newreplacementdmd.Definition)); MethodInfo newreplacement = newreplacementdmd.Generate(); MethodInfo il2CppShim = CreateIl2CppShim(newreplacement).Generate(); Type il2CppShimDelegateType = DelegateTypeFactory.instance.CreateDelegateType(il2CppShim, CallingConvention.Cdecl); Delegate il2CppShimDelegate = il2CppShim.CreateDelegate(il2CppShimDelegateType); IntPtr il2CppShimDelegatePtr = il2CppShimDelegate.GetFunctionPointer(); if (methodDetourPointer != IntPtr.Zero) { MelonUtils.NativeHookDetach(copiedMethodInfoPointer, methodDetourPointer); } MelonUtils.NativeHookAttach(copiedMethodInfoPointer, il2CppShimDelegatePtr); methodDetourPointer = il2CppShimDelegatePtr; PatchTools_RememberObject(Original, new LemonTuple <MethodInfo, MethodInfo, Delegate> { Item1 = newreplacement, Item2 = il2CppShim, Item3 = il2CppShimDelegate }); return(newreplacement); }
private static void InstallIl2CppPatch(PatchInfo patchInfo, DynamicMethod il2CppShim) { IntPtr methodInfoPtr = patchInfo.copiedMethodInfoPointer; IntPtr oldDetourPtr = patchInfo.methodDetourPointer; IntPtr newDetourPtr = il2CppShim.MethodHandle.GetFunctionPointer(); if (oldDetourPtr != IntPtr.Zero) { MelonUtils.NativeHookDetach(methodInfoPtr, oldDetourPtr); } MelonUtils.NativeHookAttach(methodInfoPtr, newDetourPtr); patchInfo.methodDetourPointer = newDetourPtr; }
public override void OnApplicationStart() { ClassInjector.RegisterTypeInIl2Cpp <BoneDeleteHandler>(); var category = MelonPreferences.CreateCategory("Turbones"); var enableCollisionChecks = category.CreateEntry("OptimizedCollisionChecks", true, "Enable optimized collision checks"); var enableUpdate = category.CreateEntry("OptimizedUpdate", true, "Enable optimized simulation"); var updateMultiThread = category.CreateEntry("OptimizedMultiThread", false, "Enable multithreading (placebo!)"); var threadCount = category.CreateEntry("DynamicBoneThreads", Math.Max(1, Environment.ProcessorCount / 2 - 1), "Thread count (placebo!)", dont_save_default: true); var dllName = "JigglyRustSolver.dll"; try { using var resourceStream = Assembly.GetExecutingAssembly() .GetManifestResourceStream(typeof(TurbonesMod), dllName); using var fileStream = File.Open("VRChat_Data/Plugins/" + dllName, FileMode.Create, FileAccess.Write); resourceStream.CopyTo(fileStream); } catch (IOException ex) { MelonLogger.Warning("Failed to write native dll; will attempt loading it anyway. This is normal if you're running multiple instances of VRChat"); MelonDebug.Msg(ex.ToString()); } if (!JigglySolverApi.Initialize("VRChat_Data/Plugins/" + dllName)) { MelonLogger.Error("Error initializing native library; mod won't work"); return; } ourDynBoneCollideEntryPoint = Marshal.ReadIntPtr((IntPtr)UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod( typeof(DynamicBoneCollider).GetMethod(nameof(DynamicBoneCollider .Method_Public_Void_byref_Vector3_Single_0))).GetValue(null)); ourDynBoneUpdateEntryPoint = Marshal.ReadIntPtr((IntPtr)UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod( typeof(DynamicBone).GetMethod(nameof(DynamicBone .Method_Private_Void_Single_Boolean_0))).GetValue(null)); var isCollidePatched = false; unsafe void PatchCollide() { if (isCollidePatched) { return; fixed(IntPtr *a = &ourDynBoneCollideEntryPoint) MelonUtils.NativeHookAttach((IntPtr)a, JigglySolverApi.LibDynBoneCollideEntryPoint); MelonLogger.Msg("Patched DynamicBone Collide"); isCollidePatched = true; } unsafe void UnpatchCollide() { if (!isCollidePatched) { return; fixed(IntPtr *a = &ourDynBoneCollideEntryPoint) MelonUtils.NativeHookDetach((IntPtr)a, JigglySolverApi.LibDynBoneCollideEntryPoint); MelonLogger.Msg("Unpatched DynamicBone Collide"); isCollidePatched = false; } unsafe void RepatchUpdate(bool useFast, bool useMt) { // TODO: re-enable multithreading if it ever gets useful/stable useMt = false; if (ourLastPatchPointer != IntPtr.Zero) { fixed(IntPtr *a = &ourDynBoneUpdateEntryPoint) MelonUtils.NativeHookDetach((IntPtr)a, ourLastPatchPointer); MelonLogger.Msg("Unpatched DynamicBone Update"); ourLastPatchPointer = IntPtr.Zero; } if (!CheckWasSuccessful) return; } if (useFast) { ourLastPatchPointer = useMt ? JigglySolverApi.LibDynBoneUpdateMultiThreaded : JigglySolverApi.LibDynBoneUpdateSingleThreaded; fixed(IntPtr *a = &ourDynBoneUpdateEntryPoint) MelonUtils.NativeHookAttach((IntPtr)a, ourLastPatchPointer); MelonLogger.Msg($"Patched DynamicBone Update (multithreaded: {useMt})"); } else { ourLastPatchPointer = JigglySolverApi.DynamicBoneUpdateNotifyPatch; fixed(IntPtr *a = &ourDynBoneUpdateEntryPoint) MelonUtils.NativeHookAttach((IntPtr)a, ourLastPatchPointer); JigglySolverApi.SetOriginalBoneUpdateDelegate(ourDynBoneUpdateEntryPoint); MelonLogger.Msg($"Patched DynamicBone Update (notify)"); } } CheckDummyThree(); enableCollisionChecks.OnValueChanged += (_, v) => { if (v) PatchCollide(); }