コード例 #1
0
ファイル: PBuilding.cs プロジェクト: pyromanci/ONIMods
 /// <summary>
 /// Adds the techs for every registered building to the database.
 /// </summary>
 internal static void AddAllTechs()
 {
     if (buildingTable == null)
     {
         throw new InvalidOperationException("Building table not loaded");
     }
     lock (PSharedData.GetLock(PRegistry.KEY_BUILDING_LOCK)) {
         PRegistry.LogPatchDebug("Register techs for {0:D} buildings".F(
                                     buildingTable.Count));
         foreach (var building in buildingTable)
         {
             if (building != null)
             {
                 try {
                     var trBuilding = Traverse.Create(building);
                     // Building is of type object because it is in another assembly
                     var addTech = Traverse.Create(building).Method(nameof(AddTech));
                     if (addTech.MethodExists())
                     {
                         addTech.GetValue();
                     }
                     else
                     {
                         PRegistry.LogPatchWarning("Invalid building technology!");
                     }
                 } catch (System.Reflection.TargetInvocationException e) {
                     // Log errors when registering building from another mod
                     PUtil.LogError("Unable to add building tech for " +
                                    building.GetType().Assembly?.GetNameSafe() + ":");
                     PUtil.LogException(e.GetBaseException());
                 }
             }
         }
     }
 }
コード例 #2
0
        /// <summary>
        /// Initializes the Imagination Loader. PLib will be initialized if not already done.
        /// </summary>
        /// <param name="rootType">The Type that will be used as the base for this Imagination
        /// mod's assembly. The namespace for that Type will be registered as the name for
        /// other Imagination mods to see.</param>
        public static void Init(Type rootType)
        {
            if (rootType == null)
            {
                throw new ArgumentNullException("rootType");
            }
            var asm = Assembly.GetExecutingAssembly();

            PUtil.InitLibrary();
            // Create imagination mod table
            var imag = PSharedData.GetData <IDictionary <string, Assembly> >(IMAGINATION_TABLE);

            if (imag == null)
            {
                PSharedData.PutData(IMAGINATION_TABLE, imag = new Dictionary <string,
                                                                              Assembly>(8));
            }
            var rootNS = rootType.Namespace;

            if (imag.ContainsKey(rootNS))
            {
                PUtil.LogWarning("Reimagination mod {0} is loaded more than once. This may " +
                                 "cause severe problems!".F(rootType.FullName));
            }
            else
            {
                imag.Add(rootNS, asm);
                PUtil.LogDebug("Imagination Loader registered mod ID: " + rootNS);
            }
        }
コード例 #3
0
ファイル: PLocalization.cs プロジェクト: julian-perge/ONIMods
        /// <summary>
        /// Registers the specified assembly for automatic PLib localization. If null is
        /// passed, the calling assembly is registered.
        /// </summary>
        /// <param name="assembly">The assembly to register for PLib localization.</param>
        public static void Register(Assembly assembly = null)
        {
            if (assembly == null)
            {
                assembly = Assembly.GetCallingAssembly();
            }
            lock (PSharedData.GetLock(PRegistry.KEY_LOCALE_LOCK)) {
                // Get list holding locale information
                var list = PSharedData.GetData <IList <Assembly> >(PRegistry.KEY_LOCALE_TABLE);
                if (list == null)
                {
                    PSharedData.PutData(PRegistry.KEY_LOCALE_TABLE, list =
                                            new List <Assembly>(8));
                }
                list.Add(assembly);
            }
            var types = assembly.GetTypes();

            if (types == null || types.Length == 0)
            {
                PUtil.LogWarning("Registered assembly " + assembly.GetName()?.Name +
                                 " that had no types for localization!");
            }
            else
            {
                // This call searches all types in the assembly implicitly
                Localization.RegisterForTranslation(types[0]);
            }
        }
コード例 #4
0
 /// <summary>
 /// Initializes and stores the options table for quicker lookups later.
 /// </summary>
 internal static void Init()
 {
     lock (PSharedData.GetLock(PRegistry.KEY_OPTIONS_LOCK)) {
         modOptions = PSharedData.GetData <OptionsTable>(PRegistry.KEY_OPTIONS_TABLE);
         PSharedData.PutData(PRegistry.KEY_OPTIONS_LATEST, typeof(POptions));
     }
 }
