示例#1
0
        private static void LoadMod(Mod mod)
        {
            if (!LoadedMods.Contains(mod))
            {
                if (mod.HasTextures)
                {
                    if (!Directory.Exists(ModsPath + "/" + mod.ID + "/Textures"))
                    {
                        Directory.CreateDirectory(ModsPath + "/" + mod.ID + "/Textures");
                    }
                }

                if (mod.HasAssetBundles)
                {
                    if (!Directory.Exists(ModsPath + "/" + mod.ID + "/AssetBundles"))
                    {
                        Directory.CreateDirectory(ModsPath + "/" + mod.ID + "/AssetBundles");
                    }
                }

                mod.OnInit();
                LoadedMods.Add(mod);
                ModLogs.Log("Loaded mod " + mod.ID);
            }
            else
            {
                ModLogs.Log("Mod " + mod.ID + " already loaded.");
            }
        }
示例#2
0
        /// <summary>
        /// Load a Mod.
        /// </summary>
        /// <param name="mod">The instance of the Mod to load.</param>
        /// <param name="isInternal">If the Mod is internal or not.</param>
        private static void LoadMod(Mod mod, bool isInternal = false)
        {
            // Check if mod already exists
            if (!LoadedMods.Contains(mod))
            {
                // Generate config files
                if (!Directory.Exists(ConfigFolder + mod.ID))
                {
                    Directory.CreateDirectory(ConfigFolder + mod.ID);
                }

                // Load
                mod.OnLoad();
                LoadedMods.Add(mod);

                if (!isInternal)
                {
                    ModConsole.Print(string.Format("<color=lime><b>Mod Loaded:</b></color><color=orange><b>{0}</b></color>", mod.ID));
                }
                else
                {
                    //ModConsole.Print("Loaded internal mod: " + mod.ID); //debug
                }
            }
            else
            {
                ModConsole.Print(string.Format("<color=orange><b>Mod already loaded (or duplicated ID):</b></color><color=red><b>{0}</b></color>", mod.ID));
            }
        }
示例#3
0
        /// <summary>
        /// Load a Mod.
        /// </summary>
        /// <param name="mod">The instance of the Mod to load.</param>
        /// <param name="isInternal">If the Mod is internal or not.</param>
        private static void LoadMod(Mod mod, bool isInternal = false)
        {
            // Check if mod already exists
            if (!LoadedMods.Contains(mod))
            {
                // Generate config files
                if (!Directory.Exists(ConfigFolder + mod.ID))
                {
                    Directory.CreateDirectory(ConfigFolder + mod.ID);
                }

                // Load
                mod.OnLoad();
                LoadedMods.Add(mod);

                if (!isInternal)
                {
                    ModConsole.Print("Loaded mod: " + mod.ID);
                }
                else
                {
                    ModConsole.Print("Loaded internal mod: " + mod.ID);
                }
            }
            else
            {
                ModConsole.Print("Mod already loaded: " + mod.ID);
            }
        }
示例#4
0
 private void UnloadMod(ModInfo mod)
 {
     LoadedMods.Remove(mod.ModID);
     if (mod.ModID != null)
     {
         UnloadedMods.Add(mod.ModID, mod);
     }
     mod.Active = false;
 }
