summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/SMAPI.Web/Framework/LogParsing/LogParser.cs49
-rw-r--r--src/SMAPI.Web/Framework/LogParsing/Models/LogModInfo.cs (renamed from src/SMAPI.Web/Framework/LogParsing/Models/ModInfo.cs)12
-rw-r--r--src/SMAPI.Web/Views/LogParser/Index.cshtml59
-rw-r--r--src/SMAPI.Web/wwwroot/Content/css/log-parser.css33
4 files changed, 137 insertions, 16 deletions
diff --git a/src/SMAPI.Web/Framework/LogParsing/LogParser.cs b/src/SMAPI.Web/Framework/LogParsing/LogParser.cs
index 6f848469..5cdc501f 100644
--- a/src/SMAPI.Web/Framework/LogParsing/LogParser.cs
+++ b/src/SMAPI.Web/Framework/LogParsing/LogParser.cs
@@ -39,6 +39,15 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
/// <summary>A regex pattern matching an entry in SMAPI's content pack list.</summary>
private readonly Regex ContentPackListEntryPattern = new Regex(@"^ (?<name>.+) (?<version>.+) 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 Regex(@"^You can update \d+ mods?:$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+
+ /// <summary>A regex pattern matching an entry in SMAPI's mod update list.</summary>
+ private readonly Regex ModUpdateListEntryPattern = new Regex(@"^ (?<name>.+?) (?<version>" + SemanticVersion.UnboundedVersionPattern + @"): (?<link>.+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+
+ /// <summary>A regex pattern matching SMAPI's update line.</summary>
+ private readonly Regex SMAPIUpdatePattern = new Regex(@"^You can update SMAPI to (?<version>" + SemanticVersion.UnboundedVersionPattern + @"): (?<link>.+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+
/*********
** Public methods
@@ -69,11 +78,12 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
};
// parse log messages
- LogModInfo smapiMod = new LogModInfo { Name = "SMAPI", Author = "Pathoschild", Description = "" };
- LogModInfo gameMod = new LogModInfo { Name = "game", Author = "", Description = "" };
+ LogModInfo smapiMod = new LogModInfo { Name = "SMAPI", Author = "Pathoschild", Description = "", Loaded = true};
+ LogModInfo gameMod = new LogModInfo { Name = "game", Author = "", Description = "", Loaded = true };
IDictionary<string, LogModInfo> mods = new Dictionary<string, LogModInfo>();
bool inModList = false;
bool inContentPackList = false;
+ bool inModUpdateList = false;
foreach (LogMessage message in log.Messages)
{
// collect stats
@@ -106,6 +116,8 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
inModList = false;
if (inContentPackList && !this.ContentPackListEntryPattern.IsMatch(message.Text))
inContentPackList = false;
+ if (inModUpdateList && !this.ModUpdateListEntryPattern.IsMatch(message.Text))
+ inModUpdateList = false;
// mod list
if (!inModList && message.Level == LogLevel.Info && this.ModListStartPattern.IsMatch(message.Text))
@@ -117,7 +129,7 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
string version = match.Groups["version"].Value;
string author = match.Groups["author"].Value;
string description = match.Groups["description"].Value;
- mods[name] = new LogModInfo { Name = name, Author = author, Version = version, Description = description };
+ mods[name] = new LogModInfo { Name = name, Author = author, Version = version, Description = description, Loaded = true };
}
// content pack list
@@ -131,7 +143,36 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
string author = match.Groups["author"].Value;
string description = match.Groups["description"].Value;
string forMod = match.Groups["for"].Value;
- mods[name] = new LogModInfo { Name = name, Author = author, Version = version, Description = description, ContentPackFor = forMod };
+ mods[name] = new LogModInfo { Name = name, Author = author, Version = version, Description = description, ContentPackFor = forMod, Loaded = true };
+ }
+
+ // mod update list
+ else if (!inModUpdateList && message.Level == LogLevel.Alert && this.ModUpdateListStartPattern.IsMatch(message.Text))
+ inModUpdateList = true;
+ else if (inModUpdateList)
+ {
+ Match match = this.ModUpdateListEntryPattern.Match(message.Text);
+ string name = match.Groups["name"].Value;
+ string version = match.Groups["version"].Value;
+ string link = match.Groups["link"].Value;
+ if (mods.ContainsKey(name))
+ {
+ mods[name].UpdateLink = link;
+ mods[name].UpdateVersion = version;
+ }
+ else
+ {
+ mods[name] = new LogModInfo {Name = name, UpdateVersion = version, UpdateLink = link, Loaded = false};
+ }
+ }
+
+ else if(message.Level == LogLevel.Alert && this.SMAPIUpdatePattern.IsMatch(message.Text))
+ {
+ Match match = this.SMAPIUpdatePattern.Match(message.Text);
+ string version = match.Groups["version"].Value;
+ string link = match.Groups["link"].Value;
+ smapiMod.UpdateVersion = version;
+ smapiMod.UpdateLink = link;
}
// platform info line
diff --git a/src/SMAPI.Web/Framework/LogParsing/Models/ModInfo.cs b/src/SMAPI.Web/Framework/LogParsing/Models/LogModInfo.cs
index 8c84ab38..067e4df4 100644
--- a/src/SMAPI.Web/Framework/LogParsing/Models/ModInfo.cs
+++ b/src/SMAPI.Web/Framework/LogParsing/Models/LogModInfo.cs
@@ -12,6 +12,12 @@ namespace StardewModdingAPI.Web.Framework.LogParsing.Models
/// <summary>The mod author.</summary>
public string Author { get; set; }
+ /// <summary>The update version.</summary>
+ public string UpdateVersion { get; set; }
+
+ /// <summary>The update link.</summary>
+ public string UpdateLink { get; set; }
+
/// <summary>The mod version.</summary>
public string Version { get; set; }
@@ -23,5 +29,11 @@ namespace StardewModdingAPI.Web.Framework.LogParsing.Models
/// <summary>The number of errors logged by this mod.</summary>
public int Errors { get; set; }
+
+ /// <summary>Whether the mod was loaded into the game.</summary>
+ public bool Loaded { get; set; }
+
+ /// <summary>Whether the mod has an update available.</summary>
+ public bool HasUpdate => this.UpdateVersion != null && this.Version != this.UpdateVersion;
}
}
diff --git a/src/SMAPI.Web/Views/LogParser/Index.cshtml b/src/SMAPI.Web/Views/LogParser/Index.cshtml
index 58830d64..bf70f2d7 100644
--- a/src/SMAPI.Web/Views/LogParser/Index.cshtml
+++ b/src/SMAPI.Web/Views/LogParser/Index.cshtml
@@ -117,9 +117,60 @@ else if (Model.ParsedLog?.IsValid == true)
@* parsed log *@
@if (Model.ParsedLog?.IsValid == true)
{
- <h2>Log info</h2>
<div id="output">
- <table id="metadata">
+ @if (Model.ParsedLog.Mods.Any(mod => mod.HasUpdate))
+ {
+ <h2>Suggested fixes</h2>
+
+ <p>You have some mods that aren't fully up to date. Updating them can fix problems.</p>
+ <table id="updates" class="table">
+ <caption>
+ Updates available:
+ </caption>
+ @foreach (LogModInfo mod in Model.ParsedLog.Mods.Where(mod => (mod.HasUpdate && mod.ContentPackFor == null) || (contentPacks != null && contentPacks.TryGetValue(mod.Name, out LogModInfo[] contentPackList) && contentPackList.Any(pack => pack.HasUpdate))))
+ {
+ <tr class="mod-entry">
+ <td>
+ <strong class=@(!mod.HasUpdate ? "hidden": "")>@mod.Name</strong>
+ @if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out LogModInfo[] contentPackList))
+ {
+ <div class="content-packs">
+ @foreach (LogModInfo contentPack in contentPackList.Where(pack => pack.HasUpdate))
+ {
+ <text>+ @contentPack.Name</text><br />
+ }
+ </div>
+ }
+ </td>
+ <td>
+ @if (mod.HasUpdate)
+ {
+ <a href="@mod.UpdateLink" target="_blank">
+ @(mod.Version == null ? @mod.UpdateVersion : $"{mod.Version} → {mod.UpdateVersion}")
+ </a>
+ }
+ else
+ {
+ <span class="invisible">Okay</span>
+ }
+
+ @if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out contentPackList))
+ {
+ <div>
+ @foreach (LogModInfo contentPack in contentPackList.Where(pack => pack.HasUpdate))
+ {
+ <a href="@contentPack.UpdateLink" target="_blank">@contentPack.Version → @contentPack.UpdateVersion</a><br />
+ }
+ </div>
+ }
+ </td>
+ </tr>
+ }
+ </table>
+ }
+
+ <h2>Log info</h2>
+ <table id="metadata" class="table">
<caption>Game info:</caption>
<tr>
<th>Stardew Valley:</th>
@@ -139,7 +190,7 @@ else if (Model.ParsedLog?.IsValid == true)
</tr>
</table>
<br />
- <table id="mods" class="@(Model.ShowRaw ? "filters-disabled" : null)">
+ <table id="mods" class="@(Model.ShowRaw ? "filters-disabled" : null) table">
<caption>
Installed mods:
@if (!Model.ShowRaw)
@@ -149,7 +200,7 @@ else if (Model.ParsedLog?.IsValid == true)
<span class="notice btn txt" v-on:click="hideAllMods" v-bind:class="{ invisible: !anyModsShown || !anyModsHidden }">hide all</span>
}
</caption>
- @foreach (var mod in Model.ParsedLog.Mods.Where(p => p.ContentPackFor == null))
+ @foreach (var mod in Model.ParsedLog.Mods.Where(p => p.Loaded && p.ContentPackFor == null))
{
<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>
diff --git a/src/SMAPI.Web/wwwroot/Content/css/log-parser.css b/src/SMAPI.Web/wwwroot/Content/css/log-parser.css
index 2f3dd0a1..5e7ccb79 100644
--- a/src/SMAPI.Web/wwwroot/Content/css/log-parser.css
+++ b/src/SMAPI.Web/wwwroot/Content/css/log-parser.css
@@ -13,6 +13,13 @@ caption {
#output {
padding: 10px;
overflow: auto;
+}
+
+#output h2 {
+ margin: -10px 0 10px -10px;
+}
+
+#output table {
font-family: monospace;
}
@@ -43,7 +50,7 @@ table caption {
/*********
** Log metadata & filters
*********/
-#metadata, #mods, #filters {
+.table, #filters {
border-bottom: 1px dashed #888888;
margin-bottom: 5px;
}
@@ -53,7 +60,7 @@ table caption {
padding-right: 0.7em;
}
-table#metadata, table#mods {
+.table {
border: 1px solid #000000;
background: #ffffff;
border-radius: 5px;
@@ -63,6 +70,18 @@ table#metadata, table#mods {
box-shadow: 1px 1px 1px 1px #dddddd;
}
+.mod-entry {
+ height: 1.8em;
+}
+
+.table > caption {
+ min-height: 1.3em;
+}
+
+#updates {
+ min-width: 10em;
+}
+
.invisible {
visibility: hidden;
}
@@ -87,8 +106,7 @@ table#metadata, table#mods {
cursor: default;
}
-#metadata tr,
-#mods tr {
+.table tr {
background: #eee
}
@@ -114,11 +132,11 @@ table#metadata, table#mods {
display: inline-block;
}
-#mods .mod-entry.hidden {
+.table .hidden {
opacity: 0.5;
}
-#mods .content-packs {
+.table .content-packs {
margin-left: 1em;
font-size: 0.9em;
font-style: italic;
@@ -128,8 +146,7 @@ table#metadata, table#mods {
padding-right: 5px;
}
-#metadata tr:nth-child(even),
-#mods tr:nth-child(even) {
+.table tr:nth-child(even) {
background: #fff
}