예제 #1
0
 private static bool HasActivePatches(HarmonyLib.Patches patches)
 {
     return(patches != null &&
            ((patches.Prefixes != null && patches.Prefixes.Count != 0) ||
             (patches.Postfixes != null && patches.Postfixes.Count != 0) ||
             (patches.Transpilers != null && patches.Transpilers.Count != 0)));
 }
        public MethodMeta(MethodBase m, HarmonyLib.Patches p)
        {
            this.method    = m;
            this.patches   = p;
            this.methodStr = Utility.GetSignature(method);

            if (p != null)
            {
                this.summaryStr = StackTraceUtility.SummaryString(p);
                this.patchCount = p.Owners.Where(Utility.IsNotAnalyzerPatch).Count();
            }
            else
            {
                this.summaryStr = "";
                this.patchCount = 0;
            }

            var foundMod = StackTraceUtility.mods.TryGetValue(m.DeclaringType.Assembly, out mod);

            if (foundMod)
            {
                return;
            }

            // We add Assembly-CSharp into the `mods` dict, so all we
            // need to check is the UnityEngine components.
            if (!foundMod && m.DeclaringType.Assembly.FullName.Contains("UnityEngine"))
            {
                this.mod = "Rimworld";
            }
            else
            {
                this.mod = "Unknown";
            }
        }
        public static bool CheckForCompetition(this HarmonyLib.Patches patches, HarmonyLib.Harmony domesticHarmoy, out string debugInfo, ReadOnlyCollection <string> ignoreList = null)
        {
            bool Result = CheckForCompetition(patches, domesticHarmoy, out StringBuilder debugInfoBuilder, ignoreList);

            debugInfo = debugInfoBuilder.ToString();
            return(Result);
        }
        private static string GetPatchStrings(MethodBase method, HarmonyLib.Patches p)
        {
            const string spacePrefix = "      - "; // 6 spaces

            var retString = new StringBuilder();

            retString.Append("\n" + spacePrefix);
            retString.Append(SummaryString(p));

            return(retString.ToString());
        }
 public static bool CheckForCompetition(this HarmonyLib.Patches patches, HarmonyLib.Harmony domesticHarmoy, out StringBuilder debugInfoBuilder, ReadOnlyCollection <string> ignoreList = null)
 {
     debugInfoBuilder = new StringBuilder(string.Empty);
     patches.GetBoolPrefixes(out ReadOnlyCollection <Patch> BoolPrefixes);
     return
         (CheckCollectionForCompetition(BoolPrefixes, domesticHarmoy, "prefixes", ref debugInfoBuilder, ignoreList) ||
          CheckCollectionForCompetition(patches.Postfixes, domesticHarmoy, "postfixes", ref debugInfoBuilder, ignoreList) ||
          CheckCollectionForCanceling(patches.Postfixes, BoolPrefixes, "postfixes", ref debugInfoBuilder, ignoreList) ||
          CheckCollectionForCompetition(patches.Transpilers, domesticHarmoy, "transpilers", ref debugInfoBuilder, ignoreList) ||
          CheckCollectionForCanceling(patches.Transpilers, BoolPrefixes, "transpilers", ref debugInfoBuilder, ignoreList));
 }
        public static void ProfilePatch()
        {
            var jiff = AccessTools.Method(typeof(StatExtension), nameof(StatExtension.GetStatValueAbstract), new[] { typeof(BuildableDef), typeof(StatDef), typeof(ThingDef) });
            var pre  = new HarmonyMethod(typeof(H_GetStatValue), nameof(PrefixAb));
            var post = new HarmonyMethod(typeof(H_GetStatValue), nameof(Postfix));

            Modbase.Harmony.Patch(jiff, pre, post);

            jiff = AccessTools.Method(typeof(StatExtension), nameof(StatExtension.GetStatValueAbstract), new[] { typeof(AbilityDef), typeof(StatDef), typeof(Pawn) });
            pre  = new HarmonyMethod(typeof(H_GetStatValue), nameof(PrefixAbility));
            Modbase.Harmony.Patch(jiff, pre, post);

            jiff = AccessTools.Method(typeof(StatWorker), nameof(StatWorker.GetValue), new[] { typeof(StatRequest), typeof(bool) });
            pre  = new HarmonyMethod(typeof(H_GetStatValue), nameof(GetValueDetour));
            Modbase.Harmony.Patch(jiff, pre);

            HarmonyMethod go   = new HarmonyMethod(typeof(H_GetStatValue), nameof(PartPrefix));
            HarmonyMethod biff = new HarmonyMethod(typeof(H_GetStatValue), nameof(PartPostfix));

            foreach (Type allLeafSubclass in typeof(StatPart).AllSubclassesNonAbstract())
            {
                try
                {
                    MethodInfo mef = AccessTools.Method(allLeafSubclass, nameof(StatPart.TransformValue), new Type[] { typeof(StatRequest), typeof(float).MakeByRefType() });
                    if (mef.DeclaringType == allLeafSubclass)
                    {
                        HarmonyLib.Patches info = Harmony.GetPatchInfo(mef);
                        bool F = true;
                        if (info != null)
                        {
                            foreach (Patch infoPrefix in info.Prefixes)
                            {
                                if (infoPrefix.PatchMethod == go.method)
                                {
                                    F = false;
                                }
                            }
                        }

                        if (F)
                        {
                            Modbase.Harmony.Patch(mef, go, biff);
                        }
                    }
                }
                catch (Exception e)
                {
                    ThreadSafeLogger.ReportException(e, $"Failed to patch {allLeafSubclass} from {allLeafSubclass.Assembly.FullName} for profiling");
                }
            }
        }
