Ejemplo n.º 1
0
 private void OnDestroy()
 {
     foreach (var bone in GetComponents <DynamicBone>())
     {
         JigglySolverApi.DynamicBoneOnDestroyPatch(bone.Pointer);
     }
 }
Ejemplo n.º 2
0
        private static IntPtr GetProcAddressSafe(IntPtr module, string name)
        {
            if (module == IntPtr.Zero)
            {
                return(IntPtr.Zero);
            }
            var result = JigglySolverApi.GetProcAddress(module, name);

            if (result == IntPtr.Zero)
            {
                MelonLogger.Error($"No entry point for {name}");
            }
            else
            {
                MelonDebug.Msg($"Entry point for {name} is {result}");
            }

            return(result);
        }
Ejemplo n.º 3
0
        public static void SetOffsets()
        {
            var ga = JigglySolverApi.LoadLibraryA("GameAssembly.dll");

            if (ga == IntPtr.Zero)
            {
                MelonLogger.Error("GameAssembly was not found, crash will likely follow");
            }

            var icalls = new ICallOffsets
            {
                get_transform_component             = GetICall("UnityEngine.Component::get_transform"),
                get_transform_ltw_matrix            = GetICall("UnityEngine.Transform::get_localToWorldMatrix_Injected"),
                get_component_enabled               = GetICall("UnityEngine.Behaviour::get_enabled"),
                get_transform_child_count           = GetICall("UnityEngine.Transform::get_childCount"),
                set_transform_position_and_rotation = GetICall("UnityEngine.Transform::SetPositionAndRotation_Injected"),

                gchandle_create = GetProcAddressSafe(ga, nameof(IL2CPP.il2cpp_gchandle_new)),
                gchandle_drop   = GetProcAddressSafe(ga, nameof(IL2CPP.il2cpp_gchandle_free)),
                gchandle_get    = GetProcAddressSafe(ga, nameof(IL2CPP.il2cpp_gchandle_get_target)),

                transform_get_local_rotation = GetICall("UnityEngine.Transform::get_localRotation_Injected")
            };

            var objectOffsets = new ObjectOffsets
            {
                cached_ptr = GetFieldOffset <UnityEngine.Object>(nameof(UnityEngine.Object.m_CachedPtr)),
            };

            var colliderOffsets = new ColliderComponentOffsets
            {
                collider_radius    = GetFieldOffset <DynamicBoneCollider>(nameof(DynamicBoneCollider.m_Radius)),
                collider_center    = GetFieldOffset <DynamicBoneCollider>(nameof(DynamicBoneCollider.m_Center)),
                collider_bound     = GetFieldOffset <DynamicBoneCollider>(nameof(DynamicBoneCollider.m_Bound)),
                collider_direction = GetFieldOffset <DynamicBoneCollider>(nameof(DynamicBoneCollider.m_Direction)),
                collider_height    = GetFieldOffset <DynamicBoneCollider>(nameof(DynamicBoneCollider.m_Height)),
            };

            var listOffsets = new ListClassOffsets
            {
                size        = GetFieldOffset <List <Il2CppSystem.Object> >(nameof(List <int> ._size)),
                store       = GetFieldOffset <List <Il2CppSystem.Object> >(nameof(List <int> ._items)),
                array_store = (uint)IntPtr.Size * 4  // classPtr, monitor, bounds, maxSize
            };

            var boneOffsets = new BoneComponentOffsets
            {
                collider_list = GetFieldOffset <DynamicBone>(nameof(DynamicBone.m_Colliders)),
                particle_list = GetFieldOffset <DynamicBone>(nameof(DynamicBone.field_Private_List_1_ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique_0)),
                force         = GetFieldOffset <DynamicBone>(nameof(DynamicBone.m_Force)),
                gravity       = GetFieldOffset <DynamicBone>(nameof(DynamicBone.m_Gravity)),
                local_gravity = GetFieldOffset <DynamicBone>(nameof(DynamicBone.field_Private_Vector3_0)),
                freeze_axis   = GetFieldOffset <DynamicBone>(nameof(DynamicBone.m_FreezeAxis)),
                update_rate   = GetFieldOffset <DynamicBone>(nameof(DynamicBone.m_UpdateRate)),
                root          = GetFieldOffset <DynamicBone>(nameof(DynamicBone.m_Root)),
            };

            var particleOffsets = new ParticleClassOffsets
            {
                transform    = GetFieldOffset <DynamicBone.ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique>(nameof(DynamicBone.ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique.field_Public_Transform_0)),
                parent_index = GetFieldOffset <DynamicBone.ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique>(nameof(DynamicBone.ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique.field_Public_Int32_0)),

                damping    = GetFieldOffset <DynamicBone.ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique>(nameof(DynamicBone.ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique.field_Public_Single_0)),
                elasticity = GetFieldOffset <DynamicBone.ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique>(nameof(DynamicBone.ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique.field_Public_Single_1)),
                stiffness  = GetFieldOffset <DynamicBone.ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique>(nameof(DynamicBone.ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique.field_Public_Single_2)),
                inert      = GetFieldOffset <DynamicBone.ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique>(nameof(DynamicBone.ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique.field_Public_Single_3)),
                radius     = GetFieldOffset <DynamicBone.ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique>(nameof(DynamicBone.ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique.field_Public_Single_4)),

                end_offset = GetFieldOffset <DynamicBone.ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique>(nameof(DynamicBone.ObjectNPrivateTrInSiVeSiQuVeSiVeSiUnique.field_Public_Vector3_2)),
            };

            JigglySolverApi.SetPointersAndOffsets(ref icalls, ref colliderOffsets, ref boneOffsets, ref particleOffsets,
                                                  ref listOffsets, ref objectOffsets);
        }
Ejemplo n.º 4
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(); }