private static void ProcessUMFMod(string modName)
        {
            Logger.Log("Processing UMF mod '" + modName + "'");
            Type[]            gadgetTypes = GadgetCoreAPI.GetUMFAPI().GetModAssembly(modName).GetExportedTypes().Where(x => x.IsSubclassOf(typeof(Gadget)) && x.GetCustomAttributes(typeof(GadgetAttribute), true).FirstOrDefault() != null).ToArray();
            List <GadgetInfo> gadgets     = new List <GadgetInfo>();

            for (int i = 0; i < gadgetTypes.Length; i++)
            {
                Type            type      = gadgetTypes[i];
                GadgetAttribute attribute = (GadgetAttribute)type.GetCustomAttributes(typeof(GadgetAttribute), true).FirstOrDefault();
                if (gadgets.Any(x => x.Attribute.Name == attribute.Name))
                {
                    throw new InvalidOperationException("It is illegal for a mod to contain multiple Gadgets with the same name: " + attribute.Name);
                }
                int[] targetVersionNums = attribute.TargetGCVersion.Split('.').Select(x => int.Parse(x)).ToArray();
                if (targetVersionNums.Length != 4)
                {
                    Array.Resize(ref targetVersionNums, 4);
                }
                if ((attribute.GadgetCoreVersionSpecificity == VersionSpecificity.MAJOR && GadgetCoreAPI.currentVersionNums[0] == targetVersionNums[0] && (GadgetCoreAPI.currentVersionNums[1] > targetVersionNums[1] || (GadgetCoreAPI.currentVersionNums[1] == targetVersionNums[1] && (GadgetCoreAPI.currentVersionNums[2] > targetVersionNums[2] || (GadgetCoreAPI.currentVersionNums[2] == targetVersionNums[2] && GadgetCoreAPI.currentVersionNums[3] >= targetVersionNums[3]))))) ||
                    (attribute.GadgetCoreVersionSpecificity == VersionSpecificity.MINOR && GadgetCoreAPI.currentVersionNums[0] == targetVersionNums[0] && GadgetCoreAPI.currentVersionNums[1] == targetVersionNums[1] && (GadgetCoreAPI.currentVersionNums[2] > targetVersionNums[2] || (GadgetCoreAPI.currentVersionNums[2] == targetVersionNums[2] && GadgetCoreAPI.currentVersionNums[3] >= targetVersionNums[3]))) ||
                    (attribute.GadgetCoreVersionSpecificity == VersionSpecificity.NONBREAKING && GadgetCoreAPI.currentVersionNums[0] == targetVersionNums[0] && GadgetCoreAPI.currentVersionNums[1] == targetVersionNums[1] && GadgetCoreAPI.currentVersionNums[2] == targetVersionNums[2] && GadgetCoreAPI.currentVersionNums[3] >= targetVersionNums[3]) ||
                    (attribute.GadgetCoreVersionSpecificity == VersionSpecificity.BUGFIX && GadgetCoreAPI.currentVersionNums[0] == targetVersionNums[0] && GadgetCoreAPI.currentVersionNums[1] == targetVersionNums[1] && GadgetCoreAPI.currentVersionNums[2] == targetVersionNums[2] && GadgetCoreAPI.currentVersionNums[3] == targetVersionNums[3]))
                {
                    Gadget gadget = null;
                    try
                    {
                        gadget = Activator.CreateInstance(type) as Gadget;
                        if (gadget != null)
                        {
                            Logger.Log("Found Gadget to load: " + attribute.Name + ", in UMF mod: {" + modName + "}");
                            GadgetInfo info = new GadgetInfo(gadget, attribute, modName);
                            gadget.Logger = new GadgetLogger(modName, attribute.Name);
                            gadget.Config = new GadgetConfig(Path.Combine(GadgetPaths.ConfigsPath, modName + ".ini"), attribute.Name);
                            Gadgets.RegisterGadget(info);
                            gadgets.Add(info);
                            if (!BatchLoading)
                            {
                                QueuedGadgets.Add(info);
                                EnableQueuedGadgets();
                            }
                        }
                    }
                    catch (Exception) { }
                    finally
                    {
                        if (gadget == null)
                        {
                            Logger.LogWarning("Found Gadget that could not be constructed: " + attribute.Name + ", in UMF mod: {" + modName + "}");
                        }
                    }
                }
                else
                {
                    int rD = (int)attribute.GadgetCoreVersionSpecificity;
                    Logger.LogWarning("Found Gadget with an incompatible version: " + attribute.Name + ", in UMF mod: {" + modName + "}. Requires version: " + new string(attribute.TargetGCVersion.TakeWhile(x => (x == '.' ? --rD : rD) > 0).ToArray()));
                }
            }
        }
 private static void LoadGadgetMod(GadgetMod mod)
 {
     Logger.Log("Loading mod '" + mod.Name + "'");
     if (mod.ModDependencies.Any(x => GadgetMods.GetModByName(x) == null))
     {
         m_IncompatibleMods.Add(mod);
         Logger.LogWarning("Aborted loading mod '" + mod.Name + "' because of the following missing dependencies: " + mod.ModDependencies.Where(x => GadgetMods.GetModByName(x) == null).Concat());
         return;
     }
     Type[] gadgetTypes = mod.Assembly.GetExportedTypes().Where(x => x.IsSubclassOf(typeof(Gadget)) && x.GetCustomAttributes(typeof(GadgetAttribute), true).FirstOrDefault() != null).ToArray();
     if (gadgetTypes.Length == 0)
     {
         m_EmptyMods.Add(mod);
         Logger.LogWarning("Aborted loading mod '" + mod.Name + "' because it does not contain any Gadgets");
     }
     mod.m_LoadedGadgets   = new List <GadgetInfo>();
     mod.LoadedGadgets     = new ReadOnlyCollection <GadgetInfo>(mod.m_LoadedGadgets);
     mod.m_UnloadedGadgets = new List <GadgetInfo>();
     mod.UnloadedGadgets   = new ReadOnlyCollection <GadgetInfo>(mod.m_UnloadedGadgets);
     for (int i = 0; i < gadgetTypes.Length; i++)
     {
         Type            type      = gadgetTypes[i];
         GadgetAttribute attribute = (GadgetAttribute)type.GetCustomAttributes(typeof(GadgetAttribute), true).FirstOrDefault();
         if (mod.m_LoadedGadgets.Any(x => x.Attribute.Name == attribute.Name))
         {
             throw new InvalidOperationException("It is illegal for a mod to contain multiple Gadgets with the same name: " + attribute.Name);
         }
         int[] targetVersionNums = attribute.TargetGCVersion.Split('.').Select(x => int.Parse(x)).ToArray();
         if (targetVersionNums.Length != 4)
         {
             Array.Resize(ref targetVersionNums, 4);
         }
         if ((attribute.GadgetCoreVersionSpecificity == VersionSpecificity.MAJOR && GadgetCoreAPI.currentVersionNums[0] == targetVersionNums[0] && (GadgetCoreAPI.currentVersionNums[1] > targetVersionNums[1] || (GadgetCoreAPI.currentVersionNums[1] == targetVersionNums[1] && (GadgetCoreAPI.currentVersionNums[2] > targetVersionNums[2] || (GadgetCoreAPI.currentVersionNums[2] == targetVersionNums[2] && GadgetCoreAPI.currentVersionNums[3] >= targetVersionNums[3]))))) ||
             (attribute.GadgetCoreVersionSpecificity == VersionSpecificity.MINOR && GadgetCoreAPI.currentVersionNums[0] == targetVersionNums[0] && GadgetCoreAPI.currentVersionNums[1] == targetVersionNums[1] && (GadgetCoreAPI.currentVersionNums[2] > targetVersionNums[2] || (GadgetCoreAPI.currentVersionNums[2] == targetVersionNums[2] && GadgetCoreAPI.currentVersionNums[3] >= targetVersionNums[3]))) ||
             (attribute.GadgetCoreVersionSpecificity == VersionSpecificity.NONBREAKING && GadgetCoreAPI.currentVersionNums[0] == targetVersionNums[0] && GadgetCoreAPI.currentVersionNums[1] == targetVersionNums[1] && GadgetCoreAPI.currentVersionNums[2] == targetVersionNums[2] && GadgetCoreAPI.currentVersionNums[3] >= targetVersionNums[3]) ||
             (attribute.GadgetCoreVersionSpecificity == VersionSpecificity.BUGFIX && GadgetCoreAPI.currentVersionNums[0] == targetVersionNums[0] && GadgetCoreAPI.currentVersionNums[1] == targetVersionNums[1] && GadgetCoreAPI.currentVersionNums[2] == targetVersionNums[2] && GadgetCoreAPI.currentVersionNums[3] == targetVersionNums[3]))
         {
             Gadget gadget = null;
             try
             {
                 gadget = Activator.CreateInstance(type) as Gadget;
             }
             catch (Exception e)
             {
                 Logger.LogWarning("Found Gadget that could not be constructed: " + attribute.Name + ", in mod: {" + mod.Name + "}: Error: " + e);
             }
             if (gadget != null)
             {
                 try
                 {
                     Logger.Log("Found Gadget to load: " + attribute.Name + ", in mod: {" + mod.Name + "}");
                     gadget.CreateSingleton(gadget);
                     GadgetInfo info = new GadgetInfo(gadget, attribute, mod);
                     gadget.Logger = new GadgetLogger(mod.Name, attribute.Name);
                     gadget.Config = new GadgetConfig(Path.Combine(GadgetPaths.ConfigsPath, mod.Name + ".ini"), attribute.Name);
                     Gadgets.RegisterGadget(info);
                     mod.m_LoadedGadgets.Add(info);
                     if (!BatchLoading)
                     {
                         QueuedGadgets.Add(info);
                         EnableQueuedGadgets();
                     }
                 }
                 catch (Exception e)
                 {
                     Logger.LogWarning("Found Gadget that had an error during registration: " + attribute.Name + ", in mod: {" + mod.Name + "}. Error: " + e);
                     if (Gadgets.GetGadgetInfo(attribute.Name) != null)
                     {
                         Gadgets.UnregisterGadget(Gadgets.GetGadgetInfo(attribute.Name));
                     }
                 }
             }
         }
         else
         {
             int rD = (int)attribute.GadgetCoreVersionSpecificity;
             Logger.LogWarning("Found Gadget with an incompatible version: " + attribute.Name + ", in mod: {" + mod.Name + "}. Requires version: " + new string(attribute.TargetGCVersion.TakeWhile(x => (x == '.' ? --rD : rD) > 0).ToArray()));
         }
     }
     mod.IsLoaded = true;
 }