diff options
-rw-r--r-- | docs/release-notes.md | 1 | ||||
-rw-r--r-- | src/SMAPI.Web/Framework/LogParsing/LogParser.cs | 10 | ||||
-rw-r--r-- | src/SMAPI.Web/Framework/LogParsing/Models/LogModInfo.cs | 22 | ||||
-rw-r--r-- | src/SMAPI.Web/Framework/LogParsing/Models/ModType.cs | 15 | ||||
-rw-r--r-- | src/SMAPI.Web/ViewModels/LogParserModel.cs | 2 | ||||
-rw-r--r-- | src/SMAPI.Web/Views/LogParser/Index.cshtml | 27 |
6 files changed, 52 insertions, 25 deletions
diff --git a/docs/release-notes.md b/docs/release-notes.md index 14421c1a..46d910a9 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -29,6 +29,7 @@ * Added log parser warning about performance of PyTK 1.23.0 or earlier. * Converted images to SVG (thanks to ishan!). * Updated log parser for new update alert format in SMAPI 3.15.1. + * Fixed parsing for invalid content packs. ## 3.15.1 Released 06 July 2022 for Stardew Valley 1.5.6 or later. 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); /// <summary>A regex pattern matching an entry in SMAPI's content pack list.</summary> - private readonly Regex ContentPackListEntryPattern = new(@"^ (?<name>.+?) (?<version>[^\s]+)(?: by (?<author>[^\|]+))? \| for (?<for>[^\|]+)(?: \| (?<description>.+))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private readonly Regex ContentPackListEntryPattern = new(@"^ (?<name>.+?) (?<version>[^\s]+)(?: by (?<author>[^\|]+))? \| for (?<for>[^\|]*)(?: \| (?<description>.+))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase); /// <summary>A regex pattern matching the start of SMAPI's mod update list.</summary> 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<string, List<LogModInfo>> mods = new Dictionary<string, List<LogModInfo>>(); bool inModList = false; bool inContentPackList = false; @@ -133,7 +133,7 @@ namespace StardewModdingAPI.Web.Framework.LogParsing if (!mods.TryGetValue(name, out List<LogModInfo>? entries)) mods[name] = entries = new List<LogModInfo>(); - 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<LogModInfo>? entries)) mods[name] = entries = new List<LogModInfo>(); - 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; + /// <summary>The mod type.</summary> + public ModType ModType { get; } + /// <summary>Whether this is an actual mod (rather than a special entry for SMAPI or the game itself).</summary> - public bool IsMod { get; } + public bool IsMod => this.ModType != ModType.Special; /// <summary>Whether this is a C# code mod.</summary> - public bool IsCodeMod { get; } + public bool IsCodeMod => this.ModType == ModType.CodeMod; /// <summary>Whether this is a content pack for another mod.</summary> - [MemberNotNullWhen(true, nameof(LogModInfo.ContentPackFor))] - public bool IsContentPack { get; } + public bool IsContentPack => this.ModType == ModType.ContentPack; /********* ** Public methods *********/ /// <summary>Construct an instance.</summary> + /// <param name="modType">The mod type.</param> /// <param name="name">The mod name.</param> /// <param name="author">The mod author.</param> /// <param name="version">The mod version.</param> @@ -72,9 +75,9 @@ namespace StardewModdingAPI.Web.Framework.LogParsing.Models /// <param name="contentPackFor">The name of the mod for which this is a content pack (if applicable).</param> /// <param name="errors">The number of errors logged by this mod.</param> /// <param name="loaded">Whether the mod was loaded into the game.</param> - /// <param name="isMod">Whether this is an actual mod (instead of a special entry for SMAPI or the game).</param> - 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 +{ + /// <summary>The type for a <see cref="LogModInfo"/> instance.</summary> + public enum ModType + { + /// <summary>A special non-mod entry (e.g. for SMAPI or the game itself).</summary> + Special, + + /// <summary>A C# mod.</summary> + CodeMod, + + /// <summary>A content pack loaded by a C# mod.</summary> + 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) <span class="notice btn txt" v-on:click="toggleContentPacks">toggle content packs in list</span> } </caption> - @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<LogModInfo>() + )) + .ToList(); + if (contentPacks?.TryGetValue("", out LogModInfo[] invalidPacks) == true) + { + modsWithContentPacks.Add(( + Mod: new LogModInfo(ModType.CodeMod, "<invalid content packs>", "", "", ""), + ContentPacks: invalidPacks + )); + } + } + + @foreach ((LogModInfo mod, LogModInfo[] contentPackList) in modsWithContentPacks) + { <tr v-on:click="toggleMod('@Model.GetSlug(mod.Name)')" class="mod-entry" v-bind:class="{ hidden: !showMods['@Model.GetSlug(mod.Name)'] }"> <td><input type="checkbox" v-bind:checked="showMods['@Model.GetSlug(mod.Name)']" v-bind:class="{ invisible: !anyModsHidden }" /></td> <td> <strong v-pre>@mod.Name</strong> @mod.Version - @if (contentPackList != null) + @if (contentPackList.Any()) { <div v-if="!hideContentPacks" class="content-packs"> @foreach (var contentPack in contentPackList) @@ -374,7 +389,7 @@ else if (log?.IsValid == true) </td> <td> @mod.Author - @if (contentPackList != null) + @if (contentPackList.Any()) { <div v-if="!hideContentPacks" class="content-packs"> @foreach (var contentPack in contentPackList) |