Esempio n. 1
0
        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);
        }