internal static void LoadMod(IMod mod, bool updateModText) { ModHooks.Instance.GlobalSettings.ModEnabledSettings[mod.GetName()] = true; mod.Initialize(); if (!ModHooks.Instance.LoadedModsWithVersions.ContainsKey(mod.GetType().Name)) { ModHooks.Instance.LoadedModsWithVersions.Add(mod.GetType().Name, mod.GetVersion()); } else { ModHooks.Instance.LoadedModsWithVersions[mod.GetType().Name] = mod.GetVersion(); } if (ModHooks.Instance.LoadedMods.All(x => x != mod.GetType().Name)) { ModHooks.Instance.LoadedMods.Add(mod.GetType().Name); } if (updateModText) { UpdateModText(); } }
private void SetInstances(IMod mod) { var fieldInstances = from field in mod.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static) where field.GetCustomAttributes(typeof(InstanceAttribute), false).Any() select field; foreach (var instanceMember in fieldInstances) { Type instanceType = instanceMember.FieldType; IMod instanceMod = CreateOrGetAllMods().SingleOrDefault(m => m.GetType() == instanceType); if (instanceMod != null) { instanceMember.SetValue(mod, instanceMod); } } var propertyInstances = from property in mod.GetType().GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static) where property.GetCustomAttributes(typeof(InstanceAttribute), false).Any() select property; foreach (var instanceMember in propertyInstances) { Type instanceType = instanceMember.PropertyType; IMod instanceMod = CreateOrGetAllMods().SingleOrDefault(m => m.GetType() == instanceType); if (instanceMod != null) { instanceMember.SetValue(mod, mod, null); } } }
/// <summary> /// Register mod, if not already registered /// </summary> /// <param name="mod">Mod to be registered</param> public static void RegisterMod(IMod mod) { if (loadedModTypes.Contains(mod.GetType())) { return; } RegisterItems(mod.RegisterItems()); RegisterRecipes(mod.RegisterRecipes()); loadedModTypes.Add(mod.GetType()); }
public ModSaveData GetDataFor(IMod mod) { ModSaveData result; if (modSaveData.TryGetValue(mod, out result)) { return(result); } var textKey = mod.GetType().FullName; if (unloadedSaveData.TryGetValue(textKey, out result)) { throw new Exception("This should never happen!"); /* #warning this should actually never happen anymore, since we look up existing mods while loading anyway. * unloadedSaveData.Remove(textKey); * modSaveData.Add(mod, result); * return result; */ } result = new ModSaveData(mod); modSaveData.Add(mod, result); allSaveData.Add(result); return(result); }
private void HookUpEvents(IMod mod) { // Get all event listeners from mod var eventMethods = (from method in mod.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public) where method.GetCustomAttributes(typeof(EventListenerAttribute), false).Any() select method).ToList(); HookUpEvents(mod, eventMethods); }
public static void LoadFor(IMod mod) { var optionType = mod.GetType().GetFirstAttribute <ModOptionsAttribute>()?.ModOptionsType; if (optionType == null) { return; } var options = (AbstractOptions)Activator.CreateInstance(optionType); ModOptions.Add(mod.GetCleanId(), options); }
private void LoadMods(IModMetadata[] mods, JsonHelper jsonHelper, SContentManager contentManager) #endif { #if SMAPI_1_x this.Monitor.Log("Loading mods..."); #else this.Monitor.Log("Loading mods...", LogLevel.Trace); #endif // load mod assemblies IDictionary <IModMetadata, string> skippedMods = new Dictionary <IModMetadata, string>(); { void TrackSkip(IModMetadata mod, string reasonPhrase) => skippedMods[mod] = reasonPhrase; AssemblyLoader modAssemblyLoader = new AssemblyLoader(Constants.TargetPlatform, this.Monitor); AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => modAssemblyLoader.ResolveAssembly(e.Name); foreach (IModMetadata metadata in mods) { // get basic info IManifest manifest = metadata.Manifest; string assemblyPath = metadata.Manifest?.EntryDll != null ? Path.Combine(metadata.DirectoryPath, metadata.Manifest.EntryDll) : null; this.Monitor.Log(assemblyPath != null ? $"Loading {metadata.DisplayName} from {assemblyPath.Replace(Constants.ModPath, "").TrimStart(Path.DirectorySeparatorChar)}..." : $"Loading {metadata.DisplayName}...", LogLevel.Trace); // validate status if (metadata.Status == ModMetadataStatus.Failed) { this.Monitor.Log($" Failed: {metadata.Error}", LogLevel.Trace); TrackSkip(metadata, metadata.Error); continue; } // preprocess & load mod assembly Assembly modAssembly; try { modAssembly = modAssemblyLoader.Load(assemblyPath, assumeCompatible: metadata.Compatibility?.Compatibility == ModCompatibilityType.AssumeCompatible); } catch (IncompatibleInstructionException ex) { #if SMAPI_1_x TrackSkip(metadata, $"it's not compatible with the latest version of the game or SMAPI (detected {ex.NounPhrase}). Please check for a newer version of the mod."); #else TrackSkip(metadata, $"it's no longer compatible (detected {ex.NounPhrase}). Please check for a newer version of the mod."); #endif continue; } catch (Exception ex) { TrackSkip(metadata, $"its DLL '{manifest.EntryDll}' couldn't be loaded:\n{ex.GetLogSummary()}"); continue; } // validate assembly try { int modEntries = modAssembly.DefinedTypes.Count(type => typeof(Mod).IsAssignableFrom(type) && !type.IsAbstract); if (modEntries == 0) { TrackSkip(metadata, $"its DLL has no '{nameof(Mod)}' subclass."); continue; } if (modEntries > 1) { TrackSkip(metadata, $"its DLL contains multiple '{nameof(Mod)}' subclasses."); continue; } } catch (Exception ex) { TrackSkip(metadata, $"its DLL couldn't be loaded:\n{ex.GetLogSummary()}"); continue; } // initialise mod try { // get implementation TypeInfo modEntryType = modAssembly.DefinedTypes.First(type => typeof(Mod).IsAssignableFrom(type) && !type.IsAbstract); Mod mod = (Mod)modAssembly.CreateInstance(modEntryType.ToString()); if (mod == null) { TrackSkip(metadata, "its entry class couldn't be instantiated."); continue; } #if SMAPI_1_x // prevent mods from using SMAPI 2.0 content interception before release // ReSharper disable SuspiciousTypeConversion.Global if (mod is IAssetEditor || mod is IAssetLoader) { TrackSkip(metadata, $"its entry class implements {nameof(IAssetEditor)} or {nameof(IAssetLoader)}. These are part of a prototype API that isn't available for mods to use yet."); } // ReSharper restore SuspiciousTypeConversion.Global #endif // inject data { IMonitor monitor = this.GetSecondaryMonitor(metadata.DisplayName); ICommandHelper commandHelper = new CommandHelper(manifest.UniqueID, metadata.DisplayName, this.CommandManager); IContentHelper contentHelper = new ContentHelper(contentManager, metadata.DirectoryPath, manifest.UniqueID, metadata.DisplayName, monitor); IReflectionHelper reflectionHelper = new ReflectionHelper(manifest.UniqueID, this.Reflection); IModRegistry modRegistryHelper = new ModRegistryHelper(manifest.UniqueID, this.ModRegistry); ITranslationHelper translationHelper = new TranslationHelper(manifest.UniqueID, manifest.Name, contentManager.GetLocale(), contentManager.GetCurrentLanguage()); mod.ModManifest = manifest; mod.Helper = new ModHelper(manifest.UniqueID, metadata.DirectoryPath, jsonHelper, contentHelper, commandHelper, modRegistryHelper, reflectionHelper, translationHelper); mod.Monitor = monitor; #if SMAPI_1_x mod.PathOnDisk = metadata.DirectoryPath; #endif } // track mod metadata.SetMod(mod); this.ModRegistry.Add(metadata); } catch (Exception ex) { TrackSkip(metadata, $"initialisation failed:\n{ex.GetLogSummary()}"); } } } IModMetadata[] loadedMods = this.ModRegistry.GetMods().ToArray(); // log skipped mods #if !SMAPI_1_x this.Monitor.Newline(); #endif if (skippedMods.Any()) { this.Monitor.Log($"Skipped {skippedMods.Count} mods:", LogLevel.Error); foreach (var pair in skippedMods.OrderBy(p => p.Key.DisplayName)) { IModMetadata mod = pair.Key; string reason = pair.Value; if (mod.Manifest?.Version != null) { this.Monitor.Log($" {mod.DisplayName} {mod.Manifest.Version} because {reason}", LogLevel.Error); } else { this.Monitor.Log($" {mod.DisplayName} because {reason}", LogLevel.Error); } } #if !SMAPI_1_x this.Monitor.Newline(); #endif } // log loaded mods this.Monitor.Log($"Loaded {loadedMods.Length} mods" + (loadedMods.Length > 0 ? ":" : "."), LogLevel.Info); foreach (IModMetadata metadata in loadedMods.OrderBy(p => p.DisplayName)) { IManifest manifest = metadata.Manifest; this.Monitor.Log( $" {metadata.DisplayName} {manifest.Version}" + (!string.IsNullOrWhiteSpace(manifest.Author) ? $" by {manifest.Author}" : "") + (!string.IsNullOrWhiteSpace(manifest.Description) ? $" | {manifest.Description}" : ""), LogLevel.Info ); } #if !SMAPI_1_x this.Monitor.Newline(); #endif // initialise translations this.ReloadTranslations(); // initialise loaded mods foreach (IModMetadata metadata in loadedMods) { // add interceptors if (metadata.Mod.Helper.Content is ContentHelper helper) { this.ContentManager.Editors[metadata] = helper.ObservableAssetEditors; this.ContentManager.Loaders[metadata] = helper.ObservableAssetLoaders; } // call entry method try { IMod mod = metadata.Mod; mod.Entry(mod.Helper); #if SMAPI_1_x (mod as Mod)?.Entry(); // deprecated since 1.0 // raise deprecation warning for old Entry() methods if (this.DeprecationManager.IsVirtualMethodImplemented(mod.GetType(), typeof(Mod), nameof(Mod.Entry), new[] { typeof(object[]) })) { deprecationWarnings.Add(() => this.DeprecationManager.Warn(metadata.DisplayName, $"{nameof(Mod)}.{nameof(Mod.Entry)}(object[]) instead of {nameof(Mod)}.{nameof(Mod.Entry)}({nameof(IModHelper)})", "1.0", DeprecationLevel.PendingRemoval)); } #else if (!this.DeprecationManager.IsVirtualMethodImplemented(mod.GetType(), typeof(Mod), nameof(Mod.Entry), new[] { typeof(IModHelper) })) { this.Monitor.Log($"{metadata.DisplayName} doesn't implement Entry() and may not work correctly.", LogLevel.Error); } #endif } catch (Exception ex) { this.Monitor.Log($"{metadata.DisplayName} failed on entry and might not work correctly. Technical details:\n{ex.GetLogSummary()}", LogLevel.Error); } } // reset cache when needed // only register listeners after Entry to avoid repeatedly reloading assets during load foreach (IModMetadata metadata in loadedMods) { if (metadata.Mod.Helper.Content is ContentHelper helper) { // TODO: optimise by only reloading assets the new editors/loaders can intercept helper.ObservableAssetEditors.CollectionChanged += (sender, e) => { if (e.NewItems.Count > 0) { this.Monitor.Log("Detected new asset editor, resetting cache...", LogLevel.Trace); this.ContentManager.InvalidateCache((key, type) => true); } }; helper.ObservableAssetLoaders.CollectionChanged += (sender, e) => { if (e.NewItems.Count > 0) { this.Monitor.Log("Detected new asset loader, resetting cache...", LogLevel.Trace); this.ContentManager.InvalidateCache((key, type) => true); } }; } } this.Monitor.Log("Resetting cache to enable interception...", LogLevel.Trace); this.ContentManager.InvalidateCache((key, type) => true); }
public ModType(IMod mod) { m_modType = mod.GetType(); m_modTypeName = TypeName; }
public bool Equals(IMod other) => GetType() == other?.GetType();
/// <summary>Load and hook up the given mods.</summary> /// <param name="mods">The mods to load.</param> /// <param name="jsonHelper">The JSON helper with which to read mods' JSON files.</param> /// <param name="contentManager">The content manager to use for mod content.</param> private void LoadMods(IModMetadata[] mods, JsonHelper jsonHelper, SContentManager contentManager) { this.Monitor.Log("Loading mods...", LogLevel.Trace); // load mod assemblies IDictionary <IModMetadata, string> skippedMods = new Dictionary <IModMetadata, string>(); { void TrackSkip(IModMetadata mod, string reasonPhrase) => skippedMods[mod] = reasonPhrase; AssemblyLoader modAssemblyLoader = new AssemblyLoader(Constants.TargetPlatform, this.Monitor); AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => modAssemblyLoader.ResolveAssembly(e.Name); foreach (IModMetadata metadata in mods) { // get basic info IManifest manifest = metadata.Manifest; string assemblyPath = metadata.Manifest?.EntryDll != null ? Path.Combine(metadata.DirectoryPath, metadata.Manifest.EntryDll) : null; this.Monitor.Log(assemblyPath != null ? $"Loading {metadata.DisplayName} from {assemblyPath.Replace(Constants.ModPath, "").TrimStart(Path.DirectorySeparatorChar)}..." : $"Loading {metadata.DisplayName}...", LogLevel.Trace); // validate status if (metadata.Status == ModMetadataStatus.Failed) { this.Monitor.Log($" Failed: {metadata.Error}", LogLevel.Trace); TrackSkip(metadata, metadata.Error); continue; } // preprocess & load mod assembly Assembly modAssembly; try { modAssembly = modAssemblyLoader.Load(metadata, assemblyPath, assumeCompatible: metadata.DataRecord.GetCompatibility(metadata.Manifest.Version)?.Status == ModStatus.AssumeCompatible); } catch (IncompatibleInstructionException ex) { TrackSkip(metadata, $"it's no longer compatible (detected {ex.NounPhrase}). Please check for a newer version of the mod."); continue; } catch (SAssemblyLoadFailedException ex) { TrackSkip(metadata, $"its DLL '{manifest.EntryDll}' couldn't be loaded: {ex.Message}"); continue; } catch (Exception ex) { TrackSkip(metadata, $"its DLL '{manifest.EntryDll}' couldn't be loaded:\n{ex.GetLogSummary()}"); continue; } // validate assembly try { int modEntries = modAssembly.DefinedTypes.Count(type => typeof(Mod).IsAssignableFrom(type) && !type.IsAbstract); if (modEntries == 0) { TrackSkip(metadata, $"its DLL has no '{nameof(Mod)}' subclass."); continue; } if (modEntries > 1) { TrackSkip(metadata, $"its DLL contains multiple '{nameof(Mod)}' subclasses."); continue; } } catch (Exception ex) { TrackSkip(metadata, $"its DLL couldn't be loaded:\n{ex.GetLogSummary()}"); continue; } // initialise mod try { // get implementation TypeInfo modEntryType = modAssembly.DefinedTypes.First(type => typeof(Mod).IsAssignableFrom(type) && !type.IsAbstract); Mod mod = (Mod)modAssembly.CreateInstance(modEntryType.ToString()); if (mod == null) { TrackSkip(metadata, "its entry class couldn't be instantiated."); continue; } // inject data { IMonitor monitor = this.GetSecondaryMonitor(metadata.DisplayName); ICommandHelper commandHelper = new CommandHelper(manifest.UniqueID, metadata.DisplayName, this.CommandManager); IContentHelper contentHelper = new ContentHelper(contentManager, metadata.DirectoryPath, manifest.UniqueID, metadata.DisplayName, monitor); IReflectionHelper reflectionHelper = new ReflectionHelper(manifest.UniqueID, metadata.DisplayName, this.Reflection); IModRegistry modRegistryHelper = new ModRegistryHelper(manifest.UniqueID, this.ModRegistry); ITranslationHelper translationHelper = new TranslationHelper(manifest.UniqueID, manifest.Name, contentManager.GetLocale(), contentManager.GetCurrentLanguage()); mod.ModManifest = manifest; mod.Helper = new ModHelper(manifest.UniqueID, metadata.DirectoryPath, jsonHelper, contentHelper, commandHelper, modRegistryHelper, reflectionHelper, translationHelper); mod.Monitor = monitor; } // track mod metadata.SetMod(mod); this.ModRegistry.Add(metadata); } catch (Exception ex) { TrackSkip(metadata, $"initialisation failed:\n{ex.GetLogSummary()}"); } } } IModMetadata[] loadedMods = this.ModRegistry.GetMods().ToArray(); // log skipped mods this.Monitor.Newline(); if (skippedMods.Any()) { this.Monitor.Log($"Skipped {skippedMods.Count} mods:", LogLevel.Error); foreach (var pair in skippedMods.OrderBy(p => p.Key.DisplayName)) { IModMetadata mod = pair.Key; string reason = pair.Value; if (mod.Manifest?.Version != null) { this.Monitor.Log($" {mod.DisplayName} {mod.Manifest.Version} because {reason}", LogLevel.Error); } else { this.Monitor.Log($" {mod.DisplayName} because {reason}", LogLevel.Error); } } this.Monitor.Newline(); } // log loaded mods this.Monitor.Log($"Loaded {loadedMods.Length} mods" + (loadedMods.Length > 0 ? ":" : "."), LogLevel.Info); foreach (IModMetadata metadata in loadedMods.OrderBy(p => p.DisplayName)) { IManifest manifest = metadata.Manifest; this.Monitor.Log( $" {metadata.DisplayName} {manifest.Version}" + (!string.IsNullOrWhiteSpace(manifest.Author) ? $" by {manifest.Author}" : "") + (!string.IsNullOrWhiteSpace(manifest.Description) ? $" | {manifest.Description}" : ""), LogLevel.Info ); } this.Monitor.Newline(); // initialise translations this.ReloadTranslations(); // initialise loaded mods foreach (IModMetadata metadata in loadedMods) { // add interceptors if (metadata.Mod.Helper.Content is ContentHelper helper) { this.ContentManager.Editors[metadata] = helper.ObservableAssetEditors; this.ContentManager.Loaders[metadata] = helper.ObservableAssetLoaders; } // call entry method try { IMod mod = metadata.Mod; mod.Entry(mod.Helper); if (!this.DeprecationManager.IsVirtualMethodImplemented(mod.GetType(), typeof(Mod), nameof(Mod.Entry), new[] { typeof(IModHelper) })) { this.Monitor.Log($"{metadata.DisplayName} doesn't implement Entry() and may not work correctly.", LogLevel.Error); } } catch (Exception ex) { this.Monitor.Log($"{metadata.DisplayName} failed on entry and might not work correctly. Technical details:\n{ex.GetLogSummary()}", LogLevel.Error); } } // invalidate cache entries when needed // (These listeners are registered after Entry to avoid repeatedly reloading assets as mods initialise.) foreach (IModMetadata metadata in loadedMods) { if (metadata.Mod.Helper.Content is ContentHelper helper) { helper.ObservableAssetEditors.CollectionChanged += (sender, e) => { if (e.NewItems.Count > 0) { this.Monitor.Log("Invalidating cache entries for new asset editors...", LogLevel.Trace); this.ContentManager.InvalidateCacheFor(e.NewItems.Cast <IAssetEditor>().ToArray(), new IAssetLoader[0]); } }; helper.ObservableAssetLoaders.CollectionChanged += (sender, e) => { if (e.NewItems.Count > 0) { this.Monitor.Log("Invalidating cache entries for new asset loaders...", LogLevel.Trace); this.ContentManager.InvalidateCacheFor(new IAssetEditor[0], e.NewItems.Cast <IAssetLoader>().ToArray()); } }; } } // reset cache now if any editors or loaders were added during entry IAssetEditor[] editors = loadedMods.SelectMany(p => ((ContentHelper)p.Mod.Helper.Content).AssetEditors).ToArray(); IAssetLoader[] loaders = loadedMods.SelectMany(p => ((ContentHelper)p.Mod.Helper.Content).AssetLoaders).ToArray(); if (editors.Any() || loaders.Any()) { this.Monitor.Log("Invalidating cached assets for new editors & loaders...", LogLevel.Trace); this.ContentManager.InvalidateCacheFor(editors, loaders); } }
public static IMod LoadMod(IMod mod) { if (mod == null) { return(null); } var modType = mod.GetType(); var attrib = modType.GetFirstAttribute <ALoadOrderAttribute>(); var name = mod.GetCleanId(); if (attrib != null) { foreach (var pair in ModIdReliance.ToArray()) { var i = pair.Value.FindIndex(m => m.GetCleanId() == name); if (i != -1) { ModIdReliance[pair.Key][i] = mod; } } foreach (var id in attrib.beforeIds) { if (!ModIdReliance.ContainsKey(id.GetCleanId())) { ModIdReliance.Add(id, new List <IMod>()); } if (!ModIdReliance[id].Contains(mod)) { ModIdReliance[id].Add(mod); } } foreach (var id in attrib.afterIds) { if (!ModIdReliance.ContainsKey(name)) { ModIdReliance.Add(name, new List <IMod>()); } if (ModIdReliance[name].FindIndex(m => m.GetCleanId() == id.GetCleanId()) != -1) { ModIdReliance[name].Add(new Placeholder(id.GetCleanId())); } } if (attrib.beforeIds.Count > 0) { return(mod); } } try { if (!Pathfinder.IsModIdentifierValid(name, true)) { return(null); // never reached due to throw } Logger.Info("Loading mod '{0}'", name); CurrentMod = mod; mod.Load(); UnloadedModIds.Remove(name); LoadedMods.Add(name, mod); GUI.ModOptions.Handler.LoadFor(mod); if (ModIdReliance.ContainsKey(name)) { foreach (var internalMod in ModIdReliance[name]) { LoadMod(internalMod); } } } catch (Exception ex) { Logger.Error("Mod '{0}' of file '{1}' failed to load:\n\t{2}", modType.FullName, Path.GetFileName(modType.Assembly.Location), ex); UnloadMod(mod); UnloadedModIds.Remove(name); CurrentMod = null; return(null); } CurrentMod = null; return(mod); }
public static void UnloadMod(IMod mod) { if (mod == null || mod is Placeholder) { return; } CurrentMod = mod; var name = Utility.ActiveModId; var attrib = mod.GetType().GetFirstAttribute <ALoadOrderAttribute>(); if (attrib != null) { foreach (var ident in attrib.afterIds) { var id = ident.GetCleanId(); if (LoadedMods.ContainsKey(id) && LoadedMods[id].GetType().GetFirstAttribute <AllowOrderUnloadAttribute>()?.Allowed == true) { UnloadMod(LoadedMods[id]); } } } foreach (var e in (from p in Extension.Handler.ModExtensions where p.Key.IndexOf('.') != -1 && p.Key.Remove(p.Key.IndexOf('.')) == name select p.Key) .ToArray() ) { Extension.Handler.UnregisterExtension(e); } foreach (var e in (from p in Executable.Handler.ModExecutables where p.Key.IndexOf('.') != -1 && p.Key.Remove(p.Key.IndexOf('.')) == name select p.Key) .ToArray() ) { Executable.Handler.UnregisterExecutable(e); } foreach (var d in (from p in Daemon.Handler.ModDaemons where p.Key.IndexOf('.') != -1 && p.Key.Remove(p.Key.IndexOf('.')) == name select p.Key) .ToArray() ) { Daemon.Handler.UnregisterDaemon(d); } List <string> clist; Command.Handler.ModIdToCommandKeyList.TryGetValue(name, out clist); if (clist != null) { foreach (var c in clist.ToArray()) { Command.Handler.UnregisterCommand(c); } } foreach (var g in (from p in Mission.Handler.ModGoals where p.Key.IndexOf('.') != -1 && p.Key.Remove(p.Key.IndexOf('.')) == name select p.Key) .ToArray() ) { Mission.Handler.UnregisterMissionGoal(g); } foreach (var m in (from p in Mission.Handler.ModMissions where p.Key.IndexOf('.') != -1 && p.Key.Remove(p.Key.IndexOf('.')) == name select p.Key) .ToArray() ) { Mission.Handler.UnregisterMission(m); } foreach (var p in (from p in Port.Handler.PortTypes where p.Key.IndexOf('.') != -1 && p.Key.Remove(p.Key.IndexOf('.')) == name select p.Key) .ToArray() ) { Port.Handler.UnregisterPort(p); } var events = new List <Tuple <Action <PathfinderEvent>, string, string, int> >(); foreach (var v in EventManager.eventListeners.Values) { events.AddRange(v.FindAll(t => t.Item3 == name)); } foreach (var list in EventManager.eventListeners.ToArray()) { foreach (var e in events) { list.Value.Remove(e); } } GUI.ModOptions.Handler.ModOptions.Remove(name); mod.Unload(); UnloadedModIds.Add(name); LoadedMods.Remove(name); CurrentMod = null; }
public ModDependency(IMod mod):base(mod) { MaxVersion = MinVersion = mod.GetType().Assembly.GetName().Version; }
/**** ** Internal methods ****/ /// <summary>Register a mod as a possible source of deprecation warnings.</summary> /// <param name="mod">The mod instance.</param> public void Add(IMod mod) { this.Mods.Add(mod); this.ModNamesByAssembly[mod.GetType().Assembly.FullName] = mod.ModManifest.Name; }
public ModDependency(IMod mod) : base(mod) { MaxVersion = MinVersion = mod.GetType().Assembly.GetName().Version; }
public static void UnloadMod(IMod mod) { if (mod == null || mod is Placeholder) { return; } using (var _ = new CurrentModOverride(mod)) { var name = Utility.ActiveModId; var attrib = mod.GetType().GetFirstAttribute <ModInfoAttribute>(); if (attrib != null) { foreach (var ident in attrib.AfterIds) { var id = ident.GetCleanId(); if (LoadedMods.ContainsKey(id) && LoadedMods[id].GetType().GetFirstAttribute <AllowOrderUnloadAttribute>()?.Allowed == true) { UnloadMod(LoadedMods[id]); } } } foreach (var e in (from p in Extension.Handler.ModExtensions where p.Key.IndexOf('.') != -1 && p.Key.Remove(p.Key.IndexOf('.')) == name select p.Key) .ToArray() ) { Logger.Verbose($"Unloading Extension '{e}'"); Extension.Handler.UnregisterExtension(e); } foreach (var e in (from p in Executable.Handler.ModExecutables where p.Key.IndexOf('.') != -1 && p.Key.Remove(p.Key.IndexOf('.')) == name select p.Key) .ToArray() ) { Logger.Verbose($"Unloading Executable '{e}'"); Executable.Handler.UnregisterExecutable(e); } foreach (var d in (from p in Daemon.Handler.ModDaemons where p.Key.IndexOf('.') != -1 && p.Key.Remove(p.Key.IndexOf('.')) == name select p.Key) .ToArray() ) { Logger.Verbose($"Unloading Daemon '{d}'"); Daemon.Handler.UnregisterDaemon(d); } Command.Handler.ModIdToCommandKeyList.TryGetValue(name, out List <string> clist); if (clist != null) { foreach (var c in clist.ToArray()) { Logger.Verbose($"Unloading Command '{c}'"); Command.Handler.UnregisterCommand(c); } } foreach (var p in (from p in Port.Handler.PortTypes where p.Key.IndexOf('.') != -1 && p.Key.Remove(p.Key.IndexOf('.')) == name select p.Key) .ToArray() ) { Logger.Verbose($"Unloading PortType '{p}'"); Port.Handler.UnregisterPort(p); } foreach (var pair in EventManager.eventListeners.Reverse()) { var listenerObjs = pair.Value.FindAll(l => l.ModId == name); foreach (var obj in listenerObjs) { Logger.Verbose($"Unloading Event Listener '{obj.Options.DebugName}'"); EventManager.UnregisterListener(pair.Key, obj); } } GUI.ModOptions.Handler.ModOptions.Remove(name); mod.Unload(); UnloadedModIds.Add(name); LoadedMods.Remove(name); } }
/* * public void GetObjectData(SerializationInfo info, StreamingContext context) * { * info.AddValue("ModType", ModType); * info.AddValue("Data", data.Select(kvp => new msd_dataItem() { key = kvp.Key, value = kvp.Value }).ToArray()); * return; * } */ public ModSaveData(IMod mod) { ModType = mod.GetType().FullName; LoadedMod = mod; }
public static IMod LoadMod(IMod mod) { if (mod == null) { return(null); } var modType = mod.GetType(); var attrib = modType.GetFirstAttribute <ModInfoAttribute>(); var name = mod.GetCleanId(); if (attrib != null) { foreach (var pair in ModIdReliance.ToArray()) { var i = pair.Value.FindIndex(m => m.GetCleanId() == name); if (i != -1) { ModIdReliance[pair.Key][i] = mod; } } foreach (var id in attrib.BeforeIds) { if (!ModIdReliance.ContainsKey(id.GetCleanId())) { ModIdReliance.Add(id, new List <IMod>()); } if (!ModIdReliance[id].Contains(mod)) { ModIdReliance[id].Add(mod); } } foreach (var id in attrib.AfterIds) { if (!ModIdReliance.ContainsKey(name)) { ModIdReliance.Add(name, new List <IMod>()); } if (ModIdReliance[name].FindIndex(m => m.GetCleanId() == id.GetCleanId()) != -1) { ModIdReliance[name].Add(new Placeholder(id.GetCleanId())); } } if (attrib.BeforeIds.Count > 0) { return(mod); } } try { if (!Pathfinder.IsModIdentifierValid(name, true)) { return(null); // never reached due to throw } Logger.Info("Loading mod '{0}'", name); using (var _ = new CurrentModOverride(mod)) { if (ModAttributeHandler.ModToEventMethods.TryGetValue(CurrentMod.GetType(), out var infos)) { foreach (var i in infos) { var eventAttrib = i.GetFirstAttribute <EventAttribute>(); var paramType = i.GetParameters()[0].ParameterType; EventManager.RegisterListener(paramType, i.CreateDelegate <Action <PathfinderEvent> >(typeof(Action <>).MakeGenericType(paramType)), eventAttrib.Options); } } mod.Load(); UnloadedModIds.Remove(name); LoadedMods.Add(name, mod); GUI.ModOptions.Handler.LoadFor(mod); if (ModIdReliance.ContainsKey(name)) { foreach (var internalMod in ModIdReliance[name]) { LoadMod(internalMod); } } } } catch (Exception ex) { Logger.Error("Mod '{0}' of file '{1}' failed to load:\n\t{2}", modType.FullName, Path.GetFileName(modType.Assembly.Location), ex); UnloadMod(mod); UnloadedModIds.Remove(name); return(null); } return(mod); }