예제 #7
0
        /// <summary>
        /// Returns all patched methods by NPC Adventures mod.
        /// </summary>
        /// <returns>Enumerable patched methods</returns>
        public IEnumerable <PatchedMethod> GetPatchedMethods()
        {
            var methods = this.harmony
                          .GetPatchedMethods()
                          .ToArray();

            foreach (var method in methods)
            {
                HarmonyLib.Patches info = Harmony.GetPatchInfo(method);

                if (info != null && info.Owners.Contains(this.harmony.Id))
                {
                    yield return(new PatchedMethod(method, info));
                }
            }
        }
        public static void UnpatchMethod(MethodInfo method)
        {
            foreach (MethodBase methodBase in Harmony.GetAllPatchedMethods())
            {
                HarmonyLib.Patches infos = Harmony.GetPatchInfo(methodBase);

                var allPatches = infos.Prefixes.Concat(infos.Postfixes, infos.Transpilers, infos.Finalizers);

                if (!allPatches.Any(patch => patch.PatchMethod == method))
                {
                    continue;
                }

                Modbase.Harmony.Unpatch(methodBase, method);
                return;
            }

            Warn("Failed to locate method to unpatch");
        }
예제 #9
0
 internal static void Apply(Harmony harmony)
 {
     harmony.PatchAll(typeof(Patches));
     harmony.PatchAll(typeof(PlanPiece));
     if (Chainloader.PluginInfos.ContainsKey(buildCameraGUID))
     {
         logger.LogInfo("Applying BuildCamera patches");
         harmony.PatchAll(typeof(PatcherBuildCamera));
     }
     if (Chainloader.PluginInfos.ContainsKey(craftFromContainersGUID))
     {
         logger.LogInfo("Applying CraftFromContainers patches");
         harmony.PatchAll(typeof(PatcherCraftFromContainers));
     }
     HarmonyLib.Patches patches = Harmony.GetPatchInfo(typeof(Player).GetMethod("OnSpawned"));
     if (patches?.Owners.Contains(buildShareGUID) == true)
     {
         logger.LogInfo("Applying BuildShare patches");
         harmony.PatchAll(typeof(PatcherBuildShare));
     }
 }
