internal static void GatherMods() { YamlFile <GuuMod>[] modFiles = YamlUtils.GetModFiles(); SortedSet <GuuMod> loadOrder = new SortedSet <GuuMod>(new ModComparer()); // Filter what is valid and invalid for load foreach (YamlFile <GuuMod> modFile in modFiles) { GuuMod mod = modFile.Read(); // Check for mod ID if (mod.ID == null || mod.ID.Equals(string.Empty)) { GuuCore.LOGGER?.LogWarning($"Missing 'modID' key on file '{modFile.Info.FullName}' or the value is blank. Skipping mod!"); continue; } // Check if it is not example mod if (mod.ID.Equals(EXAMPLE_MOD_ID)) { GuuCore.LOGGER?.LogWarning($"Found example mod ID on file '{modFile.Info.FullName}', please change the ID of the mod. Skipping mod!"); continue; } // Check for assembly to load if (mod.AssemblyName == null || mod.AssemblyName.Equals(string.Empty)) { GuuCore.LOGGER?.LogWarning($"Missing 'assembly' key on file {modFile.Info.FullName}' or the value is blank. Skipping mod!"); continue; } // Check for guu version to see if it can be loaded if (mod.GuuVersion != null && !mod.GuuVersion.Equals(string.Empty)) { if (!ValidateVersion(mod.GuuVersion, GuuCore.GUU_VERSION)) { GuuCore.LOGGER?.LogWarning($"Guu version is outdated. Requires at least '{mod.GuuVersion}' but has '{GuuCore.GUU_VERSION}'. Skipping mod!"); continue; } } mod.Info = modFile.Info; MODS.Add(mod.ID, null); loadOrder.Add(mod); } // Loads the mods and generates their mod information foreach (GuuMod mod in loadOrder) { string modid = mod.ID; string mainAssembly = mod.AssemblyName; string version = mod.Version ?? ASSEMBLY_VERSION_TAG; bool unsafeCheck = mod.IsUnsafe; HashSet <string> required = new HashSet <string>(mod.RequiredMods); EdenHarmony harmony = new EdenHarmony(modid); // Checks if all required mods are available foreach (string req in required) { if (!MODS.ContainsKey(req)) { throw new Exception($"Missing required mod '{req}' when loading '{modid}'"); } } // Checks and loads the main assembly FileInfo assembly = new FileInfo(Path.Combine(mod.Info.Directory.FullName, mainAssembly + GuuCore.DLL_EXTENSION)); if (!assembly.Exists) { throw new Exception($"Cannot load the main assembly '{mainAssembly}' for mod '{modid}'"); } Assembly modAssembly = AssemblyUtils.LoadWithSymbols(assembly.FullName); harmony.LatePatchAll(modAssembly, !unsafeCheck ? AllowedPatchType.ALL : SAFE_PATCH); // Checks if version as {assemblyVersion} tag, and replaces it if (version.Equals(ASSEMBLY_VERSION_TAG)) { mod.Version = modAssembly.GetRuntimeVersion(); } // Obtains the ModMain Type mainType = modAssembly.GetTypes().Single(t => t.IsSubclassOf(typeof(ModMain))); ModMain main = Activator.CreateInstance(mainType) as ModMain; main.Assembly = modAssembly; main.Mod = mod; main.Logger = new ModLogger(modid); main.HarmonyInst = harmony; MOD_CONTEXTS.Add(modAssembly, new ModContext(main.Mod, main)); // Finalizes the load process MODS[modid] = main; } // Loads all modules and registers them foreach (string modid in MODS.Keys) { ModMain main = MODS[modid]; List <IModLoad> moduleMains = new List <IModLoad> { main }; foreach (ModModuleAttribute module in main.GetType().GetCustomAttributes <ModModuleAttribute>()) { string name = module.moduleName; string depID = module.dependentID; string depVer = module.dependentVersion; // Checks if dependent is available, and if so if the version matches if (!MODS.ContainsKey(depID)) { continue; } if (!ValidateVersion(depVer, MODS[depID].Mod.Version)) { continue; } // Checks and loads the assembly FileInfo assembly = new FileInfo(Path.Combine(main.Mod.Info.Directory.FullName, name + GuuCore.DLL_EXTENSION)); if (!assembly.Exists) { throw new Exception($"Trying to load module '{name}' for mod '{modid}', but it wasn't found!"); } Assembly moduleAssembly = AssemblyUtils.LoadWithSymbols(assembly.FullName); main.HarmonyInst?.LatePatchAll(moduleAssembly, !main.Mod.IsUnsafe ? AllowedPatchType.ALL : SAFE_PATCH); // Obtains the ModuleMain Type mainType = moduleAssembly.GetTypes().Single(t => t.IsSubclassOf(typeof(ModuleMain))); ModuleMain moduleMain = Activator.CreateInstance(mainType) as ModuleMain; moduleMain.Assembly = moduleAssembly; moduleMain.Main = main; MOD_CONTEXTS.Add(moduleAssembly, MOD_CONTEXTS[main.Assembly]); // Finalizes the load process for this mod's modules moduleMains.Add(moduleMain); } // Finalizes the load process for all modules main.Mod.Modules = moduleMains.ToArray(); } // Executes all late patches foreach (ModMain main in MODS.Values) { main.HarmonyInst?.ExecuteLatePatches(); } // Initializes the mods Init(); // Preloads the mods PreLoad(); // Triggers registration for all mods Register(); }
// Injects Guu into the game internal static void InjectGuu() { EdenHarmony harmony = new EdenHarmony("<internal>Guu"); harmony.PatchWrapper(typeof(GameContext_Patch)); }
//+ GUU INJECT // Loads the main system of Guu internal static void LoadGuu() { // Prevents the system from being loaded twice if (isLoaded) { LOGGER.Log(new StackTrace().ToString()); return; } //& Removes Sentry SDK from the game SentrySdk sentrySdk = Object.FindObjectOfType <SentrySdk>(); if (sentrySdk != null) { sentrySdk.Dsn = string.Empty; sentrySdk.GetType().GetField("_instance", BindingFlags.NonPublic | BindingFlags.Static)?.SetValue(null, null); sentrySdk.StopAllCoroutines(); Application.logMessageReceived -= sentrySdk.OnLogMessageReceived; Object.Destroy(sentrySdk, 1); LOGGER.Log("Game is modded! Disabling Sentry SDK"); } //& Run required system functions if (!CMD_ARGS.Contains("--guuLauncher") && !DEBUG) { Application.Quit(); } // Generate the dynamic folders if they are not present foreach (string folder in DYNAMIC_FOLDERS) { if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } } //& Starts Eden before everything else LogHandler.RegisterIfEmpty(LOGGER.Log, LOGGER.LogWarning, LOGGER.LogError, LOGGER.LogCritical); EdenUnity.Entry.EdenUnity.Init(); // Add exceptions of types EdenHarmony.RegisterMethodException("SteamDLCProvider", "*"); EdenHarmony.RegisterMethodException("EpicDLCProvider", "*"); EdenHarmony.RegisterMethodException("DLCProvider", "*"); EdenHarmony.RegisterMethodException("DLCDirector", "*"); // Add exceptions of methods EdenHarmony.RegisterMethodException <GameContext>("Awake"); // Add Name Resolve EdenHarmony.EnumNameResolve += EnumInjector.NameResolve; //& Starts the loading process and times it DateTime total = DateTime.Now; LOGGER.Log(LOG_MSEPARATOR); LOGGER.Log("GUU LOADING PROCESS STARTED"); LOGGER.Log(LOG_SEPARATOR); //& Injects all assemblies, section is timed DateTime section = DateTime.Now; LOGGER.Log("[INJECTING ASSEMBLIES]"); core = LoadAssembly(CORE_ASSEM); api = LoadAssembly(API_ASSEM); save = LoadAssembly(SAVE_ASSEM); world = LoadAssembly(WORLD_ASSEM); devTools = LoadAssembly(DEV_TOOLS_ASSEM); patches = LoadAssembly(PATCHES_ASSEM); game = Assembly.Load("Assembly-CSharp"); // Load Bridge Assemblies if (ExceptionUtils.IgnoreErrors(() => Assembly.Load(SRML_ASSEM)) != null) { srmlBridge = LoadAssembly(SRML_BRIDGE_ASSEM, "Found SRML! "); Loader.ModLoader.srmlLoaderBridge = srmlBridge.ObtainTypeByForce("LoaderBridge"); } LOGGER.Log($"[INJECTION COMPLETED] - {(DateTime.Now - section).TotalMilliseconds} ms"); LOGGER.Log(LOG_SEPARATOR); //& Patches all assemblies, section is timed section = DateTime.Now; LOGGER.Log("[PATCHING ASSEMBLIES]"); harmony = new EdenHarmony("Guu"); if (patches != null) { PatchAssembly(patches); } if (srmlBridge != null) { PatchAssembly(srmlBridge); } LOGGER.Log($"[PATCHING COMPLETED] - {(DateTime.Now - section).TotalMilliseconds} ms"); LOGGER.Log(LOG_SEPARATOR); //& Loads all asset packs, section is timed section = DateTime.Now; LOGGER.Log("[LOADING ASSET PACKS]"); guiPack = LoadPack(GUI_PACK); LOGGER.Log($"[LOADING COMPLETED] - {(DateTime.Now - section).TotalMilliseconds} ms"); LOGGER.Log(LOG_SEPARATOR); //& Loads all addon libraries section = DateTime.Now; LOGGER.Log("[LOADING ADDON LIBRARIES]"); bool hasAddons = false; DirectoryInfo addons = new DirectoryInfo(LIBS_FOLDER); foreach (FileInfo file in addons.GetFiles($"*{DLL_EXTENSION}")) { hasAddons = true; ExceptionUtils.ThrowSuccessMessage(() => { Assembly loadedLib = AssemblyUtils.LoadWithSymbols(file.FullName); ADDON_ASSEMBLIES.Add(loadedLib); Type mainType = loadedLib.GetTypes().Single(t => t.IsSubclassOf(typeof(IAddonLoad))); if (mainType == null) { return; } IAddonLoad main = Activator.CreateInstance(mainType) as IAddonLoad; main?.Initialize(); }, $"- Loaded '{file.Name}'"); } if (!hasAddons) { LOGGER.Log("- No Addons were found"); } LOGGER.Log($"[LOADING COMPLETED] - {(DateTime.Now - section).TotalMilliseconds} ms"); LOGGER.Log(LOG_SEPARATOR); //& Initializes all internal services section = DateTime.Now; LOGGER.Log("[INITIALIZING INTERNAL SERVICES]"); GuuServices.CreateServiceObject(); GuuServices.InitInternalServices(); LOGGER.Log($"[INITIALIZATION COMPLETED] - {(DateTime.Now - section).TotalMilliseconds} ms"); LOGGER.Log(LOG_SEPARATOR); //& Finalize the loading process section = DateTime.Now; LOGGER.Log("[FINALIZING]"); APIHandler.InitializeHandler(); LOGGER.Log($"[FINALIZING COMPLETED] - {(DateTime.Now - section).TotalMilliseconds} ms"); LOGGER.Log(LOG_SEPARATOR); LOGGER.Log($"SYSTEM IS FULLY OPERATIONAL - {(DateTime.Now - total).TotalMilliseconds} ms"); LOGGER.Log(LOG_MSEPARATOR); // Marks loading completed isLoaded = true; // Finalizes LOGGER.Log("Starting the Mod Loader!"); InternalLogger.HandleThrow(Loader.ModLoader.GatherMods); }