From 96005cdea68b3c9114ff9c1f9e86270205f3a820 Mon Sep 17 00:00:00 2001 From: Lisias T Date: Fri, 8 Jul 2022 02:16:32 -0300 Subject: [PATCH] Sanitizer Meta Fixes and Checks. Fetch what to do from the GameData. For simple and straighforward checks and fixes that can be defined on GameData and, so, be patcheable by MM. For: * https://github.com/net-lisias-ksp/TweakScale/issues/258 * https://github.com/net-lisias-ksp/TweakScale/issues/260 --- Source/Scale/PrefabDryCostWriter.cs | 1 + Source/Scale_Sanitizer/Sanitizer/Abstract.cs | 2 +- .../Sanitizer/CheckAbstract.cs | 96 +++++++++++++++++++ .../Sanitizer/CheckPriorityCritical.cs | 29 ++++++ .../Sanitizer/CheckPriorityHigh.cs | 29 ++++++ .../Sanitizer/CheckPriorityLow.cs | 29 ++++++ .../Sanitizer/CheckPriorityNormal.cs | 29 ++++++ .../Sanitizer/CriticalFixes.cs | 4 +- .../Sanitizer/Engines/CheckEngine.cs | 43 +++++++-- .../Sanitizer/Engines/FixEngine.cs | 6 +- Source/Scale_Sanitizer/Sanitizer/HotFixes.cs | 2 +- .../Scale_Sanitizer/Sanitizer/Overrrules.cs | 2 +- .../Scale_Sanitizer/Sanitizer/ShowStoppers.cs | 61 +++++++++--- Source/Scale_Sanitizer/Scale_Sanitizer.csproj | 5 + 14 files changed, 310 insertions(+), 28 deletions(-) create mode 100644 Source/Scale_Sanitizer/Sanitizer/CheckAbstract.cs create mode 100644 Source/Scale_Sanitizer/Sanitizer/CheckPriorityCritical.cs create mode 100644 Source/Scale_Sanitizer/Sanitizer/CheckPriorityHigh.cs create mode 100644 Source/Scale_Sanitizer/Sanitizer/CheckPriorityLow.cs create mode 100644 Source/Scale_Sanitizer/Sanitizer/CheckPriorityNormal.cs diff --git a/Source/Scale/PrefabDryCostWriter.cs b/Source/Scale/PrefabDryCostWriter.cs index a5f65997..5db98d6b 100644 --- a/Source/Scale/PrefabDryCostWriter.cs +++ b/Source/Scale/PrefabDryCostWriter.cs @@ -112,6 +112,7 @@ private void WriteDryCost() foreach (AvailablePart p in PartLoader.LoadedPartsList) { + Log.detail("Procesing part named {0} ; title {1}.", p.name, p.title); { bool containsTweakScale = false; diff --git a/Source/Scale_Sanitizer/Sanitizer/Abstract.cs b/Source/Scale_Sanitizer/Sanitizer/Abstract.cs index 30b7137b..41d21505 100644 --- a/Source/Scale_Sanitizer/Sanitizer/Abstract.cs +++ b/Source/Scale_Sanitizer/Sanitizer/Abstract.cs @@ -31,7 +31,7 @@ public abstract class Abstract : SanityCheck protected abstract bool DoCheck(AvailablePart p, Part prefab); public bool Check(AvailablePart p, Part prefab) { - Log.trace("{0} is checking {1} ({2})...", this.GetType().Name, p.name, p.title); + Log.info("{0} is checking {1} ({2})...", this.GetType().Name, p.name, p.title); bool r = this.DoCheck(p, prefab); Log.trace("{0} was checked and it should{1} stop the chain.", p.name, r ? "" : " not"); return r; diff --git a/Source/Scale_Sanitizer/Sanitizer/CheckAbstract.cs b/Source/Scale_Sanitizer/Sanitizer/CheckAbstract.cs new file mode 100644 index 00000000..cda9deb5 --- /dev/null +++ b/Source/Scale_Sanitizer/Sanitizer/CheckAbstract.cs @@ -0,0 +1,96 @@ +/* + This file is part of TweakScale /L + © 2018-2022 LisiasT + + TweakScale /L is double licensed, as follows: + * SKL 1.0 : https://ksp.lisias.net/SKL-1_0.txt + * GPL 2.0 : https://www.gnu.org/licenses/gpl-2.0.txt + + And you are allowed to choose the License that better suit your needs. + + TweakScale /L is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + You should have received a copy of the SKL Standard License 1.0 + along with TweakScale /L. If not, see . + + You should have received a copy of the GNU General Public License 2.0 + along with TweakScale /L. If not, see . +*/ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace TweakScale.Sanitizer +{ + internal abstract class AbstractCheck : Abstract + { + private int failures = 0; + private int count = 0; + + private readonly Priority priority; + public override Priority Priority => this.priority; + public override int Ocurrences => this.count; + public override int Unscalable => 0; + public override int Failures => this.failures; + public override string Summary => string.Format("{0} {1} checks failed", this.count, this.Priority.ToString()); + + protected AbstractCheck(Priority priority) + { + this.priority = priority; + } + + protected override bool DoCheck(AvailablePart p, Part prefab) + { + string r; + try + { + List checksFailed = this.CheckIntegrity(p, prefab); + r = string.Join("; ", checksFailed.Select(s => s.ToProblems()).ToArray()); + Log.error("Part {0} ({1}) didn't passed the sanity check due {2}.", p.name, p.title, r); + return false; // Non Show Stoppers checks are not meant to halt the process chain. They are warnings. + } + catch (Exception e) + { + ++this.failures; + Log.error("part={0} ({1}) Exception on Sanity Checks: {2}", p.name, p.title, e); + } + return false; // Do not abort check chain. + } + + public override bool EmmitMessageIfNeeded(bool showMessageBox) + { + bool r = this.count > 0; + if (r) GUI.SanityCheckAlertBox.Show(this.count, showMessageBox); + return r; + } + + private List CheckIntegrity(AvailablePart p, Part prefab) + { + List checksFailed = new List(); + { + List checks = new List(); + { + UrlDir.UrlConfig urlc = GameDatabase.Instance.GetConfigs("TWEAKSCALE")[0]; + ConfigNode sanityNodes = urlc.config.GetNode("SANITY"); + foreach (ConfigNode cn in sanityNodes.GetNodes("CHECK")) + { + if (!cn.HasValue("priority") || this.priority.ToString().Equals(cn.GetValue("priority"))) continue; + checks.Add(new Engine.Check.Job(KSPe.ConfigNodeWithSteroids.from(cn))); + } + } + foreach (Engine.Check.Job j in checks) + { + Engine.Check.Result r = Engine.Check.Instance.Execute(j, p, prefab); + if (r.IsProblematic) + { + ++this.count; + checksFailed.Add(r); + } + } + } + return checksFailed; + } + } +} diff --git a/Source/Scale_Sanitizer/Sanitizer/CheckPriorityCritical.cs b/Source/Scale_Sanitizer/Sanitizer/CheckPriorityCritical.cs new file mode 100644 index 00000000..4f12c8eb --- /dev/null +++ b/Source/Scale_Sanitizer/Sanitizer/CheckPriorityCritical.cs @@ -0,0 +1,29 @@ +/* + This file is part of TweakScale /L + © 2018-2022 LisiasT + + TweakScale /L is double licensed, as follows: + * SKL 1.0 : https://ksp.lisias.net/SKL-1_0.txt + * GPL 2.0 : https://www.gnu.org/licenses/gpl-2.0.txt + + And you are allowed to choose the License that better suit your needs. + + TweakScale /L is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + You should have received a copy of the SKL Standard License 1.0 + along with TweakScale /L. If not, see . + + You should have received a copy of the GNU General Public License 2.0 + along with TweakScale /L. If not, see . +*/ +using System; + +namespace TweakScale.Sanitizer.Sanitizer +{ + internal class CriticalCheck : AbstractCheck + { + public CriticalCheck() : base(Priority.Critical) { } + } +} diff --git a/Source/Scale_Sanitizer/Sanitizer/CheckPriorityHigh.cs b/Source/Scale_Sanitizer/Sanitizer/CheckPriorityHigh.cs new file mode 100644 index 00000000..2298e1e7 --- /dev/null +++ b/Source/Scale_Sanitizer/Sanitizer/CheckPriorityHigh.cs @@ -0,0 +1,29 @@ +/* + This file is part of TweakScale /L + © 2018-2022 LisiasT + + TweakScale /L is double licensed, as follows: + * SKL 1.0 : https://ksp.lisias.net/SKL-1_0.txt + * GPL 2.0 : https://www.gnu.org/licenses/gpl-2.0.txt + + And you are allowed to choose the License that better suit your needs. + + TweakScale /L is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + You should have received a copy of the SKL Standard License 1.0 + along with TweakScale /L. If not, see . + + You should have received a copy of the GNU General Public License 2.0 + along with TweakScale /L. If not, see . +*/ +using System; + +namespace TweakScale.Sanitizer.Sanitizer +{ + internal class HighCheck : AbstractCheck + { + public HighCheck() : base(Priority.High) { } + } +} diff --git a/Source/Scale_Sanitizer/Sanitizer/CheckPriorityLow.cs b/Source/Scale_Sanitizer/Sanitizer/CheckPriorityLow.cs new file mode 100644 index 00000000..e05041c1 --- /dev/null +++ b/Source/Scale_Sanitizer/Sanitizer/CheckPriorityLow.cs @@ -0,0 +1,29 @@ +/* + This file is part of TweakScale /L + © 2018-2022 LisiasT + + TweakScale /L is double licensed, as follows: + * SKL 1.0 : https://ksp.lisias.net/SKL-1_0.txt + * GPL 2.0 : https://www.gnu.org/licenses/gpl-2.0.txt + + And you are allowed to choose the License that better suit your needs. + + TweakScale /L is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + You should have received a copy of the SKL Standard License 1.0 + along with TweakScale /L. If not, see . + + You should have received a copy of the GNU General Public License 2.0 + along with TweakScale /L. If not, see . +*/ +using System; + +namespace TweakScale.Sanitizer.Sanitizer +{ + internal class LowPriorityCheck : AbstractCheck + { + public LowPriorityCheck() : base(Priority.Low) { } + } +} diff --git a/Source/Scale_Sanitizer/Sanitizer/CheckPriorityNormal.cs b/Source/Scale_Sanitizer/Sanitizer/CheckPriorityNormal.cs new file mode 100644 index 00000000..83a98d74 --- /dev/null +++ b/Source/Scale_Sanitizer/Sanitizer/CheckPriorityNormal.cs @@ -0,0 +1,29 @@ +/* + This file is part of TweakScale /L + © 2018-2022 LisiasT + + TweakScale /L is double licensed, as follows: + * SKL 1.0 : https://ksp.lisias.net/SKL-1_0.txt + * GPL 2.0 : https://www.gnu.org/licenses/gpl-2.0.txt + + And you are allowed to choose the License that better suit your needs. + + TweakScale /L is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + You should have received a copy of the SKL Standard License 1.0 + along with TweakScale /L. If not, see . + + You should have received a copy of the GNU General Public License 2.0 + along with TweakScale /L. If not, see . +*/ +using System; + +namespace TweakScale.Sanitizer.Sanitizer +{ + internal class NormalCheck : AbstractCheck + { + public NormalCheck() : base(Priority.Normal) { } + } +} diff --git a/Source/Scale_Sanitizer/Sanitizer/CriticalFixes.cs b/Source/Scale_Sanitizer/Sanitizer/CriticalFixes.cs index 9559dae7..8de58075 100644 --- a/Source/Scale_Sanitizer/Sanitizer/CriticalFixes.cs +++ b/Source/Scale_Sanitizer/Sanitizer/CriticalFixes.cs @@ -24,7 +24,7 @@ namespace TweakScale.Sanitizer { - public class CriticalFixes : Abstract + internal class CriticalFixes : Abstract { private int failures = 0; private int count = 0; @@ -109,7 +109,7 @@ private List ApplyFixes(AvailablePart p, Part prefab) foreach (ConfigNode cn in sanityNodes.GetNodes("FIX")) { if (cn.HasValue("priority")) cn.RemoveValues("priority"); // All fixes must be executed on the Critical Priority. - fixes.Add(new Engine.Fix.Job(cn)); + fixes.Add(new Engine.Fix.Job(KSPe.ConfigNodeWithSteroids.from(cn))); } } foreach (Engine.Fix.Job j in fixes) if (Engine.Fix.Job.Correction.RemoveTweakScaleModule == j.correction) diff --git a/Source/Scale_Sanitizer/Sanitizer/Engines/CheckEngine.cs b/Source/Scale_Sanitizer/Sanitizer/Engines/CheckEngine.cs index 4ed8e8dd..f383e3b1 100644 --- a/Source/Scale_Sanitizer/Sanitizer/Engines/CheckEngine.cs +++ b/Source/Scale_Sanitizer/Sanitizer/Engines/CheckEngine.cs @@ -23,6 +23,8 @@ using System; using System.Collections.Generic; +using KSPe; + namespace TweakScale.Sanitizer.Engine { public class Check @@ -38,17 +40,32 @@ public class Job public readonly string[] conflicts; public readonly string[] dependencies; - public Job(ConfigNode cn) + public Job(ConfigNodeWithSteroids cn) { this.name = cn.GetValue("name"); - this.descriptionText = cn.GetValue("description_text"); - this.issueText = cn.GetValue("issue_text"); - this.issueLink = System.Uri.UnescapeDataString(cn.GetValue("issue_link")); - this.supportLink = System.Uri.UnescapeDataString(cn.GetValue("support_link")); + this.descriptionText = cn.GetValue("description_text", ""); + this.issueText = cn.GetValue("issue_text", ""); + this.issueLink = System.Uri.UnescapeDataString(cn.GetValue("issue_link","")); + this.supportLink = System.Uri.UnescapeDataString(cn.GetValue("support_link","")); this.module = cn.GetValue("module_affected"); this.conflicts = cn.GetValues("module_conflicting"); this.dependencies = cn.GetValues("module_dependency"); } + + public string GetLogDescription(string defaultDesc) + { + string r = string.IsNullOrEmpty(this.descriptionText) ? defaultDesc : this.descriptionText; + if (!string.IsNullOrEmpty(this.issueText)) r += string.Format(". {0}", this.issueText); + if (!string.IsNullOrEmpty(this.issueLink)) r += string.Format("({0})" + this.issueLink); + return r; + } + + public string GetScreenDescription(string defaultDesc) + { + string r = string.IsNullOrEmpty(this.descriptionText) ? defaultDesc : this.descriptionText; + if (!string.IsNullOrEmpty(this.supportLink)) r += string.Format(". Visit this link for further information", this.issueText); + return r; + } } public class Result @@ -58,6 +75,7 @@ public class Result public readonly Part prefab; public string[] Conflicts { get; private set;} public string[] MissingDependencies { get; private set;} + public bool IsProblematic => !(0 == this.Conflicts.Length && 0 == this.MissingDependencies.Length); public Result(Job job, AvailablePart p, Part prefab) { @@ -82,11 +100,18 @@ public void Execute() this.MissingDependencies = missing.ToArray(); } - public override string ToString() + public string ToLog() + { + if (0 != this.Conflicts.Length && 0 != this.MissingDependencies.Length) + return string.Format("{0} ({1}) passed the sanity check {2}", this.availablePart.name, this.availablePart.title, this.job.name); + return string.Format("{0} ({1}) failed the sanity check {2} due {3}", this.availablePart.name, this.availablePart.title, this.job.name, this.job.GetLogDescription(this.ToProblems())); + } + + public string ToScreen() { if (0 != this.Conflicts.Length && 0 != this.MissingDependencies.Length) return string.Format("{0} ({1}) passed the sanity check {2}", this.availablePart.name, this.availablePart.title, this.job.name); - return string.Format("{0} ({1}) failed the sanity check {2} due {3}", this.availablePart.name, this.availablePart.title, this.job.name, this.ToProblems()); + return string.Format("{0} ({1}) failed the sanity check {2} due {3}", this.availablePart.name, this.availablePart.title, this.job.name, this.job.GetScreenDescription(this.ToProblems())); } public string ToProblems() @@ -101,7 +126,7 @@ public string ToProblems() } private string ToMissingDependencies() => - string.Format("have a Conflict between {0} and {1}", this.job.module, string.Join(",", this.Conflicts)); + string.Format("have a conflict between {0} and {1}", this.job.module, string.Join(",", this.Conflicts)); private string ToConflicts() => string.Format("{0} didn't met dependency(ies) {1}", this.job.module, string.Join(",", this.MissingDependencies)); @@ -115,7 +140,7 @@ public Result Execute(Job job, AvailablePart p, Part part) { Result r = new Result(job, p, part); r.Execute(); - Log.detail(r.ToString()); + Log.detail(r.ToLog()); return r; } diff --git a/Source/Scale_Sanitizer/Sanitizer/Engines/FixEngine.cs b/Source/Scale_Sanitizer/Sanitizer/Engines/FixEngine.cs index abd8ae25..5ddf5879 100644 --- a/Source/Scale_Sanitizer/Sanitizer/Engines/FixEngine.cs +++ b/Source/Scale_Sanitizer/Sanitizer/Engines/FixEngine.cs @@ -22,6 +22,8 @@ */ using System; +using KSPe; + namespace TweakScale.Sanitizer.Engine { public class Fix : Check @@ -36,7 +38,7 @@ public enum Correction public readonly Correction correction; - public Job(ConfigNode cn):base(cn) + public Job(ConfigNodeWithSteroids cn):base(cn) { string action = cn.GetValue("action"); if ("REMOVE_TWEAKSCALE".Equals(action)) this.correction = Correction.RemoveTweakScaleModule; @@ -84,7 +86,7 @@ public void Execute() if (this.CorrectionApplied) Log.detail("Corrections were applied by {0} on {1} ({2})", this.job.name, this.availablePart.name, this.availablePart.title); } - public override string ToString() => this.result.ToString(); + public string ToLog() => this.result.ToLog(); public string ToProblems() => this.result.ToProblems(); } diff --git a/Source/Scale_Sanitizer/Sanitizer/HotFixes.cs b/Source/Scale_Sanitizer/Sanitizer/HotFixes.cs index dacaade2..340e7d20 100644 --- a/Source/Scale_Sanitizer/Sanitizer/HotFixes.cs +++ b/Source/Scale_Sanitizer/Sanitizer/HotFixes.cs @@ -22,7 +22,7 @@ namespace TweakScale.Sanitizer { - public class HotFixes : Abstract + internal class HotFixes : Abstract { private int failures = 0; private int count = 0; diff --git a/Source/Scale_Sanitizer/Sanitizer/Overrrules.cs b/Source/Scale_Sanitizer/Sanitizer/Overrrules.cs index 4bd04f52..9aa33b55 100644 --- a/Source/Scale_Sanitizer/Sanitizer/Overrrules.cs +++ b/Source/Scale_Sanitizer/Sanitizer/Overrrules.cs @@ -22,7 +22,7 @@ namespace TweakScale.Sanitizer { - public class Overrules : Abstract + internal class Overrules : Abstract { private int failures = 0; private int count = 0; diff --git a/Source/Scale_Sanitizer/Sanitizer/ShowStoppers.cs b/Source/Scale_Sanitizer/Sanitizer/ShowStoppers.cs index eabcfd3c..4be8dc4a 100644 --- a/Source/Scale_Sanitizer/Sanitizer/ShowStoppers.cs +++ b/Source/Scale_Sanitizer/Sanitizer/ShowStoppers.cs @@ -19,10 +19,12 @@ along with TweakScale /L. If not, see . */ using System; +using System.Collections.Generic; +using System.Linq; namespace TweakScale.Sanitizer { - public class ShowStoppers : Abstract + internal class ShowStoppers : Abstract { private int failures = 0; private int count = 0; @@ -52,6 +54,16 @@ protected override bool DoCheck(AvailablePart p, Part prefab) ++this.count; return true; // Abort the check chain for this part. } + + { + List checksFailed = this.CheckIntegrity(p, prefab); + if(0 != checksFailed.Count) + { + r = string.Join("; ", checksFailed.Select(s => s.ToProblems()).ToArray()); + Log.error("**FATAL** Part {0} ({1}) has a fatal problem due {2}.", p.name, p.title, r); + return true; + } + } } catch (Exception e) { @@ -74,23 +86,48 @@ private string CheckForShowStoppers(Part p) ConfigNode part = Abstract.GetMeThatConfigNode(p); if (null == part) return "having a part without a partInfo! - see issue [#237]( https://github.com/net-lisias-ksp/TweakScale/issues/237"; + foreach (ConfigNode basket in part.GetNodes("MODULE")) { - foreach (ConfigNode basket in part.GetNodes("MODULE")) + string moduleName = basket.GetValue("name"); + if ("TweakScale" != moduleName) continue; + if (basket.HasValue("ISSUE_OVERRULE")) continue; // TODO: Check if the issue overrule is for #34 or any other that is checked here. + Log.dbg("\tModule {0}", moduleName); + foreach (ConfigNode.Value property in basket.values) { - string moduleName = basket.GetValue("name"); - if ("TweakScale" != moduleName) continue; - if (basket.HasValue("ISSUE_OVERRULE")) continue; // TODO: Check if the issue overrule is for #34 or any other that is checked here. - Log.dbg("\tModule {0}", moduleName); - foreach (ConfigNode.Value property in basket.values) - { - Log.dbg("\t\t{0} = {1}", property.name, property.value); - if (1 != basket.GetValues(property.name).Length) - return "having duplicated properties - see issue [#34]( https://github.com/net-lisias-ksp/TweakScale/issues/34 )"; - } + Log.dbg("\t\t{0} = {1}", property.name, property.value); + if (1 != basket.GetValues(property.name).Length) + return "having duplicated properties - see issue [#34]( https://github.com/net-lisias-ksp/TweakScale/issues/34 )"; } } return null; } + + private List CheckIntegrity(AvailablePart p, Part prefab) + { + List checksFailed = new List(); + { + List checks = new List(); + { + UrlDir.UrlConfig urlc = GameDatabase.Instance.GetConfigs("TWEAKSCALE")[0]; + ConfigNode sanityNodes = urlc.config.GetNode("SANITY"); + foreach (ConfigNode cn in sanityNodes.GetNodes("CHECK")) + { + if (!cn.HasValue("priority") || this.Priority.ToString().Equals(cn.GetValue("priority"))) continue; + checks.Add(new Engine.Check.Job(KSPe.ConfigNodeWithSteroids.from(cn))); + } + } + foreach (Engine.Check.Job j in checks) + { + Engine.Check.Result r = Engine.Check.Instance.Execute(j, p, prefab); + if (r.IsProblematic) + { + ++this.count; + checksFailed.Add(r); + } + } + } + return checksFailed; + } } } diff --git a/Source/Scale_Sanitizer/Scale_Sanitizer.csproj b/Source/Scale_Sanitizer/Scale_Sanitizer.csproj index a44151c5..1a30b8fd 100644 --- a/Source/Scale_Sanitizer/Scale_Sanitizer.csproj +++ b/Source/Scale_Sanitizer/Scale_Sanitizer.csproj @@ -61,6 +61,11 @@ + + + + +