예제 #10
0
        public static IEnumerable <MethodInfo> GetPatchMethods()
        {
            var patches = Harmony.GetAllPatchedMethods().ToList();

            foreach (var patch in patches)
            {
                HarmonyLib.Patches p = null;
                try
                {
                    p = Harmony.GetPatchInfo(patch);
                }
                catch (Exception e)
                {
                    ThreadSafeLogger.ReportException(e, $"Failed to get patch info for {Utility.GetSignature(patch)}");
                    continue;
                }

                if (patch is MethodInfo info && p.Transpilers.Any(p => Utility.IsNotAnalyzerPatch(p.owner)))
                {
                    yield return(info);
                }
            }
        }
        public static string SummaryString(HarmonyLib.Patches patch)
        {
            var sb = new StringBuilder(255);

            void ProcessPatches(ReadOnlyCollection <Patch> patches, string type)
            {
                if (patches.Any() is false)
                {
                    return;
                }

                sb.Append($"{type}: {{ ");

                var first = true;

                foreach (var p in patches.Where(p => Utility.IsNotAnalyzerPatch(p.owner)).OrderBy(s => s.priority))
                {
                    sb.Append((first ? "" : ", ") + $"{ModFromPatchId(p.owner)}");
                    if (type == "Prefixes")
                    {
                        sb.Append((p.PatchMethod.ReturnType == typeof(bool) ? " - destructive" : null));
                    }

                    first = false;
                }

                sb.Append(" } ");
            }

            ProcessPatches(patch.Prefixes, "Prefixes");
            ProcessPatches(patch.Postfixes, "Postfixes");
            ProcessPatches(patch.Transpilers, "Transpilers");
            ProcessPatches(patch.Finalizers, "Finalizers");

            return(sb.ToString());
        }
예제 #12
0
 public PatchedMethod(MethodBase method, HarmonyLib.Patches patchInfo)
 {
     this.Method    = method;
     this.PatchInfo = patchInfo;
 }
 public static void GetBoolPrefixes(this HarmonyLib.Patches patches, out ReadOnlyCollection <Patch> boolPrefixes)
 {
     boolPrefixes = patches.Prefixes.Where(patch => patch.PatchMethod.ReturnType == typeof(bool)).ToList().AsReadOnly();
 }
