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;
        }
Example #3
0
        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(); }