internal static void Initialize() { try { string basedir = Path.Combine(Path.Combine(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "MelonLoader"), "Dependencies"), "SupportModules"); string filepath = null; if (Imports.IsIl2CppGame()) { filepath = Path.Combine(basedir, "MelonLoader.Support.Il2Cpp.dll"); } else { if (File.Exists(Path.Combine(Imports.GetAssemblyDirectory(), "UnityEngine.CoreModule.dll"))) { filepath = Path.Combine(basedir, "MelonLoader.Support.Mono.dll"); } else { if (IsOldUnity()) { filepath = Path.Combine(basedir, "MelonLoader.Support.Mono.Pre2017.2.dll"); } else { filepath = Path.Combine(basedir, "MelonLoader.Support.Mono.Pre2017.dll"); } } } if (File.Exists(filepath)) { byte[] data = File.ReadAllBytes(filepath); if (data.Length > 0) { assembly = Assembly.Load(data); if (!assembly.Equals(null)) { type = assembly.GetType("MelonLoader.Support.Main"); if (!type.Equals(null)) { MethodInfo method = type.GetMethod("Initialize", BindingFlags.NonPublic | BindingFlags.Static); if (!method.Equals(null)) { supportModule = (ISupportModule)method.Invoke(null, new object[0]); } } } } } else { MelonModLogger.LogError("Unable to load Support Module! Support Module is Missing!"); MelonModLogger.Log("------------------------------"); } } catch (Exception e) { MelonModLogger.LogError("Unable to load Support Module!\n" + e.ToString()); MelonModLogger.Log("------------------------------"); } }
private static void LoadModFromAssembly(Assembly assembly, string filelocation = null) { MelonModInfoAttribute modInfoAttribute = assembly.GetCustomAttributes(false).FirstOrDefault(x => (x.GetType() == typeof(MelonModInfoAttribute))) as MelonModInfoAttribute; if ((modInfoAttribute != null) && (modInfoAttribute.SystemType != null) && modInfoAttribute.SystemType.IsSubclassOf(typeof(MelonMod))) { bool isCompatible = false; bool isUniversal = false; bool hasAttribute = true; MelonModGameAttribute[] modGameAttributes = assembly.GetCustomAttributes(typeof(MelonModGameAttribute), true) as MelonModGameAttribute[]; int modGameAttributes_Count = modGameAttributes.Length; if (modGameAttributes_Count > 0) { for (int i = 0; i < modGameAttributes_Count; i++) { MelonModGameAttribute modGameAttribute = modGameAttributes[i]; if (CurrentGameAttribute.IsCompatible(modGameAttribute)) { isCompatible = true; isUniversal = CurrentGameAttribute.IsCompatibleBecauseUniversal(modGameAttribute); break; } } } else { hasAttribute = false; } try { MelonMod modInstance = Activator.CreateInstance(modInfoAttribute.SystemType) as MelonMod; if (modInstance != null) { modInstance.InfoAttribute = modInfoAttribute; if (modGameAttributes_Count > 0) { modInstance.GameAttributes = modGameAttributes; } else { modInstance.GameAttributes = null; } modInstance.Location = filelocation; modInstance.Compatibility = (isUniversal ? MelonBase.MelonCompatibility.UNIVERSAL : (isCompatible ? MelonBase.MelonCompatibility.COMPATIBLE : (!hasAttribute ? MelonBase.MelonCompatibility.NOATTRIBUTE : MelonBase.MelonCompatibility.INCOMPATIBLE))); if (modInstance.Compatibility < MelonBase.MelonCompatibility.INCOMPATIBLE) { modInstance.Assembly = assembly; } Mods.Add(modInstance); } else { MelonModLogger.LogError("Unable to load Mod in " + assembly.GetName() + "! Failed to Create Instance!"); } } catch (Exception e) { MelonModLogger.LogError("Unable to load Mod in " + assembly.GetName() + "! " + e.ToString()); } } }
public static bool GetBool(string section, string name) { if (prefs.TryGetValue(section, out Dictionary <string, PrefDesc> prefsInSection) && prefsInSection.TryGetValue(name, out PrefDesc pref)) { return(pref.Value.Equals("true") || pref.Value.Equals("1")); } MelonModLogger.LogError("Trying to get unregistered Pref " + section + ":" + name); return(false); }
public static string GetString(string section, string name) { if (prefs.TryGetValue(section, out Dictionary <string, PrefDesc> prefsInSection) && prefsInSection.TryGetValue(name, out PrefDesc pref)) { return(pref.Value); } MelonModLogger.LogError("Trying to get unregistered Pref " + section + ":" + name); return(""); }
private static void LoadAssembly(Assembly asm, bool isPlugin = false) { if (!asm.Equals(null)) { LoadModFromAssembly(asm, isPlugin); } else { MelonModLogger.LogError("Unable to load " + asm); } }
private static void LoadAssembly(Assembly asm, bool isPlugin = false, string filelocation = null) { if (!asm.Equals(null)) { LoadDLLFromAssembly(asm, isPlugin, filelocation); } else { MelonModLogger.LogError("Unable to load " + asm); } }
public static void SetString(string section, string name, string value) { if (prefs.TryGetValue(section, out Dictionary <string, PrefDesc> prefsInSection) && prefsInSection.TryGetValue(name, out PrefDesc pref)) { pref.Value = pref.ValueEdited = value; ModPrefsController.SetString(section, name, value); } else { MelonModLogger.LogError("Trying to save unknown pref " + section + ":" + name); } }
public static float GetFloat(string section, string name) { if (prefs.TryGetValue(section, out Dictionary <string, PrefDesc> prefsInSection) && prefsInSection.TryGetValue(name, out PrefDesc pref)) { if (float.TryParse(pref.Value, out float valueF)) { return(valueF); } } MelonModLogger.LogError("Trying to get unregistered Pref " + section + ":" + name); return(0.0f); }
// Returns true if 'assembly' was already loaded or could be loaded, false if the required assembly was missing. private static bool TryLoad(AssemblyName assembly) { try { Assembly.Load(assembly); return(true); } catch (FileNotFoundException) { return(false); } catch (Exception ex) { MelonModLogger.LogError("Loading mod dependency failed: " + ex); return(false); } }
private static void LoadAssembly(byte[] data, bool preload = false) { Assembly asm = Assembly.Load(data); if (!asm.Equals(null)) { LoadModFromAssembly(asm, preload); } else { MelonModLogger.LogError("Unable to load " + asm); } }
private static void RegisterPref(string section, string name, string defaultValue, string displayText, PrefType type, bool hideFromList) { if (prefs.TryGetValue(section, out Dictionary <string, PrefDesc> prefsInSection)) { if (prefsInSection.TryGetValue(name, out PrefDesc pref)) { MelonModLogger.LogError("Trying to registered Pref " + section + ":" + name + " more than one time"); } else { string toStoreValue = defaultValue; if (ModPrefsController.HasKey(section, name)) { toStoreValue = ModPrefsController.GetString(section, name, defaultValue); } else { ModPrefsController.SetString(section, name, defaultValue); } prefsInSection.Add(name, new PrefDesc(toStoreValue, type, hideFromList, (displayText ?? "") == "" ? name : displayText)); } } else { Dictionary <string, PrefDesc> dic = new Dictionary <string, PrefDesc>(); string toStoreValue = defaultValue; if (ModPrefsController.HasKey(section, name)) { toStoreValue = ModPrefsController.GetString(section, name, defaultValue); } else { ModPrefsController.SetString(section, name, defaultValue); } dic.Add(name, new PrefDesc(toStoreValue, type, hideFromList, (displayText ?? "") == "" ? name : displayText)); prefs.Add(section, dic); } }
private static void LoadModsFromAssembly(Assembly assembly) { MelonModInfoAttribute modInfoAttribute = assembly.GetCustomAttribute(typeof(MelonModInfoAttribute)) as MelonModInfoAttribute; if ((modInfoAttribute != null) && (modInfoAttribute.ModType != null) && modInfoAttribute.ModType.IsSubclassOf(typeof(MelonMod))) { MelonModLogger.Log(modInfoAttribute.Name + (!string.IsNullOrEmpty(modInfoAttribute.Version) ? (" v" + modInfoAttribute.Version) : "") + (!string.IsNullOrEmpty(modInfoAttribute.Author) ? (" by " + modInfoAttribute.Author) : "") + (!string.IsNullOrEmpty(modInfoAttribute.DownloadLink) ? (" (" + modInfoAttribute.DownloadLink + ")") : "")); bool should_continue = false; bool isUniversal = false; MelonModGameAttribute[] modGameAttributes = assembly.GetCustomAttributes(typeof(MelonModGameAttribute), true) as MelonModGameAttribute[]; int modGameAttributes_Count = modGameAttributes.Length; if (modGameAttributes_Count > 0) { for (int i = 0; i < modGameAttributes_Count; i++) { MelonModGameAttribute modGameAttribute = modGameAttributes[i]; if (CurrentGameAttribute.IsCompatible(modGameAttribute)) { isUniversal = CurrentGameAttribute.IsCompatibleBecauseUniversal(modGameAttribute); should_continue = true; break; } } } else { isUniversal = true; should_continue = true; } if (should_continue) { try { MelonMod modInstance = Activator.CreateInstance(modInfoAttribute.ModType) as MelonMod; if (modInstance != null) { modInstance.IsUniversal = isUniversal; modInstance.InfoAttribute = modInfoAttribute; if (modGameAttributes_Count > 0) { modInstance.GameAttributes = modGameAttributes; } else { modInstance.GameAttributes = null; } Mods.Add(modInstance); MelonModLogger.LogModStatus((modGameAttributes_Count > 0) ? (isUniversal ? 0 : 1) : 2); } else { MelonModLogger.LogError("Unable to load Mod in " + assembly.GetName() + "! Failed to Create Instance!"); } } catch (Exception e) { MelonModLogger.LogError("Unable to load Mod in " + assembly.GetName() + "! " + e.ToString()); } } else { MelonModLogger.LogModStatus(3); } } }
private static void Initialize() { CurrentGameAttribute = new MelonModGameAttribute(Imports.GetCompanyName(), Imports.GetProductName()); if (Imports.IsIl2CppGame()) { Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); IsVRChat = CurrentGameAttribute.IsGame("VRChat", "VRChat"); IsBoneworks = CurrentGameAttribute.IsGame("Stress Level Zero", "BONEWORKS"); } if (!Imports.IsDebugMode() #if !DEBUG && Environment.CommandLine.Contains("--melonloader.console") #endif ) { MelonModLogger.consoleEnabled = true; Console.Create(); } MelonModLogger.Log("------------------------------"); MelonModLogger.Log("Unity " + Imports.GetUnityVersion()); MelonModLogger.Log("Developer: " + CurrentGameAttribute.Developer); MelonModLogger.Log("GameName: " + CurrentGameAttribute.GameName); MelonModLogger.Log("------------------------------"); MelonModLogger.Log("Using v" + BuildInfo.Version + " Open-Beta"); MelonModLogger.Log("------------------------------"); if (Imports.IsIl2CppGame()) { MelonModLogger.Log("Initializing NET_SDK..."); NET_SDK.SDK.Initialize(); MelonModLogger.Log("------------------------------"); } bool no_mods = false; string modDirectory = Path.Combine(Environment.CurrentDirectory, "Mods"); if (!Directory.Exists(modDirectory)) { Directory.CreateDirectory(modDirectory); no_mods = true; } else { string[] files = Directory.GetFiles(modDirectory, "*.dll"); if (files.Length > 0) { foreach (string s in files) { if (!File.Exists(s) || !s.EndsWith(".dll", true, null)) { return; } try { byte[] data = File.ReadAllBytes(s); if (data.Length > 0) { Assembly a = Assembly.Load(data); if (a != null) { LoadModsFromAssembly(a); } else { MelonModLogger.LogError("Unable to load " + s); } } else { MelonModLogger.LogError("Unable to load " + s); } } catch (Exception e) { MelonModLogger.LogError("Unable to load " + s + ":\n" + e.ToString()); } MelonModLogger.Log("------------------------------"); } if (Mods.Count() <= 0) { no_mods = true; } } else { no_mods = true; } } if (no_mods) { MelonModLogger.Log("No Mods Loaded!"); MelonModLogger.Log("------------------------------"); } else { MelonModComponent.Create(); } }
private static void ExceptionHandler(object sender, UnhandledExceptionEventArgs e) => MelonModLogger.LogError((e.ExceptionObject as Exception).ToString());
private void TopologicalSortInto(IList <T> loadedMods) { int[] unloadedDependencies = new int[vertices.Length]; SortedList <string, Vertex> loadableMods = new SortedList <string, Vertex>(); int skippedMods = 0; // Find all sinks in the dependency graph, i.e. mods without any dependencies on other mods for (int i = 0; i < vertices.Length; ++i) { Vertex vertex = vertices[i]; int dependencyCount = vertex.dependencies.Count; unloadedDependencies[i] = dependencyCount; if (dependencyCount == 0) { loadableMods.Add(vertex.name, vertex); } } // Perform the (reverse) topological sorting while (loadableMods.Count > 0) { Vertex mod = loadableMods.Values[0]; loadableMods.RemoveAt(0); if (!mod.skipLoading) { loadedMods.Add(mod.mod); } else { ++skippedMods; } foreach (Vertex dependent in mod.dependents) { unloadedDependencies[dependent.index] -= 1; dependent.skipLoading |= mod.skipLoading; if (unloadedDependencies[dependent.index] == 0) { loadableMods.Add(dependent.name, dependent); } } } // Check if all mods were either loaded or skipped. If this is not the case, there is a cycle in the dependency graph if (loadedMods.Count + skippedMods < vertices.Length) { StringBuilder errorMessage = new StringBuilder("Some mods could not be loaded due to a cyclic dependency:\n"); for (int i = 0; i < vertices.Length; ++i) { if (unloadedDependencies[i] > 0) { errorMessage.Append($"- '{vertices[i].name}'\n"); } } errorMessage.Length -= 1; // Remove trailing newline MelonModLogger.LogError(errorMessage.ToString()); } }
private static void LoadDLLs(bool plugins = false) { string searchdir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, (plugins ? "Plugins" : "Mods")); if (!Directory.Exists(searchdir)) { Directory.CreateDirectory(searchdir); } else { // DLL string[] files = Directory.GetFiles(searchdir, "*.dll"); if (files.Length > 0) { for (int i = 0; i < files.Count(); i++) { string file = files[i]; if (!string.IsNullOrEmpty(file)) { if (plugins) { if ((Imports.IsDevPluginsOnly() && !file.EndsWith("-dev.dll")) || (!Imports.IsDevPluginsOnly() && file.EndsWith("-dev.dll"))) { continue; } } else { if ((Imports.IsDevModsOnly() && !file.EndsWith("-dev.dll")) || (!Imports.IsDevModsOnly() && file.EndsWith("-dev.dll"))) { continue; } } try { LoadAssembly(File.ReadAllBytes(file), plugins, file); } catch (Exception e) { MelonModLogger.LogError("Unable to load " + file + ":\n" + e.ToString()); MelonModLogger.Log("------------------------------"); } } } } // ZIP string[] zippedFiles = Directory.GetFiles(searchdir, "*.zip"); if (zippedFiles.Length > 0) { for (int i = 0; i < zippedFiles.Count(); i++) { string file = zippedFiles[i]; if (!string.IsNullOrEmpty(file)) { try { using (var fileStream = File.OpenRead(file)) { using (var zipInputStream = new ZipInputStream(fileStream)) { ZipEntry entry; while ((entry = zipInputStream.GetNextEntry()) != null) { string filename = Path.GetFileName(entry.Name); if (string.IsNullOrEmpty(filename) || !filename.EndsWith(".dll")) { continue; } if (plugins) { if ((Imports.IsDevPluginsOnly() && !filename.EndsWith("-dev.dll")) || (!Imports.IsDevPluginsOnly() && filename.EndsWith("-dev.dll"))) { continue; } } else { if ((Imports.IsDevModsOnly() && !filename.EndsWith("-dev.dll")) || (!Imports.IsDevModsOnly() && filename.EndsWith("-dev.dll"))) { continue; } } using (var unzippedFileStream = new MemoryStream()) { int size = 0; byte[] buffer = new byte[4096]; while (true) { size = zipInputStream.Read(buffer, 0, buffer.Length); if (size > 0) { unzippedFileStream.Write(buffer, 0, size); } else { break; } } LoadAssembly(unzippedFileStream.ToArray(), plugins, (file + "/" + filename)); } } } } } catch (Exception e) { MelonModLogger.LogError("Unable to load " + file + ":\n" + e.ToString()); MelonModLogger.Log("------------------------------"); } } } } } }
private static void LoadMods(bool preload = false) { string modDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Path.Combine("Mods", (preload ? "PRELOAD" : ""))); if (!Directory.Exists(modDirectory)) { Directory.CreateDirectory(modDirectory); } else { // DLL string[] files = Directory.GetFiles(modDirectory, "*.dll", SearchOption.TopDirectoryOnly); if (files.Length > 0) { for (int i = 0; i < files.Count(); i++) { string file = files[i]; if (!string.IsNullOrEmpty(file)) { try { byte[] data = File.ReadAllBytes(file); if (data.Length > 0) { LoadAssembly(data, preload); } else { MelonModLogger.LogError("Unable to load " + file); MelonModLogger.Log("------------------------------"); } } catch (Exception e) { MelonModLogger.LogError("Unable to load " + file + ":\n" + e.ToString()); MelonModLogger.Log("------------------------------"); } } } } // ZIP /* * string[] zippedFiles = Directory.GetFiles(modDirectory, "*.zip", SearchOption.TopDirectoryOnly); * if (zippedFiles.Length > 0) * { * for (int i = 0; i < zippedFiles.Count(); i++) * { * string file = zippedFiles[i]; * if (!string.IsNullOrEmpty(file)) * { * try * { * using (var fileStream = File.OpenRead(file)) * { * using (var zipInputStream = new ZipInputStream(fileStream)) * { * ZipEntry entry; * while ((entry = zipInputStream.GetNextEntry()) != null) * { * if ((Path.GetFileName(entry.Name).Length <= 0) || !Path.GetFileName(entry.Name).EndsWith(".dll")) * continue; * * using (var unzippedFileStream = new MemoryStream()) * { * int size = 0; * byte[] buffer = new byte[4096]; * while (true) * { * size = zipInputStream.Read(buffer, 0, buffer.Length); * if (size > 0) * unzippedFileStream.Write(buffer, 0, size); * else * break; * } * LoadAssembly(unzippedFileStream.ToArray(), preload); * } * } * } * } * } * catch (Exception e) * { * MelonModLogger.LogError("Unable to load " + file + ":\n" + e.ToString()); * MelonModLogger.Log("------------------------------"); * } * } * } * } */ } }
private static void LoadModFromAssembly(Assembly assembly, bool isPlugin = false) { MelonModInfoAttribute modInfoAttribute = assembly.GetCustomAttributes(false).FirstOrDefault(x => (x.GetType() == typeof(MelonModInfoAttribute))) as MelonModInfoAttribute; if ((modInfoAttribute != null) && (modInfoAttribute.ModType != null) && modInfoAttribute.ModType.IsSubclassOf(typeof(MelonMod))) { bool should_continue = false; bool isUniversal = false; MelonModGameAttribute[] modGameAttributes = assembly.GetCustomAttributes(typeof(MelonModGameAttribute), true) as MelonModGameAttribute[]; int modGameAttributes_Count = modGameAttributes.Length; if (modGameAttributes_Count > 0) { for (int i = 0; i < modGameAttributes_Count; i++) { MelonModGameAttribute modGameAttribute = modGameAttributes[i]; if (CurrentGameAttribute.IsCompatible(modGameAttribute)) { isUniversal = CurrentGameAttribute.IsCompatibleBecauseUniversal(modGameAttribute); should_continue = true; break; } } } else { isUniversal = true; should_continue = true; } if (should_continue) { try { MelonMod modInstance = Activator.CreateInstance(modInfoAttribute.ModType) as MelonMod; if (modInstance != null) { modInstance.IsUniversal = isUniversal; modInstance.IsPlugin = isPlugin; modInstance.InfoAttribute = modInfoAttribute; if (modGameAttributes_Count > 0) { modInstance.GameAttributes = modGameAttributes; } else { modInstance.GameAttributes = null; } modInstance.ModAssembly = assembly; Harmony.HarmonyInstance.Create(assembly.FullName).PatchAll(assembly); Mods.Add(modInstance); } else { MelonModLogger.LogError("Unable to load Mod in " + assembly.GetName() + "! Failed to Create Instance!"); } } catch (Exception e) { MelonModLogger.LogError("Unable to load Mod in " + assembly.GetName() + "! " + e.ToString()); } } else { MelonModLogger.LogModStatus(3); } } }
private static IEnumerable <Type> GetLoadableTypes(Assembly assembly) { if (assembly == null) { throw new ArgumentNullException(nameof(assembly)); } try { return(assembly.GetTypes()); } catch (ReflectionTypeLoadException e) { MelonModLogger.LogError("An Error occured while getting Types from Assembly " + assembly.GetName().Name + ". Returning Types from Error.\n" + e); return(e.Types.Where(t => t != null)); } }