コード例 #5
0
ファイル: PBuilding.cs プロジェクト: julian-perge/ONIMods
        /// <summary>
        /// Registers a building to properly display its name, description, and tech tree
        /// entry. PLib must be initialized using InitLibrary before using this method. Each
        /// building should only be registered once, either in OnLoad or a post-load patch.
        /// </summary>
        /// <param name="building">The building to register.</param>
        public static void Register(PBuilding building)
        {
            if (building == null)
            {
                throw new ArgumentNullException("building");
            }
            // In case this call is used before the library was initialized
            if (!PUtil.PLibInit)
            {
                PUtil.InitLibrary(false);
                PUtil.LogWarning("PUtil.InitLibrary was not called before using " +
                                 "PBuilding.Register!");
            }
            // Must use object as the building table type
            lock (PSharedData.GetLock(PRegistry.KEY_BUILDING_LOCK)) {
                var table = PSharedData.GetData <ICollection <object> >(PRegistry.
                                                                        KEY_BUILDING_TABLE);
                if (table == null)
                {
                    PSharedData.PutData(PRegistry.KEY_BUILDING_TABLE, table = new
                                                                              List <object>(64));
                }
#if DEBUG
                PUtil.LogDebug("Registered building: {0}".F(building.ID));
#endif
                table.Add(building);
            }
        }
コード例 #6
0
ファイル: POptions.cs プロジェクト: skairunner/ONIMods
        /// <summary>
        /// Registers a class as a mod options class.
        /// </summary>
        /// <param name="optionsType">The class which will represent the options for this mod.</param>
        public static void RegisterOptions(Type optionsType)
        {
            if (optionsType == null)
            {
                throw new ArgumentNullException("optionsType");
            }
            var assembly = optionsType.Assembly;
            var id       = Path.GetFileName(GetModDir(assembly));

            // Prevent concurrent modification (should be impossible anyways)
            lock (PSharedData.GetLock(PRegistry.KEY_OPTIONS_LOCK)) {
                // Get options table
                var options = PSharedData.GetData <OptionsTable>(PRegistry.KEY_OPTIONS_TABLE);
                if (options == null)
                {
                    PSharedData.PutData(PRegistry.KEY_OPTIONS_TABLE, options =
                                            new Dictionary <string, Type>(8));
                }
                if (options.ContainsKey(id))
                {
                    PUtil.LogWarning("Duplicate mod ID: " + id);
                }
                else
                {
                    // Add as options for this mod
                    options.Add(id, optionsType);
                    PUtil.LogDebug("Registered mod options class {0} for {1}".F(
                                       optionsType.Name, assembly.GetName()?.Name));
                }
            }
        }
コード例 #7
0
        /// <summary>
        /// Adds the save/restore lists buttons to the bottom of the Mods screen.
        /// </summary>
        /// <param name="instance">The object hosting the mods screen.</param>
        /// <param name="bottom">The panel where the buttons should be added.</param>
        internal static void AddExtraButtons(GameObject instance, GameObject bottom)
        {
            var handler = instance.AddOrGet <AllModsHandler>();
            var cb      = new PCheckBox("AllMods")
            {
                CheckSize = new Vector2(24.0f, 24.0f), Text = DebugNotIncludedStrings.
                                                              BUTTON_ALL, ToolTip = DebugNotIncludedStrings.TOOLTIP_ALL, Margin =
                    new RectOffset(5, 5, 0, 0)
            };

            // When clicked, enable/disable all
            if (handler != null)
            {
                cb.OnChecked = handler.OnClick;
            }
            handler.checkbox = cb.AddTo(bottom, 0);
            handler.UpdateCheckedState();
            // Current PLib version
            string version = PSharedData.GetData <string>("PLib.Version");
            string name    = ModDebugRegistry.Instance.OwnerOfAssembly(DebugNotIncludedPatches.
                                                                       RunningPLibAssembly)?.ModName ?? "Unknown";

            new PLabel("PLibVersion")
            {
                TextStyle = PUITuning.Fonts.UILightStyle, Text = string.Format(
                    DebugNotIncludedStrings.LABEL_PLIB, version ?? PVersion.VERSION), ToolTip =
                    string.Format(DebugNotIncludedStrings.TOOLTIP_PLIB, name),
                Margin = new RectOffset(5, 5, 0, 0)
            }.AddTo(bottom, 0);
        }
