/// <inheritdoc /> public override DynamicMethodDefinition CopyOriginal() { var dmd = new DynamicMethodDefinition(Original); dmd.Definition.Name = "UnhollowedWrapper_" + dmd.Definition.Name; var cursor = new ILCursor(new ILContext(dmd.Definition)); // Remove il2cpp_object_get_virtual_method if (cursor.TryGotoNext(x => x.MatchLdarg(0), x => x.MatchCall(typeof(UnhollowerBaseLib.IL2CPP), nameof(UnhollowerBaseLib.IL2CPP.Il2CppObjectBaseToPtr)), x => x.MatchLdsfld(out _), x => x.MatchCall(typeof(UnhollowerBaseLib.IL2CPP), nameof(UnhollowerBaseLib.IL2CPP.il2cpp_object_get_virtual_method)))) { cursor.RemoveRange(4); } else { cursor.Goto(0) .GotoNext(x => x.MatchLdsfld(UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(Original))) .Remove(); } // Replace original IL2CPPMethodInfo pointer with a modified one that points to the trampoline cursor .Emit(Mono.Cecil.Cil.OpCodes.Ldc_I8, ((IntPtr)modifiedNativeMethodInfo).ToInt64()) .Emit(Mono.Cecil.Cil.OpCodes.Conv_I); return(dmd); }
public override void OnApplicationStart() { ModPrefs.RegisterCategory(SettingsCategory, "Sparkle Be Gone"); ModPrefs.RegisterPrefBool(SettingsCategory, StartSparkleSetting, false, "Show start sparkle"); ModPrefs.RegisterPrefBool(SettingsCategory, EndSparksSetting, false, "Show end sparks"); ModPrefs.RegisterPrefBool(SettingsCategory, EndFlareSetting, true, "Show end flare"); ModPrefs.RegisterPrefBool(SettingsCategory, RecolorSparksSetting, false, "Recolor sparks"); ModPrefs.RegisterPrefBool(SettingsCategory, RecolorBeamsSetting, true, "Recolor beams"); ModPrefs.RegisterPrefString(SettingsCategory, BeamColorSetting, "25 50 255 255", "Beam color (r g b a)"); var method = typeof(VRCSpaceUiPointer).GetMethod(nameof(VRCSpaceUiPointer.LateUpdate), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); { using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("SparkleBeGone.sparklebegone"); using var memStream = new MemoryStream((int)stream.Length); stream.CopyTo(memStream); var bundle = AssetBundle.LoadFromMemory_Internal(memStream.ToArray(), 0); myWhiteLaserTexture = bundle.LoadAsset_Internal("Assets/SparkleBeGone/sniper_beam_white.png", Il2CppType.Of <Texture2D>()).Cast <Texture2D>(); myWhiteLaserTexture.hideFlags |= HideFlags.DontUnloadUnusedAsset; } unsafe { var originalPointer = *(IntPtr *)(IntPtr)UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(method).GetValue(null); CompatHook((IntPtr)(&originalPointer), typeof(SparkleBeGoneMod).GetMethod(nameof(CursorLateUpdatePatch), BindingFlags.Static | BindingFlags.NonPublic) !.MethodHandle.GetFunctionPointer()); ourOriginalLateUpdate = Marshal.GetDelegateForFunctionPointer <VoidDelegate>(originalPointer); } MelonCoroutines.Start(InitThings()); }
private static unsafe TDelegate Patch <TDelegate>(MethodBase originalMethod, IntPtr patchDetour) { IntPtr original = *(IntPtr *)(IntPtr)UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(originalMethod).GetValue(null); MelonUtils.NativeHookAttach((IntPtr)(&original), patchDetour); return(Marshal.GetDelegateForFunctionPointer <TDelegate>(original)); }
private void Init() { try { var methodField = UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(Original); if (methodField == null) { throw new Exception($"No IL2CPP equivalent found for {Original.FullDescription()}. The target might have been automatically generated by Unhollower (e.g. field accessor)."); } // Get the native MethodInfo struct for the target method originalNativeMethodInfo = (Il2CppMethodInfo *)(IntPtr)methodField.GetValue(null); // Create a trampoline from the original target method var trampolinePtr = DetourGenerator.CreateTrampolineFromFunction(originalNativeMethodInfo->methodPointer, out _, out _); // Create a modified native MethodInfo struct to point towards the trampoline modifiedNativeMethodInfo = (Il2CppMethodInfo *)Marshal.AllocHGlobal(Marshal.SizeOf <Il2CppMethodInfo>()); Marshal.StructureToPtr(*originalNativeMethodInfo, (IntPtr)modifiedNativeMethodInfo, false); modifiedNativeMethodInfo->methodPointer = trampolinePtr; isValid = true; } catch (Exception e) { DetourLogger.LogWarning($"Failed to init IL2CPP patch backend for {Original.FullDescription()}, using normal patch handlers: {e.Message}"); } }
public static unsafe void RegisterType(Type type) { try { Lock.EnterUpgradeableReadLock(); if (RegisteredTypes.Contains(type)) { return; } try { Lock.EnterWriteLock(); RegisteredTypes.Add(type); void ProcessMethod(MethodBase method) { if (method.IsGenericMethod || method.IsGenericMethodDefinition) { return; } if (method.GetMethodBody() == null) { return; } var pointerField = UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(method); if (pointerField == null || pointerField.DeclaringType?.IsGenericTypeDefinition == true) { return; } MethodMap[*(IntPtr *)(IntPtr)pointerField.GetValue(null)] = method; } var methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); foreach (var methodInfo in methods) { ProcessMethod(methodInfo); } var ctors = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); foreach (var methodInfo in ctors) { ProcessMethod(methodInfo); } } finally { Lock.ExitWriteLock(); } } finally { Lock.ExitUpgradeableReadLock(); } if (type.BaseType != null) { RegisterType(type.BaseType); } }
public static unsafe IEnumerable <XrefInstance> XrefScan(MethodBase methodBase) { var fieldValue = UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(methodBase)?.GetValue(null); if (fieldValue == null) { return(Enumerable.Empty <XrefInstance>()); } var cachedAttribute = methodBase.GetCustomAttribute <CachedScanResultsAttribute>(false); if (cachedAttribute == null) { XrefScanMetadataRuntimeUtil.CallMetadataInitForMethod(methodBase); return(XrefScanImpl(DecoderForAddress(*(IntPtr *)(IntPtr)fieldValue))); } if (cachedAttribute.XrefRangeStart == cachedAttribute.XrefRangeEnd) { return(Enumerable.Empty <XrefInstance>()); } XrefScanMethodDb.CallMetadataInitForMethod(cachedAttribute); return(XrefScanMethodDb.CachedXrefScan(cachedAttribute).Where(it => it.Type == XrefType.Method || XrefGlobalClassFilter(it.Pointer))); }
public static unsafe void ApplyPatches() { try { // PDM's are scary:( MethodInfo avatarChangedMethod = typeof(VRCAvatarManager).GetMethods().FirstOrDefault(method => method.Name.StartsWith("Method_Private_Void_ApiAvatar_GameObject_Action_1_Boolean_")); IntPtr original = *(IntPtr *)(IntPtr)UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(avatarChangedMethod).GetValue(null); MelonUtils.NativeHookAttach((IntPtr)(&original), typeof(ImmersiveTouch).GetMethod(nameof(ImmersiveTouch.OnAvatarChanged), BindingFlags.Static | BindingFlags.Public) !.MethodHandle.GetFunctionPointer()); avatarChangedDelegate = Marshal.GetDelegateForFunctionPointer <AvatarChangedDelegate>(original); } catch (Exception e) { MelonLogger.Error($"Failed to patch: OnAvatarChanged\n{e}"); } try { IntPtr original = *(IntPtr *)(IntPtr)UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(DynamicBone).GetMethod(nameof(DynamicBone.Method_Private_Void_Boolean_0))).GetValue(null); MelonUtils.NativeHookAttach((IntPtr)(&original), typeof(ImmersiveTouch).GetMethod(nameof(ImmersiveTouch.OnUpdateParticles), BindingFlags.Static | BindingFlags.Public) !.MethodHandle.GetFunctionPointer()); updateParticlesDelegate = Marshal.GetDelegateForFunctionPointer <UpdateParticlesDelegate>(original); } catch (Exception e) { MelonLogger.Error($"Failed to patch: OnUpdateParticles\n{e}"); } try { IntPtr original = *(IntPtr *)(IntPtr)UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(DynamicBoneCollider).GetMethod(nameof(DynamicBoneCollider.Method_Public_Void_byref_Vector3_Single_0))).GetValue(null); MelonUtils.NativeHookAttach((IntPtr)(&original), typeof(ImmersiveTouch).GetMethod(nameof(ImmersiveTouch.OnCollide), BindingFlags.Static | BindingFlags.Public) !.MethodHandle.GetFunctionPointer()); collideDelegate = Marshal.GetDelegateForFunctionPointer <CollideDelegate>(original); } catch (Exception e) { MelonLogger.Error($"Failed to patch: OnCollide\n{e}"); } }
public static IntPtr Il2CppPtr(this MethodInfo methodInfo) { unsafe { return(*(IntPtr *)(IntPtr)UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(methodInfo).GetValue(null)); } }
public static void HookIntoSpawnData() { unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(EnemyGroup).GetMethod(nameof(EnemyGroup.GetSpawnData))) .GetValue(null); FastNativeDetour.CreateAndApply(originalMethodPointer, HackyHooks.GetEnemySpawnDataPatch, out ourGetEnemySpawnData, CallingConvention.Cdecl); } }
public static void HookIntoChatMessages() { unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(PlayerChatManager).GetMethod(nameof(PlayerChatManager.DoSendChatMessage))) .GetValue(null); FastNativeDetour.CreateAndApply(originalMethodPointer, HackyHooks.ChatMsgPatch, out ourChatDelegate, CallingConvention.Cdecl); } }
private static void ApplyPatches() { PatchICall("UnityEngine.Transform::" + nameof(Transform.set_position_Injected), out ourOriginalTransformSetter, nameof(SetTransformVectorPatch)); PatchICall("UnityEngine.Transform::" + nameof(Transform.set_rotation_Injected), out ourOriginalTransformRotSetter, nameof(SetTransformQuaternionPatch)); PatchICall("UnityEngine.Transform::" + nameof(Transform.SetPositionAndRotation_Injected), out ourOriginalTransformTwinSetter, nameof(SetTransformVectorQuaternionPatch)); PatchICall("UnityEngine.Rigidbody::" + nameof(Rigidbody.set_position_Injected), out ourOriginalRigidbodyPosSetter, nameof(SetRigidbodyPosPatch)); PatchICall("UnityEngine.Rigidbody::" + nameof(Rigidbody.set_rotation_Injected), out ourOriginalRigidbodyRotSetter, nameof(SetRigidbodyRotPatch)); PatchICall("UnityEngine.Rigidbody::" + nameof(Rigidbody.MovePosition_Injected), out ourOriginalRigidbodyPosMove, nameof(SetRigidbodyPosMovePatch)); PatchICall("UnityEngine.Rigidbody::" + nameof(Rigidbody.MoveRotation_Injected), out ourOriginalRigidbodyRotMove, nameof(SetRigidbodyRotMovePatch)); PatchICall("UnityEngine.Rigidbody::" + nameof(Rigidbody.set_velocity_Injected), out ourOriginalRigidbodyVelSetter, nameof(SetRigidbodyVelPatch)); PatchICall("UnityEngine.Rigidbody::" + nameof(Rigidbody.set_angularVelocity_Injected), out ourOriginalRigidbodyAvSetter, nameof(SetRigidbodyAvPatch)); // These two were originally used to deserialize stuff from photon, but it seems like the vector one is not used anymore unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(PhotonSerializers).GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly).Single(it => { var parameters = it.GetParameters(); if (it.ReturnType != typeof(void) || parameters.Length != 3 || it.Name.Contains("_PDM_") || parameters[1].ParameterType != typeof(Vector3).MakeByRefType()) { return(false); } return(true); })) .GetValue(null); Imports.Hook((IntPtr)(&originalMethodPointer), typeof(FinitizerMod).GetMethod(nameof(VectorPatch), BindingFlags.Static | BindingFlags.NonPublic) !.MethodHandle.GetFunctionPointer()); ourOriginalVectorMethod = Marshal.GetDelegateForFunctionPointer <VectorMethod>(originalMethodPointer); } unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(PhotonSerializers).GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly).Single(it => { var parameters = it.GetParameters(); if (it.ReturnType != typeof(void) || parameters.Length != 3 || it.Name.Contains("_PDM_") || parameters[1].ParameterType != typeof(Quaternion).MakeByRefType()) { return(false); } return(true); })) .GetValue(null); Imports.Hook((IntPtr)(&originalMethodPointer), typeof(FinitizerMod).GetMethod(nameof(QuaternionPatch), BindingFlags.Static | BindingFlags.NonPublic) !.MethodHandle.GetFunctionPointer()); ourOriginalQuaternionMethod = Marshal.GetDelegateForFunctionPointer <QuaternionMethod>(originalMethodPointer); } MelonLogger.Log("Things patching complete"); }
public static void OnApplicationStart() { if (File.Exists(BlockedAvatarsMakersFilePath)) { ourBlockedAvatarAuthors.Clear(); foreach (var it in File.ReadAllLines(BlockedAvatarsMakersFilePath, Encoding.UTF8)) { var split = it.Split(new[] { '͏', ' ' }, 2, StringSplitOptions.RemoveEmptyEntries); if (split.Length == 2) { ourBlockedAvatarAuthors[split[0].Trim()] = split[1]; } } } if (File.Exists(BlockedAvatarsFilePath)) { ourBlockedAvatars.Clear(); foreach (var it in File.ReadAllLines(BlockedAvatarsFilePath, Encoding.UTF8)) { var split = it.Split(new[] { '͏', ' ' }, 2, StringSplitOptions.RemoveEmptyEntries); if (split.Length == 2) { ourBlockedAvatars[split[0].Trim()] = split[1]; } } } unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(VRCAvatarManager).GetMethod( nameof(VRCAvatarManager.Method_Public_Boolean_ApiAvatar_String_Single_MulticastDelegateNPublicSealedVoGaVRBoUnique_0))) .GetValue(null); Imports.Hook((IntPtr)(&originalMethodPointer), typeof(AvatarHiding).GetMethod(nameof(SwitchAvatarPatch), BindingFlags.Static | BindingFlags.NonPublic) !.MethodHandle.GetFunctionPointer()); ourSwitchAvatar = Marshal.GetDelegateForFunctionPointer <SwitchAvatarDelegate>(originalMethodPointer); } unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(FeaturePermissionManager).GetMethods() .Single(it => it.Name.StartsWith("Method_Public_Boolean_APIUser_byref_EnumPublicSealedva5vUnique_") && it.GetCustomAttribute <CallerCountAttribute>().Count > 0)) .GetValue(null); Imports.Hook((IntPtr)(&originalMethodPointer), typeof(AvatarHiding).GetMethod(nameof(CanUseCustomAvatarPatch), BindingFlags.Static | BindingFlags.NonPublic) !.MethodHandle.GetFunctionPointer()); ourCanUseCustomAvatarDelegate = Marshal.GetDelegateForFunctionPointer <CanUseCustomAvatarDelegate>(originalMethodPointer); } }
public static unsafe IEnumerable <XrefInstance> XrefScan(MethodBase methodBase) { var fieldValue = UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(methodBase)?.GetValue(null); if (fieldValue == null) { return(Enumerable.Empty <XrefInstance>()); } XrefScanMetadataUtil.CallMetadataInitForMethod(methodBase); return(XrefScanImpl(DecoderForAddress(*(IntPtr *)(IntPtr)fieldValue))); }
public unsafe static void HookAll() { Log.Info("Creating detours for hammer attack checks..."); var hammerAttackTargetCheckPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(MeleeWeaponFirstPerson).GetMethod(nameof(MeleeWeaponFirstPerson.CheckForAttackTargets))) .GetValue(null); FastNativeDetour.CreateAndApply(hammerAttackTargetCheckPointer, OurAttackCheck, out OriginalHammerMethod, CallingConvention.Cdecl); }
public static void OnApplicationStart() { unsafe { var originalMethod = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod( typeof(ObjectInstantiator).GetMethod(nameof(ObjectInstantiator._InstantiateObject))) .GetValue(null); Imports.Hook((IntPtr)(&originalMethod), typeof(PortalHiding).GetMethod(nameof(InstantiateObjectPatch), BindingFlags.Static | BindingFlags.NonPublic) !.MethodHandle.GetFunctionPointer()); ourDelegate = Marshal.GetDelegateForFunctionPointer <InstantiateObjectDelegate>(originalMethod); } }
public static void Patch() { unsafe { var setupMethod = typeof(PlayerManager).GetMethods() .Where(method => method.Name.StartsWith("Method_Public_Static_IEnumerable_1_Player_Vector3_Single_Nullable_1_Int32_Func_2_Player_Boolean_")) .OrderBy(UnhollowerSupport.GetIl2CppMethodCallerCount).Last(); var originalMethod = *(IntPtr *)(IntPtr)UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(setupMethod).GetValue(null); MelonUtils.NativeHookAttach((IntPtr)(&originalMethod), typeof(PlayerIEnumerableSetup).GetMethod(nameof(EnumerableSetup), BindingFlags.Static | BindingFlags.Public) !.MethodHandle.GetFunctionPointer()); _playerIEnumerableSetupDelegate = Marshal.GetDelegateForFunctionPointer <PlayerIEnumerableSetupDelegate>(originalMethod); } }
private static ISupportModule Initialize() { if (Console.Enabled || Imports.IsDebugMode()) { LogSupport.InfoHandler -= System.Console.WriteLine; LogSupport.InfoHandler += MelonModLogger.Log; } LogSupport.WarningHandler -= System.Console.WriteLine; LogSupport.WarningHandler += MelonModLogger.LogWarning; LogSupport.ErrorHandler -= System.Console.WriteLine; LogSupport.ErrorHandler += MelonModLogger.LogError; if (Imports.IsDebugMode()) { LogSupport.TraceHandler -= System.Console.WriteLine; LogSupport.TraceHandler += MelonModLogger.Log; } try { unsafe { var tlsHookTarget = typeof(Uri).Assembly.GetType("Mono.Unity.UnityTls").GetMethod("GetUnityTlsInterface", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).MethodHandle.GetFunctionPointer(); var unityMethodField = UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(Il2CppMono.Unity.UnityTls).GetMethod("GetUnityTlsInterface", BindingFlags.Public | BindingFlags.Static)); var unityMethodPtr = (IntPtr)unityMethodField.GetValue(null); var unityMethod = *(IntPtr *)unityMethodPtr; Imports.Hook((IntPtr)(&tlsHookTarget), unityMethod); } } catch (Exception ex) { MelonModLogger.LogWarning("Exception while setting up TLS, mods will not be able to use HTTPS: " + ex); } ClassInjector.DoHook += Imports.Hook; GetUnityVersionNumbers(out var major, out var minor, out var patch); UnityVersionHandler.Initialize(major, minor, patch); ClassInjector.RegisterTypeInIl2Cpp <MelonLoaderComponent>(); MelonLoaderComponent.CreateComponent(); SceneManager.sceneLoaded = ( (SceneManager.sceneLoaded == null) ? new Action <Scene, LoadSceneMode>(OnSceneLoad) : Il2CppSystem.Delegate.Combine(SceneManager.sceneLoaded, (UnityAction <Scene, LoadSceneMode>) new Action <Scene, LoadSceneMode>(OnSceneLoad)).Cast <UnityAction <Scene, LoadSceneMode> >() ); Camera.onPostRender = ( (Camera.onPostRender == null) ? new Action <Camera>(OnPostRender) : Il2CppSystem.Delegate.Combine(Camera.onPostRender, (Camera.CameraCallback) new Action <Camera>(OnPostRender)).Cast <Camera.CameraCallback>() ); return(new Module()); }
public unsafe static void HookAll() { Log.Info("Patching bioscanner functions..."); var tryGetTaggableEnemiesPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(EnemyScanner).GetMethod(nameof(EnemyScanner.TryGetTaggableEnemies))) .GetValue(null); FastNativeDetour.CreateAndApply(tryGetTaggableEnemiesPointer, OurScannerMethod, out OriginalScannerMethod, CallingConvention.Cdecl); FastNativeDetour.CreateAndApply( IL2CPP.il2cpp_resolve_icall("UnityEngine.Transform::" + nameof(Transform.get_rotation_Injected)), OurGetRotation, out ourOriginalRotationGetter, CallingConvention.Cdecl); }
public static void Patch() { unsafe { var setupMethod = typeof(PageWorldInfo).GetMethods() .Where(m => m.Name.StartsWith("Method_Public_Void_ApiWorld_ApiWorldInstance_Boolean_Boolean_") && !m.Name.Contains("PDM")) .OrderBy(m => m.GetCustomAttribute <CallerCountAttribute>().Count) .Last(); // Thanks to Knah var originalMethod = *(IntPtr *)(IntPtr)UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(setupMethod).GetValue(null); MelonUtils.NativeHookAttach((IntPtr)(&originalMethod), typeof(WorldInfoSetup).GetMethod(nameof(Postfix), BindingFlags.Static | BindingFlags.Public) !.MethodHandle.GetFunctionPointer()); worldInfoSetupDelegate = Marshal.GetDelegateForFunctionPointer <WorldInfoSetupDelegate>(originalMethod); } }
public static void DoPatch() { unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod( typeof(ApiModel).GetMethods().Single(it => it.Name == nameof(ApiModel.SetApiFieldsFromJson) && it.GetParameters().Length == 2)) .GetValue(null); Imports.Hook((IntPtr)(&originalMethodPointer), typeof(ApiSnifferPatch).GetMethod(nameof(ApiSnifferStatic)) !.MethodHandle.GetFunctionPointer()); ourOriginalApiPopulate = Marshal.GetDelegateForFunctionPointer <ApiPopulateDelegate>(originalMethodPointer); } unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(ImageDownloaderClosureType.GetMethod(nameof(ImageDownloaderClosure._DownloadImageInternal_b__0))).GetValue(null); Imports.Hook((IntPtr)(&originalMethodPointer), typeof(ApiSnifferPatch).GetMethod(nameof(ImageSnifferPatch)) !.MethodHandle.GetFunctionPointer()); ourOriginalOnDone = Marshal.GetDelegateForFunctionPointer <ImageDownloaderOnDoneDelegate>(originalMethodPointer); } }
internal static unsafe bool CallMetadataInitForMethod(MethodBase method) { if (ourMetadataInitForMethodPointer == IntPtr.Zero) { FindMetadataInitForMethod(); } var nativeMethodInfoObject = UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(method)?.GetValue(null); if (nativeMethodInfoObject == null) { return(false); } var nativeMethodInfo = (IntPtr)nativeMethodInfoObject; var codeStart = *(IntPtr *)nativeMethodInfo; var firstCall = XrefScannerLowLevel.JumpTargets(codeStart).FirstOrDefault(); if (firstCall != ourMetadataInitForMethodPointer || firstCall == IntPtr.Zero) { return(false); } var tokenPointer = XrefScanUtilFinder.FindLastRcxReadAddressBeforeCallTo(codeStart, ourMetadataInitForMethodPointer); var initFlagPointer = XrefScanUtilFinder.FindByteWriteTargetRightAfterCallTo(codeStart, ourMetadataInitForMethodPointer); if (tokenPointer == IntPtr.Zero || initFlagPointer == IntPtr.Zero) { return(false); } if (Marshal.ReadByte(initFlagPointer) == 0) { ourMetadataInitForMethodDelegate(Marshal.ReadInt32(tokenPointer)); Marshal.WriteByte(initFlagPointer, 1); } return(true); }
public override void OnApplicationStart() { AdvancedSafetySettings.RegisterSettings(); var matchingMethods = typeof(AssetManagement) .GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly).Where(it => it.Name.StartsWith("Method_Public_Static_Object_Object_Vector3_Quaternion_Boolean_Boolean_Boolean_") && it.GetParameters().Length == 6).ToList(); MethodBase patchTarget = null; foreach (var methodInfo in typeof(AssetManagement).GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly)) { foreach (var it in XrefScanner.XrefScan(methodInfo)) { if (it.Type != XrefType.Method) { continue; } var methodBase = it.TryResolve(); if (methodBase == null) { continue; } if (matchingMethods.Contains(methodBase)) { patchTarget = methodBase; goto haveTarget; } } } haveTarget: if (patchTarget != null) { unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(patchTarget).GetValue(null); Imports.Hook((IntPtr)(&originalMethodPointer), typeof(AdvancedSafetyMod).GetMethod(nameof(ObjectInstantiatePatch), BindingFlags.Static | BindingFlags.NonPublic) !.MethodHandle.GetFunctionPointer()); ourOriginalInstantiate = Marshal.GetDelegateForFunctionPointer <ObjectInstantiateDelegate>(originalMethodPointer); } } else { MelonLogger.LogError("Patch target for object instantiation not found, avatar filtering will not work"); } unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(AMEnumA).GetMethod( nameof(AMEnumA.MoveNext))) .GetValue(null); Imports.Hook((IntPtr)(&originalMethodPointer), typeof(AdvancedSafetyMod).GetMethod(nameof(MoveNextPatchA), BindingFlags.Static | BindingFlags.NonPublic) !.MethodHandle.GetFunctionPointer()); ourMoveNextA = originalMethodPointer; } unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(AMEnumB).GetMethod( nameof(AMEnumB.MoveNext))) .GetValue(null); Imports.Hook((IntPtr)(&originalMethodPointer), typeof(AdvancedSafetyMod).GetMethod(nameof(MoveNextPatchB), BindingFlags.Static | BindingFlags.NonPublic) !.MethodHandle.GetFunctionPointer()); ourMoveNextB = originalMethodPointer; } unsafe { var originalMethodInfo = (Il2CppMethodInfo *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(AMEnumB).GetMethod( nameof(AMEnumB.MoveNext))) .GetValue(null); var methodInfoCopy = (Il2CppMethodInfo *)Marshal.AllocHGlobal(Marshal.SizeOf <Il2CppMethodInfo>()); * methodInfoCopy = *originalMethodInfo; ourInvokeMethodInfo = (IntPtr)methodInfoCopy; } PortalHiding.OnApplicationStart(); AvatarHiding.OnApplicationStart(); if (MelonHandler.Mods.Any(it => it.Info.SystemType.Name == nameof(UiExpansionKitMod))) { typeof(UiExpansionKitSupport).GetMethod(nameof(UiExpansionKitSupport.OnApplicationStart), BindingFlags.Static | BindingFlags.Public) !.Invoke(null, new object[0]); } }
public override void OnApplicationStart() { advInvPreferencesCategory = MelonPreferences.CreateCategory("AdvancedInvites", "Advanced Invites"); advInvPreferencesCategory.CreateEntry("DeleteNotifications", InviteHandler.DeleteNotifications, "Delete Notification After Successful Use"); advInvPreferencesCategory.CreateEntry("BlacklistEnabled", blacklistEnabled, "Blacklist System"); advInvPreferencesCategory.CreateEntry("WhitelistEnabled", whitelistEnabled, "Whitelist System"); advInvPreferencesCategory.CreateEntry("NotificationVolume", .8f, "Notification Volume"); advInvPreferencesCategory.CreateEntry("JoinMeNotifyRequest", joinMeNotifyRequest, "Join Me Req Notification Sound"); advInvPreferencesCategory.CreateEntry("IgnoreBusyStatus", ignoreBusyStatus, "Ignore Busy Status"); advInvPreferencesCategory.CreateEntry("InviteSoundEnabled", true, "Invite Sound"); advInvPreferencesCategory.CreateEntry("InviteRequestSoundEnabled", true, "Invite-Request Sound"); advInvPreferencesCategory.CreateEntry("VoteToKickSoundEnabled", false, "Vote-Kick Sound", true); advInvPreferencesCategory.CreateEntry("FriendRequestSoundEnabled", false, "Friend-Request Sound", true); OnPreferencesLoaded(); Localization.Load(); #if DEBUG DebugTesting.Test(); try { MethodInfo sendNotificationMethod = typeof(NotificationManager).GetMethod( nameof(NotificationManager.Method_Public_Void_String_String_String_String_NotificationDetails_ArrayOf_Byte_0), BindingFlags.Public | BindingFlags.Instance); Harmony.Patch(sendNotificationMethod, new HarmonyMethod( typeof(AdvancedInviteSystem).GetMethod(nameof(SendNotificationPatch), BindingFlags.NonPublic | BindingFlags.Static))); } catch (Exception e) { MelonLogger.Error("Error Patching SendNotification: " + e.Message); } #endif try { unsafe { // Appears to be NotificationManager.Method_Private_Void_Notification_1 MethodInfo acceptNotificationMethod = typeof(NotificationManager).GetMethods(BindingFlags.Public | BindingFlags.Instance).Single( m => m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(Notification) && m.XRefScanFor("AcceptNotification for notification:")); IntPtr originalMethod = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(acceptNotificationMethod).GetValue(null); MelonUtils.NativeHookAttach( (IntPtr)(&originalMethod), typeof(AdvancedInviteSystem).GetMethod(nameof(AcceptNotificationPatch), BindingFlags.Static | BindingFlags.NonPublic) !.MethodHandle .GetFunctionPointer()); acceptNotificationDelegate = Marshal.GetDelegateForFunctionPointer <AcceptNotificationDelegate>(originalMethod); } } catch (Exception e) { MelonLogger.Error("Error Patching AcceptNotification: " + e.Message); } try { //Appears to be NotificationManager.Method_Private_String_Notification_1 MethodInfo addNotificationMethod = typeof(NotificationManager).GetMethods(BindingFlags.Public | BindingFlags.Instance).Single( m => m.Name.StartsWith("Method_Private_") && m.ReturnType == typeof(string) && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(Notification) && m.XRefScanFor("imageUrl")); Harmony.Patch( addNotificationMethod, postfix: new HarmonyMethod( typeof(AdvancedInviteSystem).GetMethod(nameof(AddNotificationPatch), BindingFlags.NonPublic | BindingFlags.Static))); } catch (Exception e) { MelonLogger.Error("Error Patching AddNotification: " + e.Message); } UserPermissionHandler.LoadSettings(); WorldPermissionHandler.LoadSettings(); MelonCoroutines.Start(WaitForVrChatUiManager()); }
public FieldInfo MethodBaseToIl2CppFieldInfo(MethodBase method) => UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(method);
public override void OnApplicationStart() { AdvancedSafetySettings.RegisterSettings(); var matchingMethods = typeof(AssetManagement) .GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly).Where(it => it.Name.StartsWith("Method_Public_Static_Object_Object_Vector3_Quaternion_Boolean_Boolean_Boolean_") && it.GetParameters().Length == 6).ToList(); foreach (var matchingMethod in matchingMethods) { unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(matchingMethod).GetValue(null); ObjectInstantiateDelegate originalInstantiateDelegate = null; ObjectInstantiateDelegate replacement = (assetPtr, pos, rot, allowCustomShaders, isUI, validate, nativeMethodPointer) => ObjectInstantiatePatch(assetPtr, pos, rot, allowCustomShaders, isUI, validate, nativeMethodPointer, originalInstantiateDelegate); ourPinnedDelegates.Add(replacement); Imports.Hook((IntPtr)(&originalMethodPointer), Marshal.GetFunctionPointerForDelegate(replacement)); originalInstantiateDelegate = Marshal.GetDelegateForFunctionPointer <ObjectInstantiateDelegate>(originalMethodPointer); } } unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(AMEnumA).GetMethod( nameof(AMEnumA.MoveNext))) .GetValue(null); Imports.Hook((IntPtr)(&originalMethodPointer), typeof(AdvancedSafetyMod).GetMethod(nameof(MoveNextPatchA), BindingFlags.Static | BindingFlags.NonPublic) !.MethodHandle.GetFunctionPointer()); ourMoveNextA = originalMethodPointer; } unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(AMEnumB).GetMethod( nameof(AMEnumB.MoveNext))) .GetValue(null); Imports.Hook((IntPtr)(&originalMethodPointer), typeof(AdvancedSafetyMod).GetMethod(nameof(MoveNextPatchB), BindingFlags.Static | BindingFlags.NonPublic) !.MethodHandle.GetFunctionPointer()); ourMoveNextB = originalMethodPointer; } unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(AMEnumC).GetMethod( nameof(AMEnumC.MoveNext))) .GetValue(null); Imports.Hook((IntPtr)(&originalMethodPointer), typeof(AdvancedSafetyMod).GetMethod(nameof(MoveNextPatchC), BindingFlags.Static | BindingFlags.NonPublic) !.MethodHandle.GetFunctionPointer()); ourMoveNextC = originalMethodPointer; } unsafe { var originalMethodInfo = (Il2CppMethodInfo *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(AMEnumB).GetMethod( nameof(AMEnumB.MoveNext))) .GetValue(null); var methodInfoCopy = (Il2CppMethodInfo *)Marshal.AllocHGlobal(Marshal.SizeOf <Il2CppMethodInfo>()); * methodInfoCopy = *originalMethodInfo; ourInvokeMethodInfo = (IntPtr)methodInfoCopy; } PortalHiding.OnApplicationStart(); AvatarHiding.OnApplicationStart(harmonyInstance); if (MelonHandler.Mods.Any(it => it.Info.SystemType.Name == nameof(UiExpansionKitMod))) { typeof(UiExpansionKitSupport).GetMethod(nameof(UiExpansionKitSupport.OnApplicationStart), BindingFlags.Static | BindingFlags.Public) !.Invoke(null, new object[0]); } }
private static ISupportModule Initialize() { LogSupport.RemoveAllHandlers(); if (Console.Enabled || Imports.IsDebugMode()) { LogSupport.InfoHandler += MelonModLogger.Log; } LogSupport.WarningHandler += MelonModLogger.LogWarning; LogSupport.ErrorHandler += MelonModLogger.LogError; if (Imports.IsDebugMode()) { LogSupport.TraceHandler += MelonModLogger.Log; } try { Assembly il2cppSystem = Assembly.Load("Il2CppSystem"); if (il2cppSystem != null) { Type unitytls = il2cppSystem.GetType("Il2CppMono.Unity.UnityTls"); if (unitytls != null) { unsafe { var tlsHookTarget = typeof(Uri).Assembly.GetType("Mono.Unity.UnityTls").GetMethod("GetUnityTlsInterface", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).MethodHandle.GetFunctionPointer(); var unityMethodField = UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(unitytls.GetMethod("GetUnityTlsInterface", BindingFlags.Public | BindingFlags.Static)); var unityMethodPtr = (IntPtr)unityMethodField.GetValue(null); var unityMethod = *(IntPtr *)unityMethodPtr; Imports.Hook((IntPtr)(&tlsHookTarget), unityMethod); } } else { throw new Exception("Failed to get Type Il2CppMono.Unity.UnityTls!"); } } else { throw new Exception("Failed to get Assembly Il2CppSystem!"); } } catch (Exception ex) { MelonModLogger.LogWarning("Exception while setting up TLS, mods will not be able to use HTTPS: " + ex); } if (MelonLoader.Main.IsVRChat) { try { Assembly Transmtn = Assembly.Load("Transmtn"); if (Transmtn != null) { Type Transmtn_HttpConnection = Transmtn.GetType("Transmtn.HttpConnection"); if (Transmtn_HttpConnection != null) { Il2CppSystem_Console_WriteLine = typeof(Il2CppSystem.Console).GetMethods(BindingFlags.Public | BindingFlags.Static).First(x => (x.Name.Equals("WriteLine") && (x.GetParameters().Count() == 1) && (x.GetParameters()[0].ParameterType == typeof(string)))); if (harmonyInstance == null) { harmonyInstance = HarmonyInstance.Create("MelonLoader.Support.Il2Cpp"); } harmonyInstance.Patch(Transmtn_HttpConnection.GetMethod("get", BindingFlags.Public | BindingFlags.Instance), new HarmonyMethod(typeof(Main).GetMethod("Transmtn_HttpConnection_get_Prefix", BindingFlags.NonPublic | BindingFlags.Static)), new HarmonyMethod(typeof(Main).GetMethod("Transmtn_HttpConnection_get_Postfix", BindingFlags.NonPublic | BindingFlags.Static))); } else { throw new Exception("Failed to get Type Transmtn.HttpConnection!"); } } else { throw new Exception("Failed to get Assembly Transmtn!"); } } catch (Exception ex) { MelonModLogger.LogWarning("Exception while setting up Auth Token Hider, Auth Tokens may show in Console: " + ex); } } ClassInjector.DoHook += Imports.Hook; GetUnityVersionNumbers(out var major, out var minor, out var patch); UnityVersionHandler.Initialize(major, minor, patch); SetAsLastSiblingDelegateField = IL2CPP.ResolveICall <SetAsLastSiblingDelegate>("UnityEngine.Transform::SetAsLastSibling"); ClassInjector.RegisterTypeInIl2Cpp <MelonLoaderComponent>(); MelonLoaderComponent.Create(); SceneManager.sceneLoaded = ( (SceneManager.sceneLoaded == null) ? new Action <Scene, LoadSceneMode>(OnSceneLoad) : Il2CppSystem.Delegate.Combine(SceneManager.sceneLoaded, (UnityAction <Scene, LoadSceneMode>) new Action <Scene, LoadSceneMode>(OnSceneLoad)).Cast <UnityAction <Scene, LoadSceneMode> >() ); Camera.onPostRender = ( (Camera.onPostRender == null) ? new Action <Camera>(OnPostRender) : Il2CppSystem.Delegate.Combine(Camera.onPostRender, (Camera.CameraCallback) new Action <Camera>(OnPostRender)).Cast <Camera.CameraCallback>() ); return(new Module()); }
public override void OnApplicationStart() { AdvancedSafetySettings.RegisterSettings(); var matchingMethods = typeof(AssetManagement) .GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly).Where(it => it.Name.StartsWith("Method_Public_Static_Object_Object_Vector3_Quaternion_Boolean_Boolean_Boolean_") && it.GetParameters().Length == 6).ToList(); foreach (var matchingMethod in matchingMethods) { unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(matchingMethod).GetValue(null); ObjectInstantiateDelegate originalInstantiateDelegate = null; ObjectInstantiateDelegate replacement = (assetPtr, pos, rot, allowCustomShaders, isUI, validate, nativeMethodPointer) => ObjectInstantiatePatch(assetPtr, pos, rot, allowCustomShaders, isUI, validate, nativeMethodPointer, originalInstantiateDelegate); ourPinnedDelegates.Add(replacement); MelonUtils.NativeHookAttach((IntPtr)(&originalMethodPointer), Marshal.GetFunctionPointerForDelegate(replacement)); originalInstantiateDelegate = Marshal.GetDelegateForFunctionPointer <ObjectInstantiateDelegate>(originalMethodPointer); } } unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(AMEnumA).GetMethod( nameof(AMEnumA.MoveNext))) .GetValue(null); MelonUtils.NativeHookAttach((IntPtr)(&originalMethodPointer), typeof(AdvancedSafetyMod).GetMethod(nameof(MoveNextPatchA), BindingFlags.Static | BindingFlags.NonPublic) !.MethodHandle.GetFunctionPointer()); ourMoveNextA = originalMethodPointer; } unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(AMEnumB).GetMethod( nameof(AMEnumB.MoveNext))) .GetValue(null); MelonUtils.NativeHookAttach((IntPtr)(&originalMethodPointer), typeof(AdvancedSafetyMod).GetMethod(nameof(MoveNextPatchB), BindingFlags.Static | BindingFlags.NonPublic) !.MethodHandle.GetFunctionPointer()); ourMoveNextB = originalMethodPointer; } unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(AMEnumC).GetMethod( nameof(AMEnumC.MoveNext))) .GetValue(null); MelonUtils.NativeHookAttach((IntPtr)(&originalMethodPointer), typeof(AdvancedSafetyMod).GetMethod(nameof(MoveNextPatchC), BindingFlags.Static | BindingFlags.NonPublic) !.MethodHandle.GetFunctionPointer()); ourMoveNextC = originalMethodPointer; } unsafe { var originalMethodInfo = (Il2CppMethodInfo *)(IntPtr)UnhollowerUtils .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(AMEnumB).GetMethod( nameof(AMEnumB.MoveNext))) .GetValue(null); var methodInfoCopy = (Il2CppMethodInfo *)Marshal.AllocHGlobal(Marshal.SizeOf <Il2CppMethodInfo>()); * methodInfoCopy = *originalMethodInfo; ourInvokeMethodInfo = (IntPtr)methodInfoCopy; } foreach (ProcessModule module in Process.GetCurrentProcess().Modules) { if (!module.FileName.Contains("UnityPlayer")) { continue; } // ProduceHelper<AudioMixer,0>::Produce, thanks to Ben for finding an adjacent method ourAudioMixerReadPointer = module.BaseAddress + 0x4997C0; var patchDelegate = new AudioMixerReadDelegate(AudioMixerReadPatch); ourPinnedDelegates.Add(patchDelegate); unsafe { fixed(IntPtr *mixerReadAddress = &ourAudioMixerReadPointer) MelonUtils.NativeHookAttach((IntPtr)mixerReadAddress, Marshal.GetFunctionPointerForDelegate(patchDelegate)); ourAudioMixerReadDelegate = Marshal.GetDelegateForFunctionPointer <AudioMixerReadDelegate>(ourAudioMixerReadPointer); } break; } SceneManager.add_sceneLoaded(new Action <Scene, LoadSceneMode>((s, _) => { if (s.buildIndex == -1) { ourCanReadAudioMixers = false; MelonDebug.Msg("No reading audio mixers anymore"); } })); SceneManager.add_sceneUnloaded(new Action <Scene>(s => { if (s.buildIndex == -1) { // allow loading mixers from world assetbundles ourCanReadAudioMixers = true; MelonDebug.Msg("Can read audio mixers now"); } })); PortalHiding.OnApplicationStart(); AvatarHiding.OnApplicationStart(Harmony); if (MelonHandler.Mods.Any(it => it.Info.SystemType.Name == nameof(UiExpansionKitMod))) { typeof(UiExpansionKitSupport).GetMethod(nameof(UiExpansionKitSupport.OnApplicationStart), BindingFlags.Static | BindingFlags.Public) !.Invoke(null, new object[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(); }
public override void OnApplicationStart() { if (!CheckWasSuccessful || !MustStayTrue || MustStayFalse) { return; } AdvancedSafetySettings.RegisterSettings(); ClassInjector.RegisterTypeInIl2Cpp <SortingOrderHammerer>(); try { BundleVerifierMod.OnApplicationStart(HarmonyInstance); } catch (Exception ex) { MelonLogger.Error($"Error initializing Bundle Verifier: {ex}"); } var matchingMethods = typeof(AssetManagement) .GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly).Where(it => it.Name.StartsWith("Method_Public_Static_Object_Object_Vector3_Quaternion_Boolean_Boolean_Boolean_") && it.GetParameters().Length == 6).ToList(); foreach (var matchingMethod in matchingMethods) { ObjectInstantiateDelegate originalInstantiateDelegate = null; ObjectInstantiateDelegate replacement = (assetPtr, pos, rot, allowCustomShaders, isUI, validate, nativeMethodPointer) => ObjectInstantiatePatch(assetPtr, pos, rot, allowCustomShaders, isUI, validate, nativeMethodPointer, originalInstantiateDelegate); NativePatchUtils.NativePatch(matchingMethod, out originalInstantiateDelegate, replacement); } foreach (var nestedType in typeof(VRCAvatarManager).GetNestedTypes()) { var moveNext = nestedType.GetMethod("MoveNext"); if (moveNext == null) { continue; } var avatarManagerField = nestedType.GetProperties().SingleOrDefault(it => it.PropertyType == typeof(VRCAvatarManager)); if (avatarManagerField == null) { continue; } MelonDebug.Msg($"Patching UniTask type {nestedType.FullName}"); var fieldOffset = (int)IL2CPP.il2cpp_field_get_offset((IntPtr)UnhollowerUtils .GetIl2CppFieldInfoPointerFieldForGeneratedFieldAccessor(avatarManagerField.GetMethod) .GetValue(null)); unsafe { var originalMethodPointer = *(IntPtr *)(IntPtr)UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(moveNext).GetValue(null); originalMethodPointer = XrefScannerLowLevel.JumpTargets(originalMethodPointer).First(); VoidDelegate originalDelegate = null; void TaskMoveNextPatch(IntPtr taskPtr, IntPtr nativeMethodInfo) { var avatarManager = *(IntPtr *)(taskPtr + fieldOffset - 16); using (new AvatarManagerCookie(new VRCAvatarManager(avatarManager))) originalDelegate(taskPtr, nativeMethodInfo); } var patchDelegate = new VoidDelegate(TaskMoveNextPatch); NativePatchUtils.NativePatch(originalMethodPointer, out originalDelegate, patchDelegate); } } ReaderPatches.ApplyPatches(); SceneManager.add_sceneLoaded(new Action <Scene, LoadSceneMode>((s, _) => { if (s.buildIndex == -1) { CanReadAudioMixers = false; CanReadBadFloats = false; MelonDebug.Msg("No reading audio mixers anymore"); } })); SceneManager.add_sceneUnloaded(new Action <Scene>(s => { if (s.buildIndex == -1) { // allow loading mixers from world assetbundles CanReadAudioMixers = true; CanReadBadFloats = true; MelonDebug.Msg("Can read audio mixers now"); } })); PortalHiding.OnApplicationStart(); AvatarHiding.OnApplicationStart(HarmonyInstance); FinalIkPatches.ApplyPatches(HarmonyInstance); if (MelonHandler.Mods.Any(it => it.Info.Name == "UI Expansion Kit")) { typeof(UiExpansionKitSupport).GetMethod(nameof(UiExpansionKitSupport.OnApplicationStart), BindingFlags.Static | BindingFlags.Public) !.Invoke(null, new object[0]); } }