From d813c4e2c8522584beaf1432725b4cdd2cc251b5 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 8 Aug 2022 22:27:07 -0400 Subject: fix log parsing for invalid content packs (#860) --- src/SMAPI.Web/Framework/LogParsing/LogParser.cs | 10 ++++---- .../Framework/LogParsing/Models/LogModInfo.cs | 22 ++++++++---------- .../Framework/LogParsing/Models/ModType.cs | 15 ++++++++++++ src/SMAPI.Web/ViewModels/LogParserModel.cs | 2 +- src/SMAPI.Web/Views/LogParser/Index.cshtml | 27 +++++++++++++++++----- 5 files changed, 51 insertions(+), 25 deletions(-) create mode 100644 src/SMAPI.Web/Framework/LogParsing/Models/ModType.cs (limited to 'src') diff --git a/src/SMAPI.Web/Framework/LogParsing/LogParser.cs b/src/SMAPI.Web/Framework/LogParsing/LogParser.cs index 4a110dcd..18ba754c 100644 --- a/src/SMAPI.Web/Framework/LogParsing/LogParser.cs +++ b/src/SMAPI.Web/Framework/LogParsing/LogParser.cs @@ -36,7 +36,7 @@ namespace StardewModdingAPI.Web.Framework.LogParsing private readonly Regex ContentPackListStartPattern = new(@"^Loaded \d+ content packs:$", RegexOptions.Compiled | RegexOptions.IgnoreCase); /// A regex pattern matching an entry in SMAPI's content pack list. - private readonly Regex ContentPackListEntryPattern = new(@"^ (?.+?) (?[^\s]+)(?: by (?[^\|]+))? \| for (?[^\|]+)(?: \| (?.+))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private readonly Regex ContentPackListEntryPattern = new(@"^ (?.+?) (?[^\s]+)(?: by (?[^\|]+))? \| for (?[^\|]*)(?: \| (?.+))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase); /// A regex pattern matching the start of SMAPI's mod update list. private readonly Regex ModUpdateListStartPattern = new(@"^You can update \d+ mods?:$", RegexOptions.Compiled | RegexOptions.IgnoreCase); @@ -77,8 +77,8 @@ namespace StardewModdingAPI.Web.Framework.LogParsing }; // parse log messages - LogModInfo smapiMod = new(name: "SMAPI", author: "Pathoschild", version: "", description: "", loaded: true, isMod: false); - LogModInfo gameMod = new(name: "game", author: "", version: "", description: "", loaded: true, isMod: false); + LogModInfo smapiMod = new(ModType.Special, name: "SMAPI", author: "Pathoschild", version: "", description: "", loaded: true); + LogModInfo gameMod = new(ModType.Special, name: "game", author: "", version: "", description: "", loaded: true); IDictionary> mods = new Dictionary>(); bool inModList = false; bool inContentPackList = false; @@ -133,7 +133,7 @@ namespace StardewModdingAPI.Web.Framework.LogParsing if (!mods.TryGetValue(name, out List? entries)) mods[name] = entries = new List(); - entries.Add(new LogModInfo(name: name, author: author, version: version, description: description, loaded: true)); + entries.Add(new LogModInfo(ModType.CodeMod, name: name, author: author, version: version, description: description, loaded: true)); message.Section = LogSection.ModsList; } @@ -156,7 +156,7 @@ namespace StardewModdingAPI.Web.Framework.LogParsing if (!mods.TryGetValue(name, out List? entries)) mods[name] = entries = new List(); - entries.Add(new LogModInfo(name: name, author: author, version: version, description: description, contentPackFor: forMod, loaded: true)); + entries.Add(new LogModInfo(ModType.ContentPack, name: name, author: author, version: version, description: description, contentPackFor: forMod, loaded: true)); message.Section = LogSection.ContentPackList; } diff --git a/src/SMAPI.Web/Framework/LogParsing/Models/LogModInfo.cs b/src/SMAPI.Web/Framework/LogParsing/Models/LogModInfo.cs index 557f08ff..c81942e4 100644 --- a/src/SMAPI.Web/Framework/LogParsing/Models/LogModInfo.cs +++ b/src/SMAPI.Web/Framework/LogParsing/Models/LogModInfo.cs @@ -48,21 +48,24 @@ namespace StardewModdingAPI.Web.Framework.LogParsing.Models [MemberNotNullWhen(true, nameof(LogModInfo.UpdateVersion), nameof(LogModInfo.UpdateLink))] public bool HasUpdate => this.UpdateVersion != null && this.Version != this.UpdateVersion; + /// The mod type. + public ModType ModType { get; } + /// Whether this is an actual mod (rather than a special entry for SMAPI or the game itself). - public bool IsMod { get; } + public bool IsMod => this.ModType != ModType.Special; /// Whether this is a C# code mod. - public bool IsCodeMod { get; } + public bool IsCodeMod => this.ModType == ModType.CodeMod; /// Whether this is a content pack for another mod. - [MemberNotNullWhen(true, nameof(LogModInfo.ContentPackFor))] - public bool IsContentPack { get; } + public bool IsContentPack => this.ModType == ModType.ContentPack; /********* ** Public methods *********/ /// Construct an instance. + /// The mod type. /// The mod name. /// The mod author. /// The mod version. @@ -72,9 +75,9 @@ namespace StardewModdingAPI.Web.Framework.LogParsing.Models /// The name of the mod for which this is a content pack (if applicable). /// The number of errors logged by this mod. /// Whether the mod was loaded into the game. - /// Whether this is an actual mod (instead of a special entry for SMAPI or the game). - public LogModInfo(string name, string author, string version, string description, string? updateVersion = null, string? updateLink = null, string? contentPackFor = null, int errors = 0, bool loaded = true, bool isMod = true) + public LogModInfo(ModType modType, string name, string author, string version, string description, string? updateVersion = null, string? updateLink = null, string? contentPackFor = null, int errors = 0, bool loaded = true) { + this.ModType = modType; this.Name = name; this.Author = author; this.Description = description; @@ -84,13 +87,6 @@ namespace StardewModdingAPI.Web.Framework.LogParsing.Models this.Errors = errors; this.Loaded = loaded; - if (isMod) - { - this.IsMod = true; - this.IsContentPack = !string.IsNullOrWhiteSpace(this.ContentPackFor); - this.IsCodeMod = !this.IsContentPack; - } - this.OverrideVersion(version); } diff --git a/src/SMAPI.Web/Framework/LogParsing/Models/ModType.cs b/src/SMAPI.Web/Framework/LogParsing/Models/ModType.cs new file mode 100644 index 00000000..363aaaec --- /dev/null +++ b/src/SMAPI.Web/Framework/LogParsing/Models/ModType.cs @@ -0,0 +1,15 @@ +namespace StardewModdingAPI.Web.Framework.LogParsing.Models +{ + /// The type for a instance. + public enum ModType + { + /// A special non-mod entry (e.g. for SMAPI or the game itself). + Special, + + /// A C# mod. + CodeMod, + + /// A content pack loaded by a C# mod. + ContentPack + } +} diff --git a/src/SMAPI.Web/ViewModels/LogParserModel.cs b/src/SMAPI.Web/ViewModels/LogParserModel.cs index c39a9b0a..34d0b4df 100644 --- a/src/SMAPI.Web/ViewModels/LogParserModel.cs +++ b/src/SMAPI.Web/ViewModels/LogParserModel.cs @@ -107,7 +107,7 @@ namespace StardewModdingAPI.Web.ViewModels // group by mod return mods .Where(mod => mod.IsContentPack) - .GroupBy(mod => mod.ContentPackFor!) + .GroupBy(mod => mod.ContentPackFor ?? "") .ToDictionary(group => group.Key, group => group.ToArray()); } diff --git a/src/SMAPI.Web/Views/LogParser/Index.cshtml b/src/SMAPI.Web/Views/LogParser/Index.cshtml index 57e26ace..f71c6ac1 100644 --- a/src/SMAPI.Web/Views/LogParser/Index.cshtml +++ b/src/SMAPI.Web/Views/LogParser/Index.cshtml @@ -352,16 +352,31 @@ else if (log?.IsValid == true) toggle content packs in list } - @foreach (var mod in log.Mods.Where(p => p.Loaded && !p.IsContentPack)) - { - if (contentPacks == null || !contentPacks.TryGetValue(mod.Name, out LogModInfo[]? contentPackList)) - contentPackList = null; + @{ + var modsWithContentPacks = log.Mods + .Where(mod => mod.Loaded && !mod.IsContentPack) + .Select(mod => ( + Mod: mod, + ContentPacks: contentPacks?.TryGetValue(mod.Name, out LogModInfo[]? contentPackList) == true ? contentPackList : Array.Empty() + )) + .ToList(); + if (contentPacks?.TryGetValue("", out LogModInfo[] invalidPacks) == true) + { + modsWithContentPacks.Add(( + Mod: new LogModInfo(ModType.CodeMod, "", "", "", ""), + ContentPacks: invalidPacks + )); + } + } + + @foreach ((LogModInfo mod, LogModInfo[] contentPackList) in modsWithContentPacks) + { @mod.Name @mod.Version - @if (contentPackList != null) + @if (contentPackList.Any()) {
@foreach (var contentPack in contentPackList) @@ -374,7 +389,7 @@ else if (log?.IsValid == true) @mod.Author - @if (contentPackList != null) + @if (contentPackList.Any()) {
@foreach (var contentPack in contentPackList) -- cgit