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 @@ + + + + +