コード例 #8
0
ファイル: PBuilding.cs プロジェクト: julian-perge/ONIMods
 /// <summary>
 /// Adds the techs for every registered building to the database.
 /// </summary>
 internal static void AddAllTechs()
 {
     if (buildingTable == null)
     {
         throw new InvalidOperationException("Building table not loaded");
     }
     lock (PSharedData.GetLock(PRegistry.KEY_BUILDING_LOCK)) {
         PRegistry.LogPatchDebug("Register techs for {0:D} buildings".F(
                                     buildingTable.Count));
         foreach (var building in buildingTable)
         {
             if (building != null)
             {
                 var trBuilding = Traverse.Create(building);
                 // Building is of type object because it is in another assembly
                 var addTech = Traverse.Create(building).Method(nameof(AddTech));
                 if (addTech.MethodExists())
                 {
                     addTech.GetValue();
                 }
                 else
                 {
                     PRegistry.LogPatchWarning("Invalid building technology!");
                 }
             }
         }
     }
 }
コード例 #9
0
        /// <summary>
        /// Registers a class as a mod options class. The type is registered for its defining
        /// assembly, not for the calling assembly, for compatibility reasons.
        /// </summary>
        /// <param name="optionsType">The class which will represent the options for this mod.</param>
        public static void RegisterOptions(Type optionsType)
        {
            if (optionsType == null)
            {
                throw new ArgumentNullException("optionsType");
            }
#if OPTIONS_ONLY
            var assembly = optionsType.Assembly;
            var id       = Path.GetFileName(GetModDir(assembly));
            // Local options type
            if (modOptions == null)
            {
                modOptions = new Dictionary <string, Type>(4);
            }
            if (modOptions.ContainsKey(id))
            {
                PUtil.LogWarning("Duplicate mod ID: " + id);
            }
            else
            {
                // Add as options for this mod
                modOptions.Add(id, optionsType);
                PUtil.LogDebug("Registered mod options class {0} for {1}".F(optionsType.Name,
                                                                            assembly.GetName()?.Name));
            }
#else
            // In case this call is used before the library was initialized
            if (!PUtil.PLibInit)
            {
                PUtil.InitLibrary(false);
                PUtil.LogWarning("PUtil.InitLibrary was not called before using " +
                                 "RegisterOptions!");
            }
            var assembly = optionsType.Assembly;
            var id       = Path.GetFileName(GetModDir(assembly));
            // Prevent concurrent modification (should be impossible anyways)
            lock (PSharedData.GetLock(PRegistry.KEY_OPTIONS_LOCK)) {
                // Get options table
                var options = PSharedData.GetData <OptionsTable>(PRegistry.KEY_OPTIONS_TABLE);
                if (options == null)
                {
                    PSharedData.PutData(PRegistry.KEY_OPTIONS_TABLE, options =
                                            new Dictionary <string, Type>(8));
                }
                if (options.ContainsKey(id))
                {
                    PUtil.LogWarning("Duplicate mod ID: " + id);
                }
                else
                {
                    // Add as options for this mod
                    options.Add(id, optionsType);
                    PUtil.LogDebug("Registered mod options class {0} for {1}".F(optionsType.
                                                                                Name, assembly.GetName()?.Name));
                }
            }
#endif
        }
コード例 #10
0
        /// <summary>
        /// Gets the lock object for the achievement list.
        /// </summary>
        /// <returns>An object used to synchronize mods accessing the achievement list.</returns>
        private static object GetAchievementLock()
        {
            var obj = PSharedData.GetData <object>(ACHIEVEMENTS_API_LOCK);

            if (obj == null)
            {
                PSharedData.PutData(ACHIEVEMENTS_API_LOCK, obj = new object());
            }
            return(obj);
        }
