detect missing/outdated Error Handler for 'suggested fixes' section
This commit is contained in:
parent
f3a4b316b7
commit
0ba4fd1785
|
@ -18,6 +18,7 @@
|
||||||
* The [FluentHttpClient package](https://github.com/Pathoschild/FluentHttpClient#readme) is now loaded by SMAPI.
|
* The [FluentHttpClient package](https://github.com/Pathoschild/FluentHttpClient#readme) is now loaded by SMAPI.
|
||||||
|
|
||||||
* For the web UI:
|
* For the web UI:
|
||||||
|
* The log parser now detects a missing or outdated Error Handler mod for its 'suggested fixes' section.
|
||||||
* Updated the JSON validator/schema for Content Patcher 1.27.0.
|
* Updated the JSON validator/schema for Content Patcher 1.27.0.
|
||||||
* Fixed the mod count in the log parser metadata.
|
* Fixed the mod count in the log parser metadata.
|
||||||
|
|
||||||
|
|
|
@ -200,6 +200,8 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
|
||||||
log.GameVersion = match.Groups["gameVersion"].Value;
|
log.GameVersion = match.Groups["gameVersion"].Value;
|
||||||
log.OperatingSystem = match.Groups["os"].Value;
|
log.OperatingSystem = match.Groups["os"].Value;
|
||||||
smapiMod.OverrideVersion(log.ApiVersion);
|
smapiMod.OverrideVersion(log.ApiVersion);
|
||||||
|
|
||||||
|
log.ApiVersionParsed = smapiMod.GetParsedVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
// mod path line
|
// mod path line
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
|
using System;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using StardewModdingAPI.Toolkit;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Web.Framework.LogParsing.Models
|
namespace StardewModdingAPI.Web.Framework.LogParsing.Models
|
||||||
{
|
{
|
||||||
/// <summary>Metadata about a mod or content pack in the log.</summary>
|
/// <summary>Metadata about a mod or content pack in the log.</summary>
|
||||||
public class LogModInfo
|
public class LogModInfo
|
||||||
{
|
{
|
||||||
|
/*********
|
||||||
|
** Private fields
|
||||||
|
*********/
|
||||||
|
/// <summary>The parsed mod version, if valid.</summary>
|
||||||
|
private Lazy<ISemanticVersion?> ParsedVersionImpl;
|
||||||
|
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
** Accessors
|
** Accessors
|
||||||
*********/
|
*********/
|
||||||
|
@ -68,7 +77,6 @@ namespace StardewModdingAPI.Web.Framework.LogParsing.Models
|
||||||
{
|
{
|
||||||
this.Name = name;
|
this.Name = name;
|
||||||
this.Author = author;
|
this.Author = author;
|
||||||
this.Version = version;
|
|
||||||
this.Description = description;
|
this.Description = description;
|
||||||
this.UpdateVersion = updateVersion;
|
this.UpdateVersion = updateVersion;
|
||||||
this.UpdateLink = updateLink;
|
this.UpdateLink = updateLink;
|
||||||
|
@ -82,6 +90,8 @@ namespace StardewModdingAPI.Web.Framework.LogParsing.Models
|
||||||
this.IsContentPack = !string.IsNullOrWhiteSpace(this.ContentPackFor);
|
this.IsContentPack = !string.IsNullOrWhiteSpace(this.ContentPackFor);
|
||||||
this.IsCodeMod = !this.IsContentPack;
|
this.IsCodeMod = !this.IsContentPack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.OverrideVersion(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Add an update alert for this mod.</summary>
|
/// <summary>Add an update alert for this mod.</summary>
|
||||||
|
@ -95,9 +105,29 @@ namespace StardewModdingAPI.Web.Framework.LogParsing.Models
|
||||||
|
|
||||||
/// <summary>Override the version number, for cases like SMAPI itself where the version is only known later during parsing.</summary>
|
/// <summary>Override the version number, for cases like SMAPI itself where the version is only known later during parsing.</summary>
|
||||||
/// <param name="version">The new mod version.</param>
|
/// <param name="version">The new mod version.</param>
|
||||||
|
[MemberNotNull(nameof(LogModInfo.Version), nameof(LogModInfo.ParsedVersionImpl))]
|
||||||
public void OverrideVersion(string version)
|
public void OverrideVersion(string version)
|
||||||
{
|
{
|
||||||
this.Version = version;
|
this.Version = version;
|
||||||
|
this.ParsedVersionImpl = new Lazy<ISemanticVersion?>(this.ParseVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Get the semantic version for this mod, if it's valid.</summary>
|
||||||
|
public ISemanticVersion? GetParsedVersion()
|
||||||
|
{
|
||||||
|
return this.ParsedVersionImpl.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********
|
||||||
|
** Private methods
|
||||||
|
*********/
|
||||||
|
/// <summary>Get the semantic version for this mod, if it's valid.</summary>
|
||||||
|
public ISemanticVersion? ParseVersion()
|
||||||
|
{
|
||||||
|
return !string.IsNullOrWhiteSpace(this.Version) && SemanticVersion.TryParse(this.Version, out ISemanticVersion? version)
|
||||||
|
? version
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,9 @@ namespace StardewModdingAPI.Web.Framework.LogParsing.Models
|
||||||
/// <summary>The SMAPI version.</summary>
|
/// <summary>The SMAPI version.</summary>
|
||||||
public string? ApiVersion { get; set; }
|
public string? ApiVersion { get; set; }
|
||||||
|
|
||||||
|
/// <summary>The parsed SMAPI version, if it's valid.</summary>
|
||||||
|
public ISemanticVersion? ApiVersionParsed { get; set; }
|
||||||
|
|
||||||
/// <summary>The game version.</summary>
|
/// <summary>The game version.</summary>
|
||||||
public string? GameVersion { get; set; }
|
public string? GameVersion { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -8,24 +8,29 @@
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "SMAPI log parser";
|
ViewData["Title"] = "SMAPI log parser";
|
||||||
|
|
||||||
|
// get log info
|
||||||
ParsedLog? log = Model!.ParsedLog;
|
ParsedLog? log = Model!.ParsedLog;
|
||||||
|
|
||||||
IDictionary<string, LogModInfo[]> contentPacks = Model.GetContentPacksByMod();
|
IDictionary<string, LogModInfo[]> contentPacks = Model.GetContentPacksByMod();
|
||||||
|
ISet<int> screenIds = new HashSet<int>(log?.Messages.Select(p => p.ScreenId) ?? Array.Empty<int>());
|
||||||
|
|
||||||
|
// detect suggested fixes
|
||||||
|
LogModInfo[] outdatedMods = log?.Mods.Where(mod => mod.HasUpdate).ToArray() ?? Array.Empty<LogModInfo>();
|
||||||
|
LogModInfo? errorHandler = log?.Mods.FirstOrDefault(p => p.IsCodeMod && p.Name == "Error Handler");
|
||||||
|
bool hasOlderErrorHandler = errorHandler?.GetParsedVersion() is not null && log?.ApiVersionParsed is not null && log.ApiVersionParsed.IsNewerThan(errorHandler.GetParsedVersion());
|
||||||
|
|
||||||
|
// get filters
|
||||||
IDictionary<string, bool> defaultFilters = Enum
|
IDictionary<string, bool> defaultFilters = Enum
|
||||||
.GetValues<LogLevel>()
|
.GetValues<LogLevel>()
|
||||||
.ToDictionary(level => level.ToString().ToLower(), level => level != LogLevel.Trace);
|
.ToDictionary(level => level.ToString().ToLower(), level => level != LogLevel.Trace);
|
||||||
|
|
||||||
IDictionary<int, string> logLevels = Enum
|
IDictionary<int, string> logLevels = Enum
|
||||||
.GetValues<LogLevel>()
|
.GetValues<LogLevel>()
|
||||||
.ToDictionary(level => (int)level, level => level.ToString().ToLower());
|
.ToDictionary(level => (int)level, level => level.ToString().ToLower());
|
||||||
|
|
||||||
IDictionary<int, string> logSections = Enum
|
IDictionary<int, string> logSections = Enum
|
||||||
.GetValues<LogSection>()
|
.GetValues<LogSection>()
|
||||||
.ToDictionary(section => (int)section, section => section.ToString());
|
.ToDictionary(section => (int)section, section => section.ToString());
|
||||||
|
|
||||||
|
// get form
|
||||||
string curPageUrl = this.Url.PlainAction("Index", "LogParser", new { id = Model.PasteID }, absoluteUrl: true)!;
|
string curPageUrl = this.Url.PlainAction("Index", "LogParser", new { id = Model.PasteID }, absoluteUrl: true)!;
|
||||||
|
|
||||||
ISet<int> screenIds = new HashSet<int>(log?.Messages.Select(p => p.ScreenId) ?? Array.Empty<int>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Head {
|
@section Head {
|
||||||
|
@ -69,7 +74,7 @@
|
||||||
</text>
|
</text>
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(function() {
|
$(function() {
|
||||||
smapi.logParser(
|
smapi.logParser(
|
||||||
|
@ -158,7 +163,7 @@ else if (log?.IsValid == true)
|
||||||
<div id="os-instructions">
|
<div id="os-instructions">
|
||||||
<div>
|
<div>
|
||||||
<ul data-tabs>
|
<ul data-tabs>
|
||||||
@foreach (Platform platform in new[] {Platform.Android, Platform.Linux, Platform.Mac, Platform.Windows})
|
@foreach (Platform platform in new[] { Platform.Android, Platform.Linux, Platform.Mac, Platform.Windows })
|
||||||
{
|
{
|
||||||
@if (platform == Platform.Windows)
|
@if (platform == Platform.Windows)
|
||||||
{
|
{
|
||||||
|
@ -237,55 +242,66 @@ else if (log?.IsValid == true)
|
||||||
@if (log?.IsValid == true)
|
@if (log?.IsValid == true)
|
||||||
{
|
{
|
||||||
<div id="output">
|
<div id="output">
|
||||||
@if (log.Mods.Any(mod => mod.HasUpdate))
|
@if (outdatedMods.Any() || errorHandler is null || hasOlderErrorHandler)
|
||||||
{
|
{
|
||||||
<h2>Suggested fixes</h2>
|
<h2>Suggested fixes</h2>
|
||||||
<ul id="fix-list">
|
<ul id="fix-list">
|
||||||
<li>
|
@if (errorHandler is null)
|
||||||
Consider updating these mods to fix problems:
|
{
|
||||||
|
<li>You don't have the <strong>Error Handler</strong> mod installed. This automatically prevents many game or mod errors. You can <a href="https://stardewvalleywiki.com/Modding:Player_Guide#Install_SMAPI">reinstall SMAPI</a> to re-add it.</li>
|
||||||
|
}
|
||||||
|
@if (hasOlderErrorHandler)
|
||||||
|
{
|
||||||
|
<li>Your <strong>Error Handler</strong> mod is older than SMAPI. You may be missing some game/mod error fixes. You can <a href="https://stardewvalleywiki.com/Modding:Player_Guide#Install_SMAPI">reinstall SMAPI</a> to update it.</li>
|
||||||
|
}
|
||||||
|
@if (outdatedMods.Any())
|
||||||
|
{
|
||||||
|
<li>
|
||||||
|
Consider updating these mods to fix problems:
|
||||||
|
|
||||||
<table id="updates" class="table">
|
<table id="updates" class="table">
|
||||||
@foreach (LogModInfo mod in log.Mods.Where(mod => (mod.HasUpdate && !mod.IsContentPack) || (contentPacks.TryGetValue(mod.Name, out LogModInfo[]? contentPackList) && contentPackList.Any(pack => pack.HasUpdate))))
|
@foreach (LogModInfo mod in log.Mods.Where(mod => (mod.HasUpdate && !mod.IsContentPack) || (contentPacks.TryGetValue(mod.Name, out LogModInfo[]? contentPackList) && contentPackList.Any(pack => pack.HasUpdate))))
|
||||||
{
|
{
|
||||||
<tr class="mod-entry">
|
<tr class="mod-entry">
|
||||||
<td>
|
<td>
|
||||||
<strong class=@(!mod.HasUpdate ? "hidden" : "")>@mod.Name</strong>
|
<strong class=@(!mod.HasUpdate ? "hidden" : "")>@mod.Name</strong>
|
||||||
@if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out LogModInfo[]? contentPackList))
|
@if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out LogModInfo[]? contentPackList))
|
||||||
{
|
{
|
||||||
<div class="content-packs">
|
<div class="content-packs">
|
||||||
@foreach (LogModInfo contentPack in contentPackList.Where(pack => pack.HasUpdate))
|
@foreach (LogModInfo contentPack in contentPackList.Where(pack => pack.HasUpdate))
|
||||||
{
|
{
|
||||||
<text>+ @contentPack.Name</text><br />
|
<text>+ @contentPack.Name</text><br />
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if (mod.HasUpdate)
|
@if (mod.HasUpdate)
|
||||||
{
|
{
|
||||||
<a href="@mod.UpdateLink" target="_blank">
|
<a href="@mod.UpdateLink" target="_blank">
|
||||||
@(mod.Version == null ? mod.UpdateVersion : $"{mod.Version} → {mod.UpdateVersion}")
|
@(mod.Version == null ? mod.UpdateVersion : $"{mod.Version} → {mod.UpdateVersion}")
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<text> </text>
|
<text> </text>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out contentPackList))
|
@if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out contentPackList))
|
||||||
{
|
{
|
||||||
<div>
|
<div>
|
||||||
@foreach (LogModInfo contentPack in contentPackList.Where(pack => pack.HasUpdate))
|
@foreach (LogModInfo contentPack in contentPackList.Where(pack => pack.HasUpdate))
|
||||||
{
|
{
|
||||||
<a href="@contentPack.UpdateLink" target="_blank">@contentPack.Version → @contentPack.UpdateVersion</a><br />
|
<a href="@contentPack.UpdateLink" target="_blank">@contentPack.Version → @contentPack.UpdateVersion</a><br />
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
</table>
|
</table>
|
||||||
</li>
|
</li>
|
||||||
|
}
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,7 +450,7 @@ else if (log?.IsValid == true)
|
||||||
<div>
|
<div>
|
||||||
This website uses JavaScript to display a filterable table. To view this log, please enable JavaScript or <a href="@this.Url.PlainAction("Index", "LogParser", new { id = Model.PasteID, format = LogViewFormat.RawView })">view the raw log</a>.
|
This website uses JavaScript to display a filterable table. To view this log, please enable JavaScript or <a href="@this.Url.PlainAction("Index", "LogParser", new { id = Model.PasteID, format = LogViewFormat.RawView })">view the raw log</a>.
|
||||||
</div>
|
</div>
|
||||||
<br/>
|
<br />
|
||||||
</noscript>
|
</noscript>
|
||||||
|
|
||||||
<log-table>
|
<log-table>
|
||||||
|
|
Loading…
Reference in New Issue