예제 #14
0
        internal static void EnableQueuedGadgets()
        {
            List <GadgetInfo> preFilteredQueuedGadgets = QueuedGadgets;

            QueuedGadgets = new List <GadgetInfo>();
            foreach (GadgetInfo gadget in preFilteredQueuedGadgets)
            {
                bool valid = true;
                foreach (string dependency in gadget.Attribute.Dependencies)
                {
                    string[]   splitDependency  = dependency.Split(':');
                    GadgetInfo dependencyGadget = Gadgets.GetGadgetInfo(splitDependency[0]);
                    valid = dependencyGadget != null && dependencyGadget.Gadget.Enabled;
                    if (valid)
                    {
                        if (splitDependency.Length == 2)
                        {
                            string versionString     = splitDependency[1].TrimStart('v');
                            int[]  targetVersionNums = versionString.Split('.').Select(x => int.Parse(x)).ToArray();
                            if (targetVersionNums.Length > 4)
                            {
                                continue;
                            }
                            int[] actualVersionNums = dependencyGadget.Mod.Version.ToString().Split('.').Select(x => int.Parse(x)).ToArray();
                            if (targetVersionNums.Length != 4)
                            {
                                Array.Resize(ref targetVersionNums, 4);
                            }
                            if (actualVersionNums.Length != 4)
                            {
                                Array.Resize(ref actualVersionNums, 4);
                            }
                            valid = actualVersionNums[0] == targetVersionNums[0] && actualVersionNums[1] == targetVersionNums[1] && (actualVersionNums[2] > targetVersionNums[2] || (actualVersionNums[2] == targetVersionNums[2] && actualVersionNums[3] >= targetVersionNums[3]));
                        }
                        else if (splitDependency.Length == 3)
                        {
                            string versionString     = splitDependency[1].TrimStart('v');
                            int[]  targetVersionNums = versionString.Split('.').Select(x => int.Parse(x)).ToArray();
                            if (targetVersionNums.Length > 4)
                            {
                                continue;
                            }
                            int[] actualVersionNums = dependencyGadget.Mod.Version.ToString().Split('.').Select(x => int.Parse(x)).ToArray();
                            VersionSpecificity versionSpecificity;
                            try
                            {
                                versionSpecificity = (VersionSpecificity)Enum.Parse(typeof(VersionSpecificity), splitDependency[2], true);
                            }
                            catch (ArgumentException)
                            {
                                Logger.LogWarning("Gadget " + gadget.Attribute.Name + " has an improperly-formatted dependency version string: " + dependency);
                                versionSpecificity = VersionSpecificity.MINOR;
                            }
                            if (targetVersionNums.Length != 4)
                            {
                                Array.Resize(ref targetVersionNums, 4);
                            }
                            if (actualVersionNums.Length != 4)
                            {
                                Array.Resize(ref actualVersionNums, 4);
                            }
                            valid = (versionSpecificity == VersionSpecificity.MAJOR && actualVersionNums[0] == targetVersionNums[0] && (actualVersionNums[1] > targetVersionNums[1] || (actualVersionNums[1] == targetVersionNums[1] && (actualVersionNums[2] > targetVersionNums[2] || (actualVersionNums[2] == targetVersionNums[2] && actualVersionNums[3] >= targetVersionNums[3]))))) ||
                                    (versionSpecificity == VersionSpecificity.MINOR && actualVersionNums[0] == targetVersionNums[0] && actualVersionNums[1] == targetVersionNums[1] && (actualVersionNums[2] > targetVersionNums[2] || (actualVersionNums[2] == targetVersionNums[2] && actualVersionNums[3] >= targetVersionNums[3]))) ||
                                    (versionSpecificity == VersionSpecificity.NONBREAKING && actualVersionNums[0] == targetVersionNums[0] && actualVersionNums[1] == targetVersionNums[1] && actualVersionNums[2] == targetVersionNums[2] && actualVersionNums[3] >= targetVersionNums[3]) ||
                                    (versionSpecificity == VersionSpecificity.BUGFIX && actualVersionNums[0] == targetVersionNums[0] && actualVersionNums[1] == targetVersionNums[1] && actualVersionNums[2] == targetVersionNums[2] && actualVersionNums[3] == targetVersionNums[3]);
                        }
                    }
                }
                if (valid)
                {
                    QueuedGadgets.Add(gadget);
                }
                else
                {
                    gadget.Gadget.Enabled = false;
                    GadgetCoreConfig.enabledGadgets[gadget.Attribute.Name] = false;
                    Gadgets.UnregisterGadget(gadget);
                    Logger.LogWarning("Aborted loading Gadget " + gadget.Attribute.Name + " due to missing dependencies.");
                }
            }
            Logger.Log("Loading Gadget configs...");
            foreach (GadgetInfo gadget in QueuedGadgets.ToList())
            {
                Logger.Log("Loading Config for Gadget '" + gadget.Attribute.Name + "'");
                try
                {
                    gadget.Gadget.LoadConfig();
                }
                catch (Exception e)
                {
                    gadget.Gadget.Enabled = false;
                    GadgetCoreConfig.enabledGadgets[gadget.Attribute.Name] = false;
                    Gadgets.UnregisterGadget(gadget);
                    QueuedGadgets.Remove(gadget);
                    Logger.LogError("Exception Loading Config For Gadget '" + gadget.Attribute.Name + "':" + Environment.NewLine + e.ToString());
                }
            }
            Logger.Log("Done loading Gadget configs.");
            Logger.Log("Preparing Gadgets for patching...");
            foreach (GadgetInfo gadget in QueuedGadgets.ToList())
            {
                Logger.Log("PrePatching Gadget '" + gadget.Attribute.Name + "'");
                try
                {
                    gadget.Gadget.HarmonyInstance = new Harmony(gadget.Mod.Name + "." + gadget.Attribute.Name + ".gadget");
                    gadget.Gadget.PrePatch();
                }
                catch (Exception e)
                {
                    gadget.Gadget.Enabled = false;
                    GadgetCoreConfig.enabledGadgets[gadget.Attribute.Name] = false;
                    Gadgets.UnregisterGadget(gadget);
                    QueuedGadgets.Remove(gadget);
                    Logger.LogError("Exception PrePatching Gadget '" + gadget.Attribute.Name + "':" + Environment.NewLine + e.ToString());
                }
            }
            Logger.Log("Done preparing Gadgets for patching.");
            Logger.Log("Patching Gadgets...");
            foreach (GadgetInfo gadget in QueuedGadgets.ToList())
            {
                int patches = 0, totalMethods = 0, errorPatching = 0, targetMissing = 0;
                try
                {
                    gadget.Mod.Assembly.GetExportedTypes().Do(delegate(Type type)
                    {
                        HarmonyGadgetAttribute attribute = type.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(HarmonyGadgetAttribute)) as HarmonyGadgetAttribute;
                        if (attribute?.Gadget == gadget.Attribute.Name && attribute.RequiredGadgets.All(x => Gadgets.GetGadget(x) != null))
                        {
                            try
                            {
                                List <MethodInfo> methods = gadget.Gadget.HarmonyInstance.CreateClassProcessor(type).Patch();
                                totalMethods += methods?.Count ?? 0;
                                if (methods == null || methods.Count == 0)
                                {
                                    Logger.Log("Skipping patch '" + type.Name + "' for Gadget '" + gadget.Attribute.Name + "': Attribute target does not exist.");
                                    targetMissing++;
                                }
                                else
                                {
                                    patches++;
                                }
                            }
                            catch (Exception e)
                            {
                                if (e.InnerException == null || !e.InnerException.Message.EndsWith("returned an unexpected result: null"))
                                {
                                    Logger.LogError("Exception running patch '" + type.Name + "' for Gadget '" + gadget.Attribute.Name + "': " + Environment.NewLine + e.ToString());
                                    errorPatching++;
                                }
                                else
                                {
                                    Logger.Log("Skipping patch '" + type.Name + "' for Gadget '" + gadget.Attribute.Name + "': TargetMethod returned null.");
                                    targetMissing++;
                                }
                            }
                        }
                    });
                    Logger.Log("Performed " + patches + " patches for '" + gadget.Attribute.Name + "'" + (totalMethods > 0 ? $" ({totalMethods} total methods patched)" : string.Empty) + (errorPatching > 0 ? targetMissing > 0 ? $" ({errorPatching} skipped due to errors, {targetMissing} skipped due to missing targets)" : $" ({errorPatching} skipped due to errors)" : targetMissing > 0 ? $" ({targetMissing} skipped due to missing targets)" : string.Empty));
                }
                catch (Exception e)
                {
                    gadget.Gadget.Enabled = false;
                    GadgetCoreConfig.enabledGadgets[gadget.Attribute.Name] = false;
                    Gadgets.UnregisterGadget(gadget);
                    QueuedGadgets.Remove(gadget);
                    Logger.LogError("Exception patching Gadget '" + gadget.Attribute.Name + "':" + Environment.NewLine + e.ToString());
                }
            }
            Logger.Log("Done patching Gadgets.");
            bool logOverrideWarnings = false;

            foreach (MethodBase patchedMethod in Harmony.GetAllPatchedMethods())
            {
                HarmonyLib.Patches patches = Harmony.GetPatchInfo(patchedMethod);
                if (patches == null)
                {
                    continue;
                }
                Dictionary <string, string> owners = new Dictionary <string, string>();
                List <Patch> overridingPrefixes    = patches.Prefixes.Where(x => x.PatchMethod.ReturnType == typeof(bool) && (x.PatchMethod.GetCustomAttributes(true).FirstOrDefault(a => a.GetType() == typeof(HarmonyOverridesAttribute)) as HarmonyOverridesAttribute)?.Overrides.Length != 0).ToList();
                if (overridingPrefixes != null && overridingPrefixes.Count > 0)
                {
                    foreach (string ownerID in patches.Owners)
                    {
                        if (ownerID == GadgetCore.HarmonyInstance.Id)
                        {
                            owners[ownerID] = "GadgetCore";
                        }
                        else
                        {
                            string[] splitOwnerID = ownerID.Split('.');
                            if (splitOwnerID.Length == 3 && splitOwnerID[2] == "gadget")
                            {
                                GadgetMod  mod    = GadgetMods.GetModByName(splitOwnerID[0]);
                                GadgetInfo gadget = mod?.LoadedGadgets.SingleOrDefault(x => x.Attribute.Name == splitOwnerID[1]);
                                if (gadget != null)
                                {
                                    owners[ownerID] = $"'{splitOwnerID[1]}' from the mod {{{splitOwnerID[0]}}}";
                                }
                                else
                                {
                                    owners[ownerID] = $"Unrecognized patcher '{ownerID}'";
                                }
                            }
                            else
                            {
                                owners[ownerID] = $"Unrecognized patcher '{ownerID}'";
                            }
                        }
                    }
                    IEnumerable <Patch> problematicPrefixes = patches.Prefixes.Where(x => !overridingPrefixes.Contains(x) && (x.PatchMethod.GetCustomAttributes(true).FirstOrDefault(a => a.GetType() == typeof(HarmonyOverriddenAttribute)) as HarmonyOverriddenAttribute)?.Overrides.Length != 0 && overridingPrefixes.Any(
                                                                                         p => x.owner != p.owner &&
                                                                                         (x.PatchMethod.GetCustomAttributes(true).FirstOrDefault(a => a.GetType() == typeof(HarmonyOverriddenAttribute)) as HarmonyOverriddenAttribute)?.Overrides.Contains(p.owner) != true &&
                                                                                         (p.PatchMethod.GetCustomAttributes(true).FirstOrDefault(a => a.GetType() == typeof(HarmonyOverridesAttribute)) as HarmonyOverridesAttribute)?.Overrides.Contains(x.owner) != true &&
                                                                                         x.priority <= p.priority &&
                                                                                         !x.before.Contains(p.owner) &&
                                                                                         !p.after.Contains(x.owner)));
                    IEnumerable <Patch> problematicTranspilers = patches.Transpilers.Where(x => (x.PatchMethod.GetCustomAttributes(true).FirstOrDefault(a => a.GetType() == typeof(HarmonyOverriddenAttribute)) as HarmonyOverriddenAttribute)?.Overrides.Length != 0 && overridingPrefixes.Any(
                                                                                               p => x.owner != p.owner &&
                                                                                               (x.PatchMethod.GetCustomAttributes(true).FirstOrDefault(a => a.GetType() == typeof(HarmonyOverriddenAttribute)) as HarmonyOverriddenAttribute)?.Overrides.Contains(p.owner) != true &&
                                                                                               (p.PatchMethod.GetCustomAttributes(true).FirstOrDefault(a => a.GetType() == typeof(HarmonyOverridesAttribute)) as HarmonyOverridesAttribute)?.Overrides.Contains(x.owner) != true));
                    if (problematicPrefixes != null && problematicPrefixes.Any() || problematicTranspilers != null && problematicTranspilers.Any())
                    {
                        if (!logOverrideWarnings)
                        {
                            logOverrideWarnings = true;
                            Logger.LogWarning("Possibly problematic patch overrides detected!", false);
                        }
                        Logger.Log($"Patches to {patchedMethod.DeclaringType.FullName}.{patchedMethod.Name} by {overridingPrefixes.Select(x => owners[x.owner]).Concat()} may override the following patch{(problematicPrefixes.Count() + problematicTranspilers.Count() > 1 ? "es" : "")}:");
                        if (problematicPrefixes != null)
                        {
                            foreach (Patch patch in problematicPrefixes)
                            {
                                Logger.Log($" - Prefix from {owners[patch.owner]}");
                            }
                        }
                        if (problematicTranspilers != null)
                        {
                            foreach (Patch patch in problematicTranspilers)
                            {
                                Logger.Log($" - Transpiler from {owners[patch.owner]}");
                            }
                        }
                    }
                }
            }
            if (logOverrideWarnings)
            {
                Logger.Log("End of possibly problematic patch overrides.");
            }
            Logger.Log("Creating registries...");
            foreach (GadgetInfo gadget in QueuedGadgets.ToList())
            {
                if (gadget.Gadget.Enabled)
                {
                    foreach (Registry registry in gadget.Gadget.CreateRegistries())
                    {
                        GameRegistry.RegisterRegistry(registry);
                    }
                }
            }
            Logger.Log("Done creating registries.");
            Logger.Log("Initializing Gadgets...");
            foreach (GadgetInfo gadget in QueuedGadgets.ToList())
            {
                Logger.Log("Initializing Gadget '" + gadget.Attribute.Name + "'");
                try
                {
                    Registry.gadgetRegistering = gadget.Gadget.ModID;
                    gadget.Gadget.LoadInternal();
                }
                catch (Exception e)
                {
                    gadget.Gadget.Enabled = false;
                    GadgetCoreConfig.enabledGadgets[gadget.Attribute.Name] = false;
                    Gadgets.UnregisterGadget(gadget);
                    QueuedGadgets.Remove(gadget);
                    Logger.LogError("Exception Initializing Gadget '" + gadget.Attribute.Name + "':" + Environment.NewLine + e.ToString());
                }
                finally
                {
                    Registry.gadgetRegistering = -1;
                }
            }
            Logger.Log("Done initializing Gadgets.");
            QueuedGadgets.Clear();
            GadgetCoreConfig.Update();
        }