コード例 #11
0
ファイル: PLightShape.cs プロジェクト: pether-pg/ONIMods
        /// <summary>
        /// Registers a light shape handler.
        /// </summary>
        /// <param name="identifier">A unique identifier for this shape. If another mod has
        /// already registered that identifier, the previous mod will take precedence.</param>
        /// <param name="handler">The handler for that shape.</param>
        /// <returns>The light shape which can be used.</returns>
        public static PLightShape Register(string identifier, CastLight handler)
        {
            PLightShape lightShape;

            // In case this call is used before the library was initialized
            if (!PUtil.PLibInit)
            {
                PUtil.InitLibrary(false);
                PUtil.LogWarning("PUtil.InitLibrary was not called before using " +
                                 "PLightShape.Register!");
            }
            lock (PSharedData.GetLock(PRegistry.KEY_LIGHTING_LOCK)) {
                // Get list holding lighting information
                var list = PSharedData.GetData <IList <object> >(PRegistry.KEY_LIGHTING_TABLE);
                if (list == null)
                {
                    PSharedData.PutData(PRegistry.KEY_LIGHTING_TABLE, list =
                                            new List <object>(8));
                }
                // Try to find a match for this identifier
                object ls = null;
                int    n = list.Count, index = 0;
                for (int i = 0; i < n; i++)
                {
                    var light = list[i];
                    // Might be from another assembly so the types may or may not be compatible
                    if (light != null && light.ToString() == identifier && light.GetType().
                        Name == typeof(PLightShape).Name)
                    {
                        index = i;
                        break;
                    }
                }
                if (ls == null)
                {
                    // Not currently existing
                    lightShape = new PLightShape(n + 1, identifier, handler);
                    PUtil.LogDebug("Registered new light shape: " + identifier);
                    list.Add(lightShape);
                }
                else
                {
                    // Exists already
                    PUtil.LogDebug("Found existing light shape: " + identifier);
                    lightShape = new PLightShape(n + 1, identifier, null);
                }
            }
            return(lightShape);
        }
コード例 #12
0
ファイル: PBuilding.cs プロジェクト: julian-perge/ONIMods
        /// <summary>
        /// Checks for globally registered buildings and puts them into this assembly's
        /// building cache if present.
        /// </summary>
        /// <returns>true if buildings must be patched in, or false otherwise</returns>
        internal static bool CheckBuildings()
        {
            bool any = false;

            lock (PSharedData.GetLock(PRegistry.KEY_BUILDING_LOCK)) {
                var table = PSharedData.GetData <ICollection <object> >(PRegistry.
                                                                        KEY_BUILDING_TABLE);
                if (table != null && table.Count > 0)
                {
                    buildingTable = table;
                    any           = true;
                }
            }
            return(any);
        }
コード例 #13
0
        /// <summary>
        /// Gets the information for the specified achievement. The achievement lock must be
        /// held for this method to work properly.
        /// </summary>
        /// <param name="id">The achievement ID to look up.</param>
        /// <returns>The achievement information.</returns>
        private static Traverse GetAchievement(string id)
        {
            var data = PSharedData.GetData <AchievementDict>(ACHIEVEMENTS_API_INFO);

            if (data == null)
            {
                PSharedData.PutData(ACHIEVEMENTS_API_INFO, data =
                                        new Dictionary <string, object>(32));
            }
            if (!data.TryGetValue(id, out object info))
            {
                data.Add(id, info = new AchievementInfo(id));
            }
            return(Traverse.Create(info));
        }
コード例 #14
0
ファイル: PLocalization.cs プロジェクト: pether-pg/ONIMods
 /// <summary>
 /// Debug dumps the translation templates for ALL registered PLib localized mods.
 /// </summary>
 internal static void DumpAll()
 {
     lock (PSharedData.GetLock(PRegistry.KEY_LOCALE_LOCK)) {
         // Get list holding locale information
         var list = PSharedData.GetData <IList <Assembly> >(PRegistry.KEY_LOCALE_TABLE);
         if (list != null)
         {
             foreach (var mod in list)
             {
                 if (mod != null)
                 {
                     ModUtil.RegisterForTranslation(mod.GetTypes()[0]);
                 }
             }
         }
     }
 }
コード例 #15
0
        private static void RegisterEntry(Assembly modAssembly, string lockKey, string tableKey,
                                          string entryPath, string debugLine)
        {
            // Store the path to the creatures folder on disk for use in loading codex entries
            string dir = Options.POptions.GetModDir(modAssembly);

            lock (PSharedData.GetLock(lockKey)) {
                var table = PSharedData.GetData <IList <string> >(tableKey);
                if (table == null)
                {
                    PSharedData.PutData(tableKey, table = new List <string>(8));
                }
#if DEBUG
                PUtil.LogDebug(debugLine.F(dir));
#endif
                table.Add(Path.Combine(dir, entryPath));
            }
        }
