private static void InitializeUnityVersion() { string unityVersion = MelonUtils.GetUnityVersion(); if (string.IsNullOrEmpty(unityVersion)) { return; } string[] unityVersionSplit = unityVersion.Split('.'); int major = int.Parse(unityVersionSplit[0]); int minor = int.Parse(unityVersionSplit[1]); string patchString = unityVersionSplit[2]; char firstBadChar = patchString.FirstOrDefault(it => it <'0' || it> '9'); int patch = int.Parse(firstBadChar == 0 ? patchString : patchString.Substring(0, patchString.IndexOf(firstBadChar))); UnityVersionHandler.Initialize(major, minor, patch); }
public static void Erect(Record record) { var trampoline = Trampoline.Generate(record.FinalInitVa); unsafe { var p = (IntPtr *)Marshal.AllocHGlobal(IntPtr.Size); * p = record.FinalInitVa; MelonUtils.NativeHookAttach((IntPtr)p, trampoline.Address); var handle = trampoline.Finish(*p, Bridge); BRIDGE_INDEX.Add(handle, record); Marshal.FreeHGlobal((IntPtr)p); } }
internal static InfoStruct Contact(string response_str) { ResponseStruct responseobj = MelonUtils.ParseJSONStringtoStruct <ResponseStruct>(response_str); if (responseobj == null) { return(null); } InfoStruct returninfo = new InfoStruct(); //returninfo.ForceDumperVersion = responseobj.forceDumperVersion; returninfo.ForceUnhollowerVersion = responseobj.forceUnhollowerVersion; returninfo.ObfuscationRegex = responseobj.obfuscationRegex; returninfo.MappingURL = responseobj.mappingURL; returninfo.MappingFileSHA512 = responseobj.mappingFileSHA512; return(returninfo); }
unsafe static UIVertexWrapper() { if (NativeSignatureResolver.IsUnityVersionOverOrEqual(MelonUtils.GetUnityVersion(), new string[] { "2020.2.0", "2021.1.0" })) { mode = 2; sizeOfElement = sizeof(UIVertex_2020); } else if (NativeSignatureResolver.IsUnityVersionOverOrEqual(MelonUtils.GetUnityVersion(), new string[] { "2018.1.0" })) { mode = 1; sizeOfElement = sizeof(UIVertex_2018); } else if (NativeSignatureResolver.IsUnityVersionOverOrEqual(MelonUtils.GetUnityVersion(), new string[] { "2017.2.0" })) { mode = 0; sizeOfElement = sizeof(UIVertex_2017); } }
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); } }
private bool CheckPlatformDomainAttribute() { MelonPlatformDomainAttribute platformDomainAttribute = MelonUtils.PullAttributeFromAssembly <MelonPlatformDomainAttribute>(Assembly); if ((platformDomainAttribute == null) || (platformDomainAttribute.Domain == MelonPlatformDomainAttribute.CompatibleDomains.UNIVERSAL)) { return(true); } bool is_il2cpp_expected_mono = (MelonUtils.IsGameIl2Cpp() && (platformDomainAttribute.Domain == MelonPlatformDomainAttribute.CompatibleDomains.MONO)); bool is_mono_expected_il2cpp = (!MelonUtils.IsGameIl2Cpp() && (platformDomainAttribute.Domain == MelonPlatformDomainAttribute.CompatibleDomains.IL2CPP)); if (is_il2cpp_expected_mono || is_mono_expected_il2cpp) { MelonLogger.Error($"Incompatible Platform Domain for {(is_plugin ? "Plugin" : "Mod")}: {FilePath}"); return(false); } return(true); }
internal static int LoadAndRun(LemonFunc <int> functionToWaitForAsync) { // We don't support Unity versions under 2017.2.0 (yet?) if (!MelonLaunchOptions.Core.StartScreen || !MelonUtils.GetUnityVersion().StartsWith("20") || MelonUtils.GetUnityVersion().StartsWith("2017.1")) { return(functionToWaitForAsync()); } if (!Load()) { return(functionToWaitForAsync()); } if (LoadAndRunMethod != null) { return((int)LoadAndRunMethod.Invoke(null, new object[] { functionToWaitForAsync })); } return(-1); }
private unsafe static bool PatchIl2CppExport() { NativeLibrary il2cppLibrary = NativeLibrary.Load(Path.Combine(MelonUtils.GameDirectory, "GameAssembly.dll")); IntPtr export = il2cppLibrary.GetExport("il2cpp_unity_install_unitytls_interface"); if (export == IntPtr.Zero) { Logger.Error("Failed to find il2cpp_unity_install_unitytls_interface!"); return(false); } Logger.Msg("Patching il2cpp_unity_install_unitytls_interface..."); MethodInfo patch = typeof(Il2CppUnityTls_Module).GetMethod("SetUnityTlsInterface", BindingFlags.NonPublic | BindingFlags.Static); IntPtr patchptr = patch.MethodHandle.GetFunctionPointer(); MelonUtils.NativeHookAttach((IntPtr)(&export), patchptr); OriginalSetUnityTlsInterface = (dSetUnityTlsInterface)Marshal.GetDelegateForFunctionPointer(export, typeof(dSetUnityTlsInterface)); return(true); }
public override void Setup() { HarmonyLib.Harmony harmony = new HarmonyLib.Harmony("DemeoIntegration"); harmony.Patch(typeof(GameStateMachine).GetMethod("GetConnectionString", BindingFlags.Public | BindingFlags.Static), typeof(Demeo_Module).GetMethod("GetConnectionString", BindingFlags.NonPublic | BindingFlags.Static).ToNewHarmonyMethod()); if (MelonUtils.IsGameIl2Cpp()) { Il2Cpp.Patch(harmony); } else { Mono.Patch(harmony); } MelonCompatibilityLayer.AddRefreshPluginsEvent(Refresh); MelonCompatibilityLayer.AddRefreshModsEvent(Refresh); Refresh(); }
internal static void LoadAll(string folderpath, bool is_plugins = false) { MelonLaunchOptions.Core.LoadModeEnum loadMode = is_plugins ? MelonLaunchOptions.Core.LoadMode_Plugins : MelonLaunchOptions.Core.LoadMode_Mods; string[] filearr = Directory.GetFiles(folderpath).Where(x => Path.GetExtension(x).ToLowerInvariant().Equals(".dll") && ((loadMode == MelonLaunchOptions.Core.LoadModeEnum.DEV) ? x.ToLowerInvariant().EndsWith(".dev.dll") : ((loadMode == MelonLaunchOptions.Core.LoadModeEnum.NORMAL) ? !x.ToLowerInvariant().EndsWith(".dev.dll") : true)) ).ToArray(); if (filearr.Length <= 0) { return; } for (int i = 0; i < filearr.Length; i++) { string filepath = filearr[i]; if (string.IsNullOrEmpty(filepath)) { continue; } string melonname = MelonUtils.GetFileProductName(filepath); if (string.IsNullOrEmpty(melonname)) { melonname = Path.GetFileNameWithoutExtension(filepath); } if (is_plugins ? MelonHandler.IsPluginAlreadyLoaded(melonname) : MelonHandler.IsModAlreadyLoaded(melonname)) { MelonLogger.Error($"Duplicate File: {filepath}"); continue; } LoadFromFile(filepath); } }
private bool CheckGameVersionAttribute() { if (!is_plugin) // Temporarily Skip this Check for Plugins { return(true); } List <MelonGameVersionAttribute> gameVersionAttributes = MelonUtils.PullAttributesFromAssembly <MelonGameVersionAttribute>(Assembly).ToList(); if (gameVersionAttributes.Count <= 0) { return(true); } string game_version = GameVersionHandler.Version; bool is_compatible = false; for (int i = 0; i < gameVersionAttributes.Count; i++) { MelonGameVersionAttribute melonGameVersionAttribute = gameVersionAttributes[i]; if (melonGameVersionAttribute == null) { continue; } if (melonGameVersionAttribute.Universal || game_version.Equals(melonGameVersionAttribute.Version)) { is_compatible = true; break; } } if (!is_compatible) { //MelonLogger.Error($"Incompatible Game Version for {(is_plugin ? "Plugin" : "Mod")}: {FilePath}"); MelonLogger.Error($"Incompatible Game Version for Mod: {FilePath}"); return(false); } return(true); }
internal static void Init() { if (disabled) { return; } MelonDebug.Msg("Initializing UIStyleValues"); UIStyleValues.Init(); MelonDebug.Msg("UIStyleValues Initialized"); TextGenerationSettings settings = new TextGenerationSettings(); settings.textAnchor = TextAnchor.MiddleCenter; settings.color = new Color(1, 1, 1); settings.generationExtents = new Vector2(540, 47.5f); settings.richText = true; settings.font = UIStyleValues.standardFont; settings.pivot = new Vector2(0.5f, 0.5f); settings.fontSize = 24; settings.fontStyle = FontStyle.Bold; settings.verticalOverflow = VerticalWrapMode.Overflow; settings.scaleFactor = 1f; settings.lineSpacing = 1f; MelonDebug.Msg("TextGenerationSettings settings set"); string melonloaderText = (MelonLaunchOptions.Console.Mode == MelonLaunchOptions.Console.DisplayMode.LEMON) ? "<color=#FFCC4D>LemonLoader</color>" : "<color=#78f764>Melon</color><color=#ff3c6a>Loader</color>"; melonloaderversionTextmesh = TextMeshGenerator.Generate($"{melonloaderText} v{BuildInfo.Version} Open-Beta", settings); progressBar = new ProgressBar(width: 540, height: 36); uint graphicsDeviceType = SystemInfo.GetGraphicsDeviceType(); MelonDebug.Msg("Graphics Device Type: " + graphicsDeviceType); shouldCallWFLPAGT = NativeSignatureResolver.IsUnityVersionOverOrEqual(MelonUtils.GetUnityVersion(), new[] { "2020.2.7", "2020.3.0", "2021.1.0" }) && (graphicsDeviceType == /*DX11*/ 2 || graphicsDeviceType == /*DX12*/ 18) ? graphicsDeviceType : 0; }
private bool CheckVerifyLoaderVersionAttribute() { VerifyLoaderVersionAttribute verifyLoaderVersionAttribute = MelonUtils.PullAttributeFromAssembly <VerifyLoaderVersionAttribute>(Assembly); if (verifyLoaderVersionAttribute == null) { return(true); } bool is_acceptable = verifyLoaderVersionAttribute.IsMinimum ? (verifyLoaderVersionAttribute.SemVer <= BuildInfo.Version) : (verifyLoaderVersionAttribute.SemVer == BuildInfo.Version); if (!is_acceptable) { MelonLogger.Error($"Incompatible MelonLoader Version for {(is_plugin ? "Plugin" : "Mod")}: {FilePath}"); return(false); } return(true); }
private bool CheckPlatformDomainAttribute() { MelonPlatformDomainAttribute platformDomainAttribute = MelonUtils.PullAttributeFromAssembly <MelonPlatformDomainAttribute>(Assembly); if ((platformDomainAttribute == null) || (platformDomainAttribute.Domain == MelonPlatformDomainAttribute.CompatibleDomains.UNIVERSAL)) { return(true); } bool is_acceptable = MelonUtils.IsGameIl2Cpp() ? (platformDomainAttribute.Domain == MelonPlatformDomainAttribute.CompatibleDomains.IL2CPP) : (platformDomainAttribute.Domain == MelonPlatformDomainAttribute.CompatibleDomains.MONO); if (!is_acceptable) { MelonLogger.Error($"Incompatible Platform Domain for {(is_plugin ? "Plugin" : "Mod")}: {FilePath}"); return(false); } return(true); }
private bool CheckProcessAttributes() { List <MelonProcessAttribute> processAttributes = MelonUtils.PullAttributesFromAssembly <MelonProcessAttribute>(Assembly).ToList(); if (processAttributes.Count <= 0) { return(true); } string current_exe_path = Process.GetCurrentProcess().MainModule.FileName; string current_exe_name = Path.GetFileName(current_exe_path); string current_exe_name_no_ext = Path.GetFileNameWithoutExtension(current_exe_path); bool is_compatible = false; for (int i = 0; i < processAttributes.Count; i++) { MelonProcessAttribute melonProcessAttribute = processAttributes[i]; if (melonProcessAttribute == null) { continue; } if (melonProcessAttribute.Universal || current_exe_name.Equals(melonProcessAttribute.EXE_Name) || current_exe_name_no_ext.Equals(melonProcessAttribute.EXE_Name)) { is_compatible = true; break; } } if (!is_compatible) { MelonLogger.Error($"Incompatible Process Executable for {(is_plugin ? "Plugin" : "Mod")}: {FilePath}"); return(false); } return(true); }
static Texture2D() { InternalClassPointerStore <Texture2D> .NativeClassPtr = UnityInternals.GetClass("UnityEngine.CoreModule.dll", "UnityEngine", "Texture2D"); UnityInternals.runtime_class_init(InternalClassPointerStore <Texture2D> .NativeClassPtr); m_ctor = UnityInternals.GetMethod(InternalClassPointerStore <Texture2D> .NativeClassPtr, ".ctor", "System.Void", "System.Int32", "System.Int32"); m_get_whiteTexture = UnityInternals.GetMethod(InternalClassPointerStore <Texture2D> .NativeClassPtr, "get_whiteTexture", "UnityEngine.Texture2D"); if (NativeSignatureResolver.IsUnityVersionOverOrEqual(MelonUtils.GetUnityVersion(), new string[] { "2018.1.0" })) { type_SetPixelsImpl = 1; m_SetPixelsImpl_2018 = UnityInternals.ResolveICall <SetPixelsImplDelegate_2018>("UnityEngine.Texture2D::SetPixelsImpl"); } else if (NativeSignatureResolver.IsUnityVersionOverOrEqual(MelonUtils.GetUnityVersion(), new string[] { "2017.1.0" })) { type_SetPixelsImpl = 0; m_SetPixelsImpl_2017 = UnityInternals.ResolveICall <SetPixelsImplDelegate_2017>("UnityEngine.Texture2D::SetPixels"); } m_Apply = UnityInternals.GetMethod(InternalClassPointerStore <Texture2D> .NativeClassPtr, "Apply", "System.Void"); }
private bool CheckVerifyLoaderBuildAttribute() { VerifyLoaderBuildAttribute verifyLoaderBuildAttribute = MelonUtils.PullAttributeFromAssembly <VerifyLoaderBuildAttribute>(Assembly); if ((verifyLoaderBuildAttribute == null) || string.IsNullOrEmpty(verifyLoaderBuildAttribute.HashCode)) { return(true); } string currentHashCode = MelonUtils.HashCode; if (string.IsNullOrEmpty(currentHashCode)) { return(true); } if (!currentHashCode.Equals(verifyLoaderBuildAttribute.HashCode)) { MelonLogger.Error($"Incompatible MelonLoader Build for {(is_plugin ? "Plugin" : "Mod")}: {FilePath}"); return(false); } return(true); }
private unsafe static void RunInstallFunction() { IntPtr unityplayer = GetUnityPlayerModule(out int unityplayer_size); if (unityplayer == IntPtr.Zero) { return; } IntPtr[] ptrs = null; if (MelonUtils.IsGame32Bit()) { ptrs = GetPointers(unityplayer, unityplayer_size, Signatures_x86); } else { ptrs = GetPointers(unityplayer, unityplayer_size, Signatures_x64); } if ((ptrs == null) || (ptrs.Length <= 0)) { Logger.Warning("Unable to find Il2CppInstallUnityTlsInterface!"); return; } foreach (IntPtr ptr in ptrs) { byte *i = (byte *)ptr.ToPointer(); if (*i == 0 || (*i & 0xF) == 0xF) { continue; } Logger.Msg("Calling Il2CppInstallUnityTlsInterface..."); VoidDelegate installUnityTlsInterface = (VoidDelegate)Marshal.GetDelegateForFunctionPointer(ptr, typeof(VoidDelegate)); installUnityTlsInterface(); break; } }
internal static IntPtr GetClass(string assemblyname, string name_space, string classname) { MelonDebug.Msg($"GetClass {assemblyname} {name_space} {classname}"); if (MelonUtils.IsGameIl2Cpp()) { InternalAssembly assembly = assemblies.FirstOrDefault(a => a.name == assemblyname); if (assembly == null) { throw new Exception("Unable to find assembly " + assemblyname + " in il2cpp domain"); } IntPtr clazz = il2cpp_class_from_name(assembly.ptr, name_space, classname); if (clazz == null) { throw new Exception("Unable to find class " + name_space + "." + classname + " in assembly " + assemblyname); } MelonDebug.Msg($" > 0x{(long)clazz:X}"); return(clazz); } else { string fullname = string.IsNullOrEmpty(name_space) ? "" : (name_space + ".") + classname; Assembly ass = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().Name + ".dll" == assemblyname); if (ass == null) { throw new Exception("Unable to find assembly " + assemblyname + " in mono domain"); } Type t = ass.GetType(fullname); if (t == null) { throw new Exception("Unable to find class " + fullname + " in assembly " + assemblyname); } MelonDebug.Msg($" > 0x{(long)(*(IntPtr*)t.TypeHandle.Value):X}"); return(*(IntPtr *)t.TypeHandle.Value); } }
private unsafe static bool PatchExports() { IntPtr monolib = MonoLibrary.GetLibPtr(); if (monolib == IntPtr.Zero) { Logger.Warning("Unable to find Mono Library Pointer!"); return(false); } NativeLibrary monoLibrary = new NativeLibrary(monolib); IntPtr mono_export = monoLibrary.GetExport("mono_unity_get_unitytls_interface"); if (mono_export == IntPtr.Zero) { Logger.Warning("Unable to find Mono's mono_unity_get_unitytls_interface Export!"); return(false); } NativeLibrary il2cppLibrary = NativeLibrary.Load(Path.Combine(MelonUtils.GameDirectory, "GameAssembly.dll")); IntPtr il2cpp_export = il2cppLibrary.GetExport("il2cpp_unity_install_unitytls_interface"); if (il2cpp_export == IntPtr.Zero) { Logger.Warning("Unable to find Il2Cpp's il2cpp_unity_install_unitytls_interface Export!"); return(false); } Logger.Msg("Patching mono_unity_get_unitytls_interface..."); MelonUtils.NativeHookAttach((IntPtr)(&mono_export), typeof(Il2CppUnityTls_Module).GetMethod("GetUnityTlsInterface", BindingFlags.NonPublic | BindingFlags.Static).MethodHandle.GetFunctionPointer()); Logger.Msg("Patching il2cpp_unity_install_unitytls_interface..."); MelonUtils.NativeHookAttach((IntPtr)(&il2cpp_export), typeof(Il2CppUnityTls_Module).GetMethod("SetUnityTlsInterface", BindingFlags.NonPublic | BindingFlags.Static).MethodHandle.GetFunctionPointer()); OriginalSetUnityTlsInterface = (dSetUnityTlsInterface)Marshal.GetDelegateForFunctionPointer(il2cpp_export, typeof(dSetUnityTlsInterface)); return(true); }
public override void OnApplicationStart() { var library = LoadLibrary(MelonUtils.GetGameDataDirectory() + "\\Plugins\\steam_api64.dll"); if (library == IntPtr.Zero) { MelonLogger.LogError("Library load failed"); return; } var names = new[] { "SteamAPI_Init", "SteamAPI_RestartAppIfNecessary", "SteamAPI_GetHSteamUser", "SteamAPI_RegisterCallback", "SteamAPI_UnregisterCallback", "SteamAPI_RunCallbacks", "SteamAPI_Shutdown" }; foreach (var name in names) { unsafe { var address = GetProcAddress(library, name); if (address == IntPtr.Zero) { MelonLogger.LogError($"Procedure {name} not found"); continue; } Imports.Hook((IntPtr)(&address), AccessTools.Method(typeof(NoSteamAtAllMod), nameof(InitFail)).MethodHandle .GetFunctionPointer()); } } }
public static int class_value_size(IntPtr klass, ref uint align) => MelonUtils.IsGameIl2Cpp() ? il2cpp_class_value_size(klass, ref align) : mono_class_value_size(klass, ref align);
private static void ReadGameInfo(AssetsManager assetsManager) { string gameDataPath = MelonUtils.GetGameDataDirectory(); AssetsFileInstance instance = null; try { string bundlePath = Path.Combine(gameDataPath, "globalgamemanagers"); if (!File.Exists(bundlePath)) { bundlePath = Path.Combine(gameDataPath, "mainData"); } if (!File.Exists(bundlePath)) { bundlePath = Path.Combine(gameDataPath, "data.unity3d"); if (!File.Exists(bundlePath)) { return; } BundleFileInstance bundleFile = assetsManager.LoadBundleFile(bundlePath); instance = assetsManager.LoadAssetsFileFromBundle(bundleFile, "globalgamemanagers"); } else { instance = assetsManager.LoadAssetsFile(bundlePath, true); } if (instance == null) { return; } assetsManager.LoadIncludedClassPackage(); if (!instance.file.typeTree.hasTypeTree) { assetsManager.LoadClassDatabaseFromPackage(instance.file.typeTree.unityVersion); } EngineVersion = UnityVersion.Parse(instance.file.typeTree.unityVersion); List <AssetFileInfoEx> assetFiles = instance.table.GetAssetsOfType(129); if (assetFiles.Count > 0) { AssetFileInfoEx playerSettings = assetFiles.First(); AssetTypeInstance assetTypeInstance = null; try { assetTypeInstance = assetsManager.GetTypeInstance(instance, playerSettings); } catch (Exception ex) { if (MelonDebug.IsEnabled()) { MelonLogger.Error(ex); MelonLogger.Warning("Attempting to use Large Class Package..."); } assetsManager.LoadIncludedLargeClassPackage(); assetsManager.LoadClassDatabaseFromPackage(instance.file.typeTree.unityVersion); assetTypeInstance = assetsManager.GetTypeInstance(instance, playerSettings); } if (assetTypeInstance != null) { AssetTypeValueField playerSettings_baseField = assetTypeInstance.GetBaseField(); AssetTypeValueField bundleVersion = playerSettings_baseField.Get("bundleVersion"); if (bundleVersion != null) { GameVersion = bundleVersion.GetValue().AsString(); } AssetTypeValueField companyName = playerSettings_baseField.Get("companyName"); if (companyName != null) { GameDeveloper = companyName.GetValue().AsString(); } AssetTypeValueField productName = playerSettings_baseField.Get("productName"); if (productName != null) { GameName = productName.GetValue().AsString(); } } } } catch (Exception ex) { if (MelonDebug.IsEnabled()) { MelonLogger.Error(ex); } MelonLogger.Error("Failed to Initialize Assets Manager!"); } if (instance != null) { instance.file.Close(); } }
public override void OnApplicationStart() { var pluginsPath = MelonUtils.GetGameDataDirectory() + "/Plugins"; var dllName = ShaderFilterApi.DLLName + ".dll"; try { using var resourceStream = Assembly.GetExecutingAssembly() .GetManifestResourceStream(typeof(TrueShaderAntiCrashMod), dllName); using var fileStream = File.Open(pluginsPath + "/" + dllName, FileMode.Create, FileAccess.Write); resourceStream.CopyTo(fileStream); } catch (IOException ex) { MelonLogger.Warning("Failed to write native unity plugin; will attempt loading it anyway. This is normal if you're running multiple instances of VRChat"); MelonDebug.Msg(ex.ToString()); } var process = Process.GetCurrentProcess(); foreach (ProcessModule module in process.Modules) { if (!module.FileName.Contains("UnityPlayer")) { continue; } var loadLibraryAddress = module.BaseAddress + 0x819130; var dg = Marshal.GetDelegateForFunctionPointer <FindAndLoadUnityPlugin>(loadLibraryAddress); var strPtr = Marshal.StringToHGlobalAnsi(ShaderFilterApi.DLLName); dg(strPtr, out var loaded); if (loaded == IntPtr.Zero) { MelonLogger.Error("Module load failed"); return; } ShaderFilterApi.Init(loaded); Marshal.FreeHGlobal(strPtr); break; } var category = MelonPreferences.CreateCategory("True Shader Anticrash"); var loopsEnabled = (MelonPreferences_Entry <bool>)category.CreateEntry("LimitLoops", true, "Limit loops"); var geometryEnabled = (MelonPreferences_Entry <bool>)category.CreateEntry("LimitGeometry", true, "Limit geometry shaders"); var tessEnabled = (MelonPreferences_Entry <bool>)category.CreateEntry("LimitTesselation", true, "Limit tesselation"); MelonPreferences_Entry <bool> enabledInPublicsOnly = null; IEnumerator WaitForRoomManagerAndUpdate() { while (RoomManager.field_Internal_Static_ApiWorldInstance_0 == null) { yield return(null); } UpdateLimiters(); } void UpdateLimiters() { if (enabledInPublicsOnly.Value) { var room = RoomManager.field_Internal_Static_ApiWorldInstance_0; if (room == null) { MelonCoroutines.Start(WaitForRoomManagerAndUpdate()); return; } if (room.GetAccessType() != ApiWorldInstance.AccessType.Public) { ShaderFilterApi.SetFilteringState(false, false, false); return; } } ShaderFilterApi.SetFilteringState(loopsEnabled.Value, geometryEnabled.Value, tessEnabled.Value); } loopsEnabled.OnValueChanged += (_, value) => UpdateLimiters(); geometryEnabled.OnValueChanged += (_, value) => UpdateLimiters(); tessEnabled.OnValueChanged += (_, value) => UpdateLimiters(); var maxLoopIterations = (MelonPreferences_Entry <int>)category.CreateEntry("MaxLoopIterations", 128, "Max loop iterations"); maxLoopIterations.OnValueChanged += (_, value) => ShaderFilterApi.SetLoopLimit(value); var maxGeometry = (MelonPreferences_Entry <int>)category.CreateEntry("MaxGeometryOutputs", 60, "Max geometry shader outputs"); maxGeometry.OnValueChanged += (_, value) => ShaderFilterApi.SetLoopLimit(value); var maxTess = (MelonPreferences_Entry <float>)category.CreateEntry("MaxTesselation", 5f, "Max tesselation power"); maxTess.OnValueChanged += (_, value) => ShaderFilterApi.SetMaxTesselationPower(value); var enabledForWorlds = (MelonPreferences_Entry <bool>)category.CreateEntry("DisableDuringWorldLoad", true, "Try to avoid affecting world shaders"); enabledInPublicsOnly = (MelonPreferences_Entry <bool>)category.CreateEntry("EnabledInPublicsOnly", false, "Only enabled in public instances"); SceneManager.add_sceneLoaded(new Action <Scene, LoadSceneMode>((sc, _) => { if (sc.buildIndex == -1) { UpdateLimiters(); } })); SceneManager.add_sceneUnloaded(new Action <Scene>(_ => { if (enabledForWorlds.Value) { ShaderFilterApi.SetFilteringState(false, false, false); } })); UpdateLimiters(); ShaderFilterApi.SetMaxTesselationPower(maxTess.Value); ShaderFilterApi.SetLoopLimit(maxLoopIterations.Value); ShaderFilterApi.SetGeometryLimit(maxGeometry.Value); if (MelonHandler.Mods.Any(it => it.Assembly.GetName().Name == "UIExpansionKit" && it.Assembly.GetName().Version >= new Version(0, 2, 4))) { AddNewUixProperties(category.Identifier); } }
public static uint gchandle_new(IntPtr obj, bool pinned) => MelonUtils.IsGameIl2Cpp() ? il2cpp_gchandle_new(obj, pinned) : mono_gchandle_new(obj, pinned ? 1 : 0);
public override void OnApplicationStart() { /* Register settings */ Settings.RegisterConfig(); /* Load audio settings */ WorldAudio.LoadConfig(); /* Load avatar parameters */ Parameters.LoadConfig(); /* Load our custom UI elements */ UiExpansion.LoadUiObjects(); /* TODO: Consider switching to operator+ when everyone had to update the assembly unhollower */ /* The current solution might be prefereable so we are always first */ VRCAvatarManager.field_Private_Static_Action_3_Player_GameObject_VRC_AvatarDescriptor_0 += (Il2CppSystem.Action <Player, GameObject, VRC.SDKBase.VRC_AvatarDescriptor>)OnAvatarInstantiate; /* Register async, awaiting network manager */ MelonCoroutines.Start(RegisterJoinLeaveNotifier()); ExpansionKitApi.GetExpandedMenu(ExpandedMenu.QuickMenu).AddSimpleButton("Player List", PlayerList); ExpansionKitApi.GetExpandedMenu(ExpandedMenu.QuickMenu).AddSimpleButton("WorldCleanup", MainMenu); ExpansionKitApi.GetExpandedMenu(ExpandedMenu.UserQuickMenu).AddSimpleButton("Avatar Toggles", OnUserQuickMenu); /* Hook into setter for parameter properties */ unsafe { var param_prop_bool_set = (IntPtr)typeof(AvatarParameter).GetField("NativeMethodInfoPtr_Method_Public_Virtual_Final_New_set_Void_Boolean_0", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); MelonUtils.NativeHookAttach(param_prop_bool_set, new Action <IntPtr, bool>(Parameters.BoolPropertySetter).Method.MethodHandle.GetFunctionPointer()); Parameters._boolPropertySetterDelegate = Marshal.GetDelegateForFunctionPointer <Parameters.BoolPropertySetterDelegate>(*(IntPtr *)(void *)param_prop_bool_set); var param_prop_int_set = (IntPtr)typeof(AvatarParameter).GetField("NativeMethodInfoPtr_Method_Public_Virtual_Final_New_set_Void_Int32_0", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); MelonUtils.NativeHookAttach(param_prop_int_set, new Action <IntPtr, int>(Parameters.IntPropertySetter).Method.MethodHandle.GetFunctionPointer()); Parameters._intPropertySetterDelegate = Marshal.GetDelegateForFunctionPointer <Parameters.IntPropertySetterDelegate>(*(IntPtr *)(void *)param_prop_int_set); var param_prop_float_set = (IntPtr)typeof(AvatarParameter).GetField("NativeMethodInfoPtr_Method_Public_Virtual_Final_New_set_Void_Single_0", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); MelonUtils.NativeHookAttach(param_prop_float_set, new Action <IntPtr, float>(Parameters.FloatPropertySetter).Method.MethodHandle.GetFunctionPointer()); Parameters._floatPropertySetterDelegate = Marshal.GetDelegateForFunctionPointer <Parameters.FloatPropertySetterDelegate>(*(IntPtr *)(void *)param_prop_float_set); } AMUtils.AddToModsFolder("Player Toggles", () => { /* Filter inactive avatar objects */ s_PlayerList = s_PlayerList.Where(o => o.Value).ToDictionary(o => o.Key, o => o.Value); /* Order by physical distance to camera */ var query = from player in s_PlayerList orderby Vector3.Distance(player.Value.transform.position, Camera.main.transform.position) select player; /* Only allow a max of 10 players there at once */ /* TODO: Consider adding multiple pages */ var remaining_count = 10; foreach (var entry in query) { var manager = entry.Value.GetComponentInParent <VRCAvatarManager>(); /* Ignore SDK2 & avatars w/o custom expressions */ if (!manager.HasCustomExpressions()) { continue; } var avatar_id = entry.Value.GetComponent <VRC.Core.PipelineManager>().blueprintId; var user_icon = s_Portraits[avatar_id].Get(); /* Source default expression icon */ var menu_icons = ActionMenuDriver.prop_ActionMenuDriver_0.field_Public_MenuIcons_0; var default_expression = menu_icons.defaultExpression; CustomSubMenu.AddSubMenu(entry.Key, () => { if (entry.Value == null || !entry.Value.active) { return; } var parameters = manager.GetAllAvatarParameters(); var filtered = Parameters.FilterDefaultParameters(parameters); var avatar_descriptor = manager.prop_VRCAvatarDescriptor_0; CustomSubMenu.AddToggle("Lock", filtered.Any(Parameters.IsLocked), (state) => { filtered.ForEach(state ? Parameters.Lock : Parameters.Unlock); }, icon: UiExpansion.LockClosedIcon); CustomSubMenu.AddButton("Save", () => Parameters.StoreParameters(manager), icon: UiExpansion.SaveIcon); AvatarParameter FindParameter(string name) { foreach (var parameter in parameters) { if (parameter.field_Private_String_0 == name) { return(parameter); } } return(null); } void ExpressionSubmenu(VRCExpressionsMenu expressions_menu) { if (entry.Value == null || !entry.Value.active) { return; } void FourAxisControl(VRCExpressionsMenu.Control control, Action <Vector2> callback) { CustomSubMenu.AddFourAxisPuppet( control.TruncatedName(), callback, icon: control.icon ?? default_expression, topButtonText: control.labels[0]?.TruncatedName() ?? "Up", rightButtonText: control.labels[1]?.TruncatedName() ?? "Right", downButtonText: control.labels[2]?.TruncatedName() ?? "Down", leftButtonText: control.labels[3]?.TruncatedName() ?? "Left"); } foreach (var control in expressions_menu.controls) { try { switch (control.type) { case VRCExpressionsMenu.Control.ControlType.Button: /* Note: Action Menu "Buttons" are actually Toggles */ /* that set on press and revert on release. */ /* TODO: Add proper implementation. */ case VRCExpressionsMenu.Control.ControlType.Toggle: { var param = FindParameter(control.parameter.name); var current_value = param.GetValue(); var default_value = avatar_descriptor.expressionParameters.FindParameter(control.parameter.name)?.defaultValue ?? 0f; var target_value = control.value; void SetIntFloat(bool state) => param.SetValue(state ? target_value : default_value); void SetBool(bool state) => param.SetValue(state ? 1f : 0f); CustomSubMenu.AddToggle( control.TruncatedName(), current_value == target_value, param.prop_ParameterType_0 == AvatarParameter.ParameterType.Bool ? SetBool : SetIntFloat, icon: control.icon ?? default_expression); break; } case VRCExpressionsMenu.Control.ControlType.SubMenu: { CustomSubMenu.AddSubMenu(control.TruncatedName(), () => ExpressionSubmenu(control.subMenu), icon: control.icon ?? default_expression); break; } case VRCExpressionsMenu.Control.ControlType.TwoAxisPuppet: { var horizontal = FindParameter(control.subParameters[0]?.name); var vertical = FindParameter(control.subParameters[1]?.name); FourAxisControl(control, (value) => { horizontal.SetFloatProperty(value.x); vertical.SetFloatProperty(value.y); }); break; } case VRCExpressionsMenu.Control.ControlType.FourAxisPuppet: { var up = FindParameter(control.subParameters[0]?.name); var down = FindParameter(control.subParameters[1]?.name); var left = FindParameter(control.subParameters[2]?.name); var right = FindParameter(control.subParameters[3]?.name); FourAxisControl(control, (value) => { up.SetFloatProperty(Math.Max(0, value.y)); down.SetFloatProperty(-Math.Min(0, value.y)); left.SetFloatProperty(Math.Max(0, value.x)); right.SetFloatProperty(-Math.Min(0, value.x)); }); break; } case VRCExpressionsMenu.Control.ControlType.RadialPuppet: { var param = FindParameter(control.subParameters[0]?.name); CustomSubMenu.AddRestrictedRadialPuppet(control.TruncatedName(), param.SetValue, startingValue: param.GetValue(), icon: control.icon ?? default_expression); break; } } } catch (Exception e) { MelonLogger.Error(e.StackTrace); } } } ExpressionSubmenu(avatar_descriptor.expressionsMenu); }, icon: user_icon); if (--remaining_count == 0) { break; } } }); MelonLogger.Msg(ConsoleColor.Green, "WorldCleanup ready!"); }
static GfxDevice() { if (NativeSignatureResolver.IsUnityVersionOverOrEqual(MelonUtils.GetUnityVersion(), new[] { "2020.2.7", "2020.3.0", "2021.1.0" })) { // `FrameTimingManager_CUSTOM_CaptureFrameTimings()` calls `GetRealGfxDevice()` after 4 bytes. m_GetRealGfxDevice = (GetRealGfxDeviceDelegate)Marshal.GetDelegateForFunctionPointer( CppUtils.ResolveRelativeInstruction( (IntPtr)((long)UnityInternals.ResolveICall("UnityEngine.FrameTimingManager::CaptureFrameTimings") + (MelonUtils.IsGame32Bit() ? 0 : 4))), typeof(GetRealGfxDeviceDelegate)); } }
public static IntPtr gchandle_get_target(uint gchandle) => MelonUtils.IsGameIl2Cpp() ? il2cpp_gchandle_get_target(gchandle) : mono_gchandle_get_target(gchandle);
public static void format_stack_trace(IntPtr ex, void *output, int output_size) { if (MelonUtils.IsGameIl2Cpp()) il2cpp_format_stack_trace(ex, output, output_size); }
public static IntPtr value_box(IntPtr klass, IntPtr val) => MelonUtils.IsGameIl2Cpp() ? il2cpp_value_box(klass, val) : mono_value_box(domain, klass, val);