示例#5
0
        public void LoadMod(ModInfo modInfo)
        {
            if (LoadedMods.Contains(modInfo))
            {
                return;
            }

            if (!modInfo.IsBepinexMod)
            {
                return;
            }

            // Add to loaded mods already so we don't get infinite recursion
            LoadedMods.Add(modInfo);

            foreach (var dependency in modInfo.Manifest.Dependencies)
            {
                var versionless = dependency.Substring(0, dependency.LastIndexOf('-'));
                if (ModsToLoadByName.ContainsKey(dependency))
                {
                    LoadMod(ModsToLoadByName[dependency]);
                }
                else if (ModsToLoadByName.ContainsKey(versionless))
                {
                    LoadMod(ModsToLoadByName[versionless]);
                }
            }

            Logger.LogInfo($"Loading {modInfo.FullVersionName}...");
            foreach (var dllPath in Directory.GetFiles(modInfo.Path, "*.dll", SearchOption.AllDirectories))
            {
                try
                {
                    AssemblyName assemblyName = AssemblyName.GetAssemblyName(dllPath);
                    Assembly     assembly     = Assembly.Load(assemblyName);

                    foreach (Type type in assembly.GetTypes())
                    {
                        if (!type.IsInterface && !type.IsAbstract && typeof(BaseUnityPlugin).IsAssignableFrom(type))
                        {
                            Chainloader.ManagerObject.AddComponent(type);
                            Logger.LogInfo($"    Loaded plugin {type.ToString()}");
                        }
                    }
                }
                catch (BadImageFormatException) { }
                catch (ReflectionTypeLoadException ex)
                {
                    Logger.LogError($"Could not load \"{Path.GetFileName(dllPath)}\"!");
                    Logger.LogDebug(Utils.TypeLoadExceptionToString(ex));
                }
            }
        }