コード例 #16
0
ファイル: PCodex.cs プロジェクト: pyromanci/ONIMods
        /// <summary>
        /// Loads all codex entries for all mods registered.
        /// </summary>
        /// <param name="lockKey">Key for shared data lock.</param>
        /// <param name="tableKey">Key for shared data table.</param>
        /// <param name="category">The codex category under which these data entries should be loaded.</param>
        /// <returns>The list of entries that were loaded.</returns>
        private static IList <CodexEntry> LoadEntries(string lockKey, string tableKey,
                                                      string category)
        {
            var entries = new List <CodexEntry>(32);

            lock (PSharedData.GetLock(lockKey)) {
                var table = PSharedData.GetData <IList <string> >(tableKey);
                if (table != null)
                {
                    foreach (string dir in table)
                    {
#if DEBUG
                        PUtil.LogDebug("Loaded codex entries from directory: {0}".F(dir));
#endif
                        LoadFromDirectory(entries, dir, category);
                    }
                }
            }
            return(entries);
        }
コード例 #17
0
        /// <summary>
        /// Loads all codex entries for all mods registered.
        /// </summary>
        /// <param name="lockKey">Key for shared data lock.</param>
        /// <param name="tableKey">Key for shared data table.</param>
        /// <param name="category">The codex category under which these data entries should be loaded.</param>
        /// <returns>The list of entries that were loaded.</returns>
        private static IList <CodexEntry> LoadEntries(string lockKey, string tableKey,
                                                      string category)
        {
            var entries = new List <CodexEntry>(32);

            lock (PSharedData.GetLock(lockKey)) {
                var table = PSharedData.GetData <IList <string> >(tableKey);
                if (table != null)
                {
                    foreach (string dir in table)
                    {
#if DEBUG
                        PUtil.LogDebug("Loaded codex entries from directory: {0}".F(dir));
#endif
                        string[] codexFiles = new string[0];
                        try {
                            // List codex data files in the codex directory
                            codexFiles = Directory.GetFiles(dir, CODEX_FILES);
                        } catch (UnauthorizedAccessException ex) {
                            PUtil.LogExcWarn(ex);
                        } catch (IOException ex) {
                            PUtil.LogExcWarn(ex);
                        }
                        var widgetTagMappings = Traverse.Create(typeof(CodexCache)).
                                                GetField <List <Tuple <string, Type> > >("widgetTagMappings");
                        foreach (string str in codexFiles)
                        {
                            try {
                                string filename   = str;
                                var    codexEntry = YamlIO.LoadFile <CodexEntry>(filename, PUtil.
                                                                                 YamlParseErrorCB, widgetTagMappings);
                                if (codexEntry != null)
                                {
                                    codexEntry.category = category;
                                    entries.Add(codexEntry);
                                }
                            } catch (IOException ex) {
                                PUtil.LogException(ex);
                            }
                        }
コード例 #18
0
        /// <summary>
        /// Creates and initializes the lighting manager instance.
        /// </summary>
        /// <returns>true if the lighting manager was initialized and has something to do,
        /// or false otherwise.</returns>
        internal static bool InitInstance()
        {
            bool patch = false;

            lock (PSharedData.GetLock(PRegistry.KEY_LIGHTING_LOCK)) {
                // Only run if any lights were registered
                var list = PSharedData.GetData <IList <object> >(PRegistry.KEY_LIGHTING_TABLE);
                if (list != null)
                {
                    Instance = new PLightManager();
                    Instance.Init(list);
                    patch = true;
                }
            }
            // Initialize anyways if smooth lighting is forced on
            if (!patch && ForceSmoothLight)
            {
                Instance = new PLightManager();
                patch    = true;
            }
            return(patch);
        }
コード例 #19
0
ファイル: PLocalization.cs プロジェクト: pether-pg/ONIMods
        /// <summary>
        /// Registers the specified assembly for automatic PLib localization. If null is
        /// passed, the calling assembly is registered.
        /// </summary>
        /// <param name="assembly">The assembly to register for PLib localization.</param>
        public static void Register(Assembly assembly = null)
        {
            if (!PUtil.PLibInit)
            {
                PUtil.InitLibrary(false);
                PUtil.LogWarning("PUtil.InitLibrary was not called before using " +
                                 "PLocalization.Register!");
            }
            if (assembly == null)
            {
                assembly = Assembly.GetCallingAssembly();
            }
            lock (PSharedData.GetLock(PRegistry.KEY_LOCALE_LOCK)) {
                // Get list holding locale information
                var list = PSharedData.GetData <IList <Assembly> >(PRegistry.KEY_LOCALE_TABLE);
                if (list == null)
                {
                    PSharedData.PutData(PRegistry.KEY_LOCALE_TABLE, list =
                                            new List <Assembly>(8));
                }
                list.Add(assembly);
            }
            var types = assembly.GetTypes();

            if (types == null || types.Length == 0)
            {
                PUtil.LogWarning("Registered assembly " + assembly.GetNameSafe() +
                                 " that had no types for localization!");
            }
            else
            {
                // This call searches all types in the assembly implicitly
                Localization.RegisterForTranslation(types[0]);
#if DEBUG
                PUtil.LogDebug("Localizing assembly {0} using base namespace {1}".F(assembly.
                                                                                    GetNameSafe(), types[0].Namespace));
#endif
            }
        }
コード例 #20
0
        /// <summary>
        /// Shows a mod options dialog now, as if Options was used inside the Mods menu.
        /// </summary>
        /// <param name="optionsType">The type of the options to show. The mod to configure,
        /// configuration directory, and so forth will be retrieved from the provided type.
        /// This type must be the same type configured in RegisterOptions for the mod.</param>
        /// <param name="title">The title to show in the dialog. If null, a default title
        /// will be used.</param>
        /// <param name="onClose">The method to call when the dialog is closed.</param>
        public static void ShowNow(Type optionsType, string title = null,
                                   Action <object> onClose        = null)
        {
#if OPTIONS_ONLY
            ShowDialog(optionsType, title, onClose);
#else
            Type forwardType;
            if (optionsType == null)
            {
                throw new ArgumentNullException("optionsType");
            }
            // Find latest version if possible
            lock (PSharedData.GetLock(PRegistry.KEY_OPTIONS_LOCK)) {
                forwardType = PSharedData.GetData <Type>(PRegistry.KEY_OPTIONS_LATEST);
            }
            if (forwardType == null)
            {
                forwardType = typeof(POptions);
            }
            try {
                var method = forwardType.GetMethod(nameof(ShowDialog), BindingFlags.Static |
                                                   BindingFlags.NonPublic, null, new Type[] { typeof(Type), typeof(string),
                                                                                              typeof(Action <object>) }, null);
                // Forward call to that version
                if (method != null)
                {
                    method.Invoke(null, new object[] { optionsType, title, onClose });
                }
                else
                {
                    PUtil.LogWarning("No call to show options dialog found!");
                    ShowDialog(optionsType, title, onClose);
                }
            } catch (AmbiguousMatchException e) {
                PUtil.LogException(e);
            }
#endif
        }
コード例 #21
0
ファイル: PLocalization.cs プロジェクト: pether-pg/ONIMods
 /// <summary>
 /// Localizes all mods which registered for it.
 /// </summary>
 /// <param name="locale">The locale to use.</param>
 internal static void LocalizeAll(Localization.Locale locale)
 {
     if (locale == null)
     {
         throw new ArgumentNullException("locale");
     }
     lock (PSharedData.GetLock(PRegistry.KEY_LOCALE_LOCK)) {
         // Get list holding locale information
         var list = PSharedData.GetData <IList <Assembly> >(PRegistry.KEY_LOCALE_TABLE);
         if (list != null)
         {
             PUtil.LogDebug("Localizing {0:D} mods to locale {1}".F(list.Count,
                                                                    locale.Code));
             foreach (var mod in list)
             {
                 if (mod != null)
                 {
                     Localize(mod, POptions.GetModDir(mod), locale);
                 }
             }
         }
     }
 }
コード例 #22
0
        /// <summary>
        /// Reports whether another Reimagination mod with the specified mod ID is loaded.
        /// Only usable in postload patches or later.
        /// </summary>
        /// <param name="modID">The mod ID to check, typically the namespace of its root
        /// type.</param>
        /// <returns>true if that mod has been loaded and called Init(), or false otherwise.</returns>
        public static bool IsModLoaded(string modID)
        {
            var imag = PSharedData.GetData <IDictionary <string, Assembly> >(IMAGINATION_TABLE);

            return(imag != null && imag.ContainsKey(modID));
        }