summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--build/common.targets3
-rw-r--r--docs/release-notes.md34
-rw-r--r--docs/technical/mod-package.md3
-rw-r--r--docs/technical/smapi.md9
-rw-r--r--src/SMAPI.Installer/InteractiveInstaller.cs12
-rw-r--r--src/SMAPI.Installer/assets/unix-launcher.sh34
-rw-r--r--src/SMAPI.ModBuildConfig/build/smapi.targets3
-rw-r--r--src/SMAPI.Mods.ConsoleCommands/manifest.json4
-rw-r--r--src/SMAPI.Mods.ErrorHandler/manifest.json4
-rw-r--r--src/SMAPI.Mods.SaveBackup/manifest.json4
-rw-r--r--src/SMAPI.Web/Controllers/LogParserController.cs16
-rw-r--r--src/SMAPI.Web/Framework/LogParsing/LogParser.cs12
-rw-r--r--src/SMAPI.Web/Framework/LogParsing/Models/LogModInfo.cs22
-rw-r--r--src/SMAPI.Web/Framework/LogParsing/Models/ModType.cs15
-rw-r--r--src/SMAPI.Web/SMAPI.Web.csproj2
-rw-r--r--src/SMAPI.Web/ViewModels/LogParserModel.cs2
-rw-r--r--src/SMAPI.Web/Views/Index/Index.cshtml4
-rw-r--r--src/SMAPI.Web/Views/LogParser/Index.cshtml34
-rw-r--r--src/SMAPI.Web/wwwroot/Content/css/main.css2
-rw-r--r--src/SMAPI.Web/wwwroot/Content/images/pufferchick-cool.pngbin1099 -> 0 bytes
-rw-r--r--src/SMAPI.Web/wwwroot/Content/images/pufferchick-cool.svg1
-rw-r--r--src/SMAPI.Web/wwwroot/Content/images/pufferchick.pngbin831 -> 0 bytes
-rw-r--r--src/SMAPI.Web/wwwroot/Content/images/pufferchick.svg1
-rw-r--r--src/SMAPI.Web/wwwroot/Content/images/sidebar-bg.gifbin1104 -> 0 bytes
-rw-r--r--src/SMAPI.Web/wwwroot/Content/images/sidebar-bg.svg1
-rw-r--r--src/SMAPI.Web/wwwroot/Content/js/index.js4
-rw-r--r--src/SMAPI.Web/wwwroot/schemas/content-patcher.json4
-rw-r--r--src/SMAPI/Constants.cs8
-rw-r--r--src/SMAPI/Framework/Content/AssetInfo.cs4
-rw-r--r--src/SMAPI/Framework/ContentManagers/ModContentManager.cs4
-rw-r--r--src/SMAPI/Framework/Deprecations/DeprecationManager.cs2
-rw-r--r--src/SMAPI/Framework/ExitState.cs15
-rw-r--r--src/SMAPI/Framework/ModHelpers/CommandHelper.cs2
-rw-r--r--src/SMAPI/Framework/ModHelpers/ContentHelper.cs8
-rw-r--r--src/SMAPI/Framework/ModHelpers/ModHelper.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs70
-rw-r--r--src/SMAPI/Framework/ModLoading/AssemblyLoader.cs13
-rw-r--r--src/SMAPI/Framework/ModLoading/ModResolver.cs6
-rw-r--r--src/SMAPI/Framework/SCore.cs67
-rw-r--r--src/SMAPI/SMAPI.csproj3
-rw-r--r--src/SMAPI/Utilities/PerScreen.cs2
-rw-r--r--src/SMAPI/app.manifest41
-rw-r--r--src/SMAPI/i18n/tr.json2
44 files changed, 359 insertions, 123 deletions
diff --git a/.gitignore b/.gitignore
index 527ac6bb..a89ccd21 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,3 +34,6 @@ appsettings.Development.json
# Azure generated files
src/SMAPI.Web/Properties/PublishProfiles/*.pubxml
src/SMAPI.Web/Properties/ServiceDependencies/* - Web Deploy/
+
+# macOS
+.DS_Store
diff --git a/build/common.targets b/build/common.targets
index 230bef41..383e258b 100644
--- a/build/common.targets
+++ b/build/common.targets
@@ -7,12 +7,11 @@ repo. It imports the other MSBuild files as needed.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!--set general build properties -->
- <Version>3.15.1</Version>
+ <Version>3.16.0</Version>
<Product>SMAPI</Product>
<LangVersion>latest</LangVersion>
<AssemblySearchPaths>$(AssemblySearchPaths);{GAC}</AssemblySearchPaths>
<DefineConstants>$(DefineConstants);SMAPI_DEPRECATED</DefineConstants>
- <DebugType>pdbonly</DebugType>
<DebugSymbols>true</DebugSymbols>
<!--enable nullable annotations, except in .NET Standard 2.0 where they aren't supported-->
diff --git a/docs/release-notes.md b/docs/release-notes.md
index 8b258fb3..ca7d6e6e 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -4,9 +4,39 @@
<!--
## 4.0.0
* The installer no longer supports updating from SMAPI 2.11.3 or earlier (released in 2019).
- _If needed, you can update to SMAPI 3.15.0 first and then install to the latest version._
+ _If needed, you can update to SMAPI 3.16.0 first and then install the latest version._
-->
+## 3.16.0
+Released 22 August 2022 for Stardew Valley 1.5.6 or later. See [release highlights](https://www.patreon.com/posts/70797008).
+
+* For players:
+ * Added error message if mod files are detected directly under `Mods` (instead of each mod having its own subfolder).
+ * SMAPI now sets a success/error code when the game exits.
+ _This is used by your OS (like Windows) to decide whether to keep the console window open when the game ends._
+ * Fixed SMAPI on Windows applying different DPI awareness settings than the game (thanks to spacechase0!).
+ * Fixed Linux/macOS installer's color scheme question partly unreadable if the terminal background is dark.
+ * Fixed error message when a mod loads an invalid PNG file (thanks to atravita!).
+ * Fixed error message when a mod is duplicated, but one of the copies is also missing the DLL file. This now shows the duplicate-mod message instead of the missing-DLL message.
+ * Fixed macOS launcher using Terminal regardless of the system's default terminal (thanks to ishan!).
+ * Fixed best practices in Linux/macOS launcher scripts (thanks to ishan!).
+ * Improved translations. Thanks to KediDili (updated Turkish)!
+
+* For mod authors:
+ * While loading your mod, SMAPI now searches for indirect dependencies in your mod's folder (thanks to TehPers)! This mainly enables F# mods.
+ * **Raised deprecation message levels.**
+ _Deprecation warnings are now player-visible in the SMAPI console as faded `DEBUG` messages._
+ * Updated to Pintail 2.2.1 (see [changes](https://github.com/Nanoray-pl/Pintail/blob/master/docs/release-notes.md#221)).
+ * Switched SMAPI's `.pdb` files to the newer 'portable' format. This has no effect on mods.
+
+* For the web UI:
+ * Added log parser warning about performance of PyTK 1.23.0 or earlier.
+ * Converted images to SVG (thanks to ishan!).
+ * Updated log parser for the new update alert format in SMAPI 3.15.1.
+ * Updated the JSON validator/schema for Content Patcher 1.28.0.
+ * Fixed log parsing for invalid content packs.
+ * Fixed log parsing if a mod logged a null character.
+
## 3.15.1
Released 06 July 2022 for Stardew Valley 1.5.6 or later.
@@ -41,7 +71,7 @@ Released 17 June 2022 for Stardew Valley 1.5.6 or later. See [release highlights
* Updated dependencies:
* Harmony 2.2.1 (see changes in [2.2.0](https://github.com/pardeike/Harmony/releases/tag/v2.2.0.0) and [2.2.1](https://github.com/pardeike/Harmony/releases/tag/v2.2.1.0));
* Newtonsoft.Json 13.0.1 (see [changes](https://github.com/JamesNK/Newtonsoft.Json/releases/tag/13.0.1));
- * Pintail 2.2.0.
+ * Pintail 2.2.0 (see [changes](https://github.com/Nanoray-pl/Pintail/blob/master/docs/release-notes.md#220)).
* Removed transitional `UsePintail` option added in 3.14.0 (now always enabled).
* Fixed `onBehalfOf` arguments in the new content API being case-sensitive.
* Fixed map edits which change warps sometimes rebuilding the NPC pathfinding cache unnecessarily, which could cause a noticeable delay for players.
diff --git a/docs/technical/mod-package.md b/docs/technical/mod-package.md
index dd65a992..ca78be55 100644
--- a/docs/technical/mod-package.md
+++ b/docs/technical/mod-package.md
@@ -412,6 +412,9 @@ The NuGet package is generated automatically in `StardewModdingAPI.ModBuildConfi
when you compile it.
## Release notes
+### Upcoming release
+* Switched to the newer crossplatform `portable` debug symbols (thanks to lanturnalis!).
+
### 4.0.1
Released 14 April 2022.
diff --git a/docs/technical/smapi.md b/docs/technical/smapi.md
index 90990ee4..b8a1683b 100644
--- a/docs/technical/smapi.md
+++ b/docs/technical/smapi.md
@@ -33,14 +33,15 @@ argument | purpose
`--uninstall` | Preselects the uninstall action, skipping the prompt asking what the user wants to do.
`--game-path "path"` | Specifies the full path to the folder containing the Stardew Valley executable, skipping automatic detection and any prompt to choose a path. If the path is not valid, the installer displays an error.
-SMAPI itself recognises five arguments **on Windows only**, but these are intended for internal use
-or testing and may change without warning. On Linux/macOS, see _environment variables_ below.
+SMAPI itself recognises five arguments, but these are meant for internal use or testing, and might
+change without warning. **On Linux/macOS**, command-line arguments won't work; see _environment
+variables_ below instead.
argument | purpose
-------- | -------
`--developer-mode`<br />`--developer-mode-off` | Enable or disable features intended for mod developers. Currently this only makes `TRACE`-level messages appear in the console.
-`--no-terminal` | The SMAPI launcher won't try to open a terminal window, and SMAPI won't log anything to the console. (Messages will still be written to the log file.)
-`--use-current-shell` | The SMAPI launcher won't try to open a terminal window, but SMAPI will still log to the console. (Messages will still be written to the log file.)
+`--no-terminal` | SMAPI won't log anything to the console. On Linux/macOS only, this will also prevent the launch script from trying to open a terminal window. (Messages will still be written to the log file.)
+`--use-current-shell` | On Linux/macOS only, the launch script won't try to open a terminal window. All console output will be sent to the shell running the launch script.
`--mods-path` | The path to search for mods, if not the standard `Mods` folder. This can be a path relative to the game folder (like `--mods-path "Mods (test)"`) or an absolute path.
### Environment variables
diff --git a/src/SMAPI.Installer/InteractiveInstaller.cs b/src/SMAPI.Installer/InteractiveInstaller.cs
index fd1a6047..d00a5df4 100644
--- a/src/SMAPI.Installer/InteractiveInstaller.cs
+++ b/src/SMAPI.Installer/InteractiveInstaller.cs
@@ -206,7 +206,7 @@ namespace StardewModdingApi.Installer
Console.WriteLine();
// handle choice
- string choice = this.InteractivelyChoose("Type 1 or 2, then press enter.", new[] { "1", "2" });
+ string choice = this.InteractivelyChoose("Type 1 or 2, then press enter.", new[] { "1", "2" }, printLine: Console.WriteLine);
switch (choice)
{
case "1":
@@ -629,22 +629,22 @@ namespace StardewModdingApi.Installer
}
/// <summary>Interactively ask the user to choose a value.</summary>
- /// <param name="print">A callback which prints a message to the console.</param>
+ /// <param name="printLine">A callback which prints a message to the console.</param>
/// <param name="message">The message to print.</param>
/// <param name="options">The allowed options (not case sensitive).</param>
/// <param name="indent">The indentation to prefix to output.</param>
- private string InteractivelyChoose(string message, string[] options, string indent = "", Action<string>? print = null)
+ private string InteractivelyChoose(string message, string[] options, string indent = "", Action<string>? printLine = null)
{
- print ??= this.PrintInfo;
+ printLine ??= this.PrintInfo;
while (true)
{
- print(indent + message);
+ printLine(indent + message);
Console.Write(indent);
string? input = Console.ReadLine()?.Trim().ToLowerInvariant();
if (input == null || !options.Contains(input))
{
- print($"{indent}That's not a valid option.");
+ printLine($"{indent}That's not a valid option.");
continue;
}
return input;
diff --git a/src/SMAPI.Installer/assets/unix-launcher.sh b/src/SMAPI.Installer/assets/unix-launcher.sh
index ae9624e7..778663d7 100644
--- a/src/SMAPI.Installer/assets/unix-launcher.sh
+++ b/src/SMAPI.Installer/assets/unix-launcher.sh
@@ -54,12 +54,12 @@ if [ "$(uname)" == "Darwin" ]; then
# https://stackoverflow.com/a/29511052/262123
if [ "$USE_CURRENT_SHELL" == "false" ]; then
echo "Reopening in the Terminal app..."
- echo '#!/bin/sh' > /tmp/open-smapi-terminal.sh
- echo "\"$0\" $@ --use-current-shell" >> /tmp/open-smapi-terminal.sh
- chmod +x /tmp/open-smapi-terminal.sh
- cat /tmp/open-smapi-terminal.sh
- open -W -a Terminal /tmp/open-smapi-terminal.sh
- rm /tmp/open-smapi-terminal.sh
+ echo '#!/bin/sh' > /tmp/open-smapi-terminal.command
+ echo "\"$0\" $@ --use-current-shell" >> /tmp/open-smapi-terminal.command
+ chmod +x /tmp/open-smapi-terminal.command
+ cat /tmp/open-smapi-terminal.command
+ open -W /tmp/open-smapi-terminal.command
+ rm /tmp/open-smapi-terminal.command
exit 0
fi
fi
@@ -71,8 +71,8 @@ fi
##########
# script must be run from the game folder
if [ ! -f "Stardew Valley.dll" ]; then
- echo "Oops! SMAPI must be placed in the Stardew Valley game folder.\nSee instructions: https://stardewvalleywiki.com/Modding:Player_Guide";
- read
+ printf "Oops! SMAPI must be placed in the Stardew Valley game folder.\nSee instructions: https://stardewvalleywiki.com/Modding:Player_Guide";
+ read -r
exit 1
fi
@@ -102,37 +102,39 @@ else
# find the true shell behind x-terminal-emulator
if [ "$TERMINAL_NAME" = "x-terminal-emulator" ]; then
- export TERMINAL_NAME="$(basename "$(readlink -f $(command -v x-terminal-emulator))")"
+ TERMINAL_NAME="$(basename "$(readlink -f "$(command -v x-terminal-emulator)")")"
+ export TERMINAL_NAME
fi
# run in selected terminal and account for quirks
- export TERMINAL_PATH="$(command -v $TERMINAL_NAME)"
- if [ -x $TERMINAL_PATH ]; then
+ TERMINAL_PATH="$(command -v "$TERMINAL_NAME")"
+ export TERMINAL_PATH
+ if [ -x "$TERMINAL_PATH" ]; then
case $TERMINAL_NAME in
terminal|termite)
# consumes only one argument after -e
# options containing space characters are unsupported
- exec $TERMINAL_NAME -e "env TERM=xterm $LAUNCH_FILE $@"
+ exec "$TERMINAL_NAME" -e "env TERM=xterm $LAUNCH_FILE $@"
;;
xterm|konsole|alacritty)
# consumes all arguments after -e
- exec $TERMINAL_NAME -e env TERM=xterm $LAUNCH_FILE "$@"
+ exec "$TERMINAL_NAME" -e env TERM=xterm $LAUNCH_FILE "$@"
;;
terminator|xfce4-terminal|mate-terminal)
# consumes all arguments after -x
- exec $TERMINAL_NAME -x env TERM=xterm $LAUNCH_FILE "$@"
+ exec "$TERMINAL_NAME" -x env TERM=xterm $LAUNCH_FILE "$@"
;;
gnome-terminal)
# consumes all arguments after --
- exec $TERMINAL_NAME -- env TERM=xterm $LAUNCH_FILE "$@"
+ exec "$TERMINAL_NAME" -- env TERM=xterm $LAUNCH_FILE "$@"
;;
kitty)
# consumes all trailing arguments
- exec $TERMINAL_NAME env TERM=xterm $LAUNCH_FILE "$@"
+ exec "$TERMINAL_NAME" env TERM=xterm $LAUNCH_FILE "$@"
;;
*)
diff --git a/src/SMAPI.ModBuildConfig/build/smapi.targets b/src/SMAPI.ModBuildConfig/build/smapi.targets
index b66ec27b..12619439 100644
--- a/src/SMAPI.ModBuildConfig/build/smapi.targets
+++ b/src/SMAPI.ModBuildConfig/build/smapi.targets
@@ -8,8 +8,7 @@
** Set build options
**********************************************-->
<PropertyGroup>
- <!-- include PDB file by default to enable line numbers in stack traces -->
- <DebugType>pdbonly</DebugType>
+ <!-- enable line numbers in stack traces -->
<DebugSymbols>true</DebugSymbols>
<!-- don't create the 'refs' folder (which isn't useful for mods) -->
diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json
index 3c2dec19..adc45ec3 100644
--- a/src/SMAPI.Mods.ConsoleCommands/manifest.json
+++ b/src/SMAPI.Mods.ConsoleCommands/manifest.json
@@ -1,9 +1,9 @@
{
"Name": "Console Commands",
"Author": "SMAPI",
- "Version": "3.15.1",
+ "Version": "3.16.0",
"Description": "Adds SMAPI console commands that let you manipulate the game.",
"UniqueID": "SMAPI.ConsoleCommands",
"EntryDll": "ConsoleCommands.dll",
- "MinimumApiVersion": "3.15.1"
+ "MinimumApiVersion": "3.16.0"
}
diff --git a/src/SMAPI.Mods.ErrorHandler/manifest.json b/src/SMAPI.Mods.ErrorHandler/manifest.json
index 28b4b149..3a3c9283 100644
--- a/src/SMAPI.Mods.ErrorHandler/manifest.json
+++ b/src/SMAPI.Mods.ErrorHandler/manifest.json
@@ -1,9 +1,9 @@
{
"Name": "Error Handler",
"Author": "SMAPI",
- "Version": "3.15.1",
+ "Version": "3.16.0",
"Description": "Handles some common vanilla errors to log more useful info or avoid breaking the game.",
"UniqueID": "SMAPI.ErrorHandler",
"EntryDll": "ErrorHandler.dll",
- "MinimumApiVersion": "3.15.1"
+ "MinimumApiVersion": "3.16.0"
}
diff --git a/src/SMAPI.Mods.SaveBackup/manifest.json b/src/SMAPI.Mods.SaveBackup/manifest.json
index 1944575b..eb98aa32 100644
--- a/src/SMAPI.Mods.SaveBackup/manifest.json
+++ b/src/SMAPI.Mods.SaveBackup/manifest.json
@@ -1,9 +1,9 @@
{
"Name": "Save Backup",
"Author": "SMAPI",
- "Version": "3.15.1",
+ "Version": "3.16.0",
"Description": "Automatically backs up all your saves once per day into its folder.",
"UniqueID": "SMAPI.SaveBackup",
"EntryDll": "SaveBackup.dll",
- "MinimumApiVersion": "3.15.1"
+ "MinimumApiVersion": "3.16.0"
}
diff --git a/src/SMAPI.Web/Controllers/LogParserController.cs b/src/SMAPI.Web/Controllers/LogParserController.cs
index 33af5a81..a3bcf4c3 100644
--- a/src/SMAPI.Web/Controllers/LogParserController.cs
+++ b/src/SMAPI.Web/Controllers/LogParserController.cs
@@ -1,7 +1,9 @@
using System;
-using System.Linq;
+using System.Collections.Specialized;
+using System.IO;
using System.Text;
using System.Threading.Tasks;
+using System.Web;
using Microsoft.AspNetCore.Mvc;
using StardewModdingAPI.Toolkit.Utilities;
using StardewModdingAPI.Web.Framework;
@@ -87,9 +89,15 @@ namespace StardewModdingAPI.Web.Controllers
public async Task<ActionResult> PostAsync()
{
// get raw log text
- string? input = this.Request.Form["input"].FirstOrDefault();
- if (string.IsNullOrWhiteSpace(input))
- return this.View("Index", this.GetModel(null, uploadError: "The log file seems to be empty."));
+ // note: avoid this.Request.Form, which fails if any mod logged a null character.
+ string? input;
+ {
+ using StreamReader reader = new StreamReader(this.Request.Body);
+ NameValueCollection parsed = HttpUtility.ParseQueryString(await reader.ReadToEndAsync());
+ input = parsed["input"];
+ if (string.IsNullOrWhiteSpace(input))
+ return this.View("Index", this.GetModel(null, uploadError: "The log file seems to be empty."));
+ }
// upload log
UploadResult uploadResult = await this.Storage.SaveAsync(input);
diff --git a/src/SMAPI.Web/Framework/LogParsing/LogParser.cs b/src/SMAPI.Web/Framework/LogParsing/LogParser.cs
index 0efa62c5..18ba754c 100644
--- a/src/SMAPI.Web/Framework/LogParsing/LogParser.cs
+++ b/src/SMAPI.Web/Framework/LogParsing/LogParser.cs
@@ -36,13 +36,13 @@ 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);
/// <summary>A regex pattern matching an entry in SMAPI's mod update list.</summary>
- private readonly Regex ModUpdateListEntryPattern = new(@"^ (?<name>.+) (?<version>[^\s]+): (?<link>.+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ private readonly Regex ModUpdateListEntryPattern = new(@"^ (?<name>.+) (?<version>[^\s]+): (?<link>[^\s]+)(?: \(you have [^\)]+\))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>A regex pattern matching SMAPI's update line.</summary>
private readonly Regex SmapiUpdatePattern = new(@"^You can update SMAPI to (?<version>[^\s]+): (?<link>.+)$", 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/SMAPI.Web.csproj b/src/SMAPI.Web/SMAPI.Web.csproj
index 0a460e9e..d26cb6f8 100644
--- a/src/SMAPI.Web/SMAPI.Web.csproj
+++ b/src/SMAPI.Web/SMAPI.Web.csproj
@@ -15,7 +15,7 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="Azure.Storage.Blobs" Version="12.12.0" />
+ <PackageReference Include="Azure.Storage.Blobs" Version="12.13.0" />
<PackageReference Include="Hangfire.AspNetCore" Version="1.7.29" />
<PackageReference Include="Hangfire.MemoryStorage" Version="1.7.0" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.43" />
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/Index/Index.cshtml b/src/SMAPI.Web/Views/Index/Index.cshtml
index acb8df78..d6472fcb 100644
--- a/src/SMAPI.Web/Views/Index/Index.cshtml
+++ b/src/SMAPI.Web/Views/Index/Index.cshtml
@@ -10,12 +10,12 @@
@section Head {
<link rel="stylesheet" href="~/Content/css/index.css" />
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1" crossorigin="anonymous"></script>
- <script src="~/Content/js/index.js"></script>
+ <script src="~/Content/js/index.js?r=20220708"></script&