示例#6
0
        /// <summary>
        /// Loads the mod by searching for assemblies in hollow_knight_Data\Managed\Mods\
        /// </summary>
        public static void LoadMods()
        {
            if (Loaded)
            {
                return;
            }

            Logger.Log("[API] - Trying to load mods");
            string path = string.Empty;

            if (SystemInfo.operatingSystem.Contains("Windows"))
            {
                path = Application.dataPath + "\\Managed\\Mods";
            }
            else if (SystemInfo.operatingSystem.Contains("Mac"))
            {
                path = Application.dataPath + "/Resources/Data/Managed/Mods/";
            }
            else if (SystemInfo.operatingSystem.Contains("Linux"))
            {
                path = Application.dataPath + "/Managed/Mods";
            }
            else
            {
                Logger.LogWarn($"Operating system of {SystemInfo.operatingSystem} is not known.  Unable to load mods.");
            }

            if (string.IsNullOrEmpty(path))
            {
                Loaded = true;
                return;
            }

            foreach (string text2 in Directory.GetFiles(path, "*.dll"))
            {
                Logger.LogDebug("[API] - Loading assembly: " + text2);
                try
                {
                    foreach (Type type in Assembly.LoadFile(text2).GetExportedTypes())
                    {
                        if (IsSubclassOfRawGeneric(typeof(Mod <>), type))
                        {
                            Logger.LogDebug("[API] - Trying to instantiate mod<T>: " + type);

                            IMod mod = Activator.CreateInstance(type) as IMod;
                            if (mod == null)
                            {
                                continue;
                            }
                            LoadedMods.Add((Mod)mod);
                        }
                        else if (!type.IsGenericType && type.IsClass && type.IsSubclassOf(typeof(Mod)))
                        {
                            Logger.LogDebug("[API] - Trying to instantiate mod: " + type);
                            Mod mod2 = type.GetConstructor(new Type[0])?.Invoke(new object[0]) as Mod;
                            if (mod2 == null)
                            {
                                continue;
                            }
                            LoadedMods.Add(mod2);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogError("[API] - Error: " + ex);
                    Errors.Add(string.Concat(text2, ": FAILED TO LOAD! Check ModLog.txt."));
                }
            }

            foreach (IMod mod in LoadedMods.OrderBy(x => x.LoadPriority()))
            {
                try
                {
                    LoadMod(mod, false);
                }
                catch (Exception ex)
                {
                    Errors.Add(string.Concat(mod.GetName(), ": FAILED TO LOAD! Check ModLog.txt."));
                    Logger.LogError("[API] - Error: " + ex);
                }
            }

            //Clean out the ModEnabledSettings for any mods that don't exist.
            //Calling ToList means we are not working with the dictionary keys directly, preventing an out of sync error
            foreach (string modName in ModHooks.Instance.GlobalSettings.ModEnabledSettings.Keys.ToList())
            {
                if (LoadedMods.All(x => x.GetName() != modName))
                {
                    ModHooks.Instance.GlobalSettings.ModEnabledSettings.Remove(modName);
                }
            }


            GameObject gameObject = new GameObject();

            _draw = gameObject.AddComponent <ModVersionDraw>();
            UnityEngine.Object.DontDestroyOnLoad(gameObject);
            UpdateModText();
            Loaded = true;

            ModHooks.Instance.SaveGlobalSettings();
        }
示例#7
0
        private void ResolveModDependencies()
        {
            Manager.Info("Resolving mod dependencies...");

            //First, detect if any currently loaded mods conflict with any other loaded mods, and if so, remove it.
            //This is a bit awkward as the first step, considering that the conflict might be resolved due to
            // the other mod failing its requirements later on in the process, but I can't find an elegant way
            // to solve this.  Arbitrariness will have to do.
            foreach (var mod in LoadedMods.Values.ToList())
            {
                var conflicts = mod.ConflictingMods.Where(x => LoadedMods.ContainsKey(x));
                if (conflicts.Count() > 0)
                {
                    Manager.Warn($"Mod '{mod.ModName}' declares it is incompatible with the following mods: {conflicts.ToCSVString()}.");
                    if (CanIgnoreModConflict(mod.ModID))
                    {
                        Manager.Warn($"Due to config settings, the above conflicts are being ignored. This may cause problems.");
                    }
                    else
                    {
                        Manager.Info($"Mod '{mod.ModName}' is being unloaded due to conflict.  If this is not desired, alter the IgnoreModConflicts setting within {Constants.SettingsLocation}.");
                        UnloadMod(mod);
                    }
                }
            }

            //Next we check for cycles in the dependency graph.
            var(sorted, cycles) = GetGraph(LoadedMods.Values).TarjanSort();

            //change this to continue, unload, or fail?
            if (cycles.Count() > 0)
            {
                Manager.Warn($"Warning! One or more circular dependencies in the requested mod load order have been detected.");
                Manager.Warn("The following cycles were found:");
                List <string> errorMessages = new List <string>();
                bool          failure       = false;
                foreach (var cycle in cycles)
                {
                    var loop = cycle.Select(x => LoadedMods[x].ModName).ToList();
                    //this shows the loop a bit better in the log; instead of just [D -> E -> A], it shows [D -> E -> A -> D]
                    loop.Add(LoadedMods[cycle[0]].ModName);
                    string message = $"[{loop.ToStringList(" -> ")}]";
                    errorMessages.Add(message);
                    Manager.Warn(message);
                    failure = failure || !CanIgnoreCircularReferences(cycle);
                }

                if (failure)
                {
                    throw new CircularReferenceException($"One or more disallowed circular mod dependencies were detected: {errorMessages.ToStringList()}.  This error can be ignored by setting PermitCircularDependencies to All in the XGEF_settings.json.");
                }
                else
                {
                    Manager.Warn("Compilation will continue, but note that mod loading order is now essentially arbitrary for the affected mods.");
                }
            }

            //Lastly, now that mods have been determined to be compatible, we'll check to see if anyone is
            // missing a required mod (possibly due to flunking out of the above steps).
            var mods = LoadedMods.Values.ToList();

            for (int i = 0; i < mods.Count; i++)
            {
                var mod = mods[i];
                if (!LoadedMods.ContainsKey(mod.ModID))
                {
                    continue;
                }

                var missing = mod.RequiredMods.Except(LoadedMods.Keys);
                if (missing.Count() > 0)
                {
                    Manager.Warn($"Mod '{mod.ModName}' declares it requires the existence of the following mods: {missing.ToCSVString()}.");
                    if (CanIgnoreModRequirement(mod.ModID))
                    {
                        Manager.Warn($"Due to config settings, the above missing requirements are being ignored. This may cause problems.");
                    }
                    else
                    {
                        Manager.Warn($"Mod '{mod.ModName}' is being unloaded due to missing requirements.  If this is not desired, alter the IgnoreModRequirements setting within {Constants.SettingsLocation}.");
                        UnloadMod(mod);
                        //if a mod is removed, there's a possibility that another mod becomes invalidated because of it.
                        //thus, we start the entire loop over again.
                        i = 0;
                    }
                }
            }
        }