diff options
55 files changed, 710 insertions, 314 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 74954cf4..c51d164b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -24,7 +24,7 @@ Exact steps which reproduce the bug, if possible. For example: 4. Error occurs. **Log file** -Upload your SMAPI log to https://log.smapi.io and post a link here. +Upload your SMAPI log to https://smapi.io/log and post a link here. **Screenshots** If applicable, add screenshots to help explain your problem. @@ -28,4 +28,7 @@ _ReSharper*/ appsettings.Development.json # AWS generated files -src/SMAPI.Web/aws-beanstalk-tools-defaults.json +src/SMAPI.Web.LegacyRedirects/aws-beanstalk-tools-defaults.json + +# Azure generated files +src/SMAPI.Web/Properties/PublishProfiles/smapi-web-release - Web Deploy.pubxml diff --git a/build/common.targets b/build/common.targets index 10cdbe2c..e738bab0 100644 --- a/build/common.targets +++ b/build/common.targets @@ -4,7 +4,7 @@ <!--set properties --> <PropertyGroup> - <Version>3.0.0</Version> + <Version>3.0.1</Version> <Product>SMAPI</Product> <AssemblySearchPaths>$(AssemblySearchPaths);{GAC}</AssemblySearchPaths> diff --git a/build/prepare-install-package.targets b/build/prepare-install-package.targets index e5286bf5..4297756d 100644 --- a/build/prepare-install-package.targets +++ b/build/prepare-install-package.targets @@ -63,7 +63,7 @@ <Copy SourceFiles="$(CompiledModsPath)\SaveBackup\SaveBackup.pdb" DestinationFolder="$(PackagePath)\bundle\Mods\SaveBackup" /> <Copy SourceFiles="$(CompiledModsPath)\SaveBackup\manifest.json" DestinationFolder="$(PackagePath)\bundle\Mods\SaveBackup" /> - <!-- fix errors on Linux/Mac (sample: https://log.smapi.io/mMdFUpgB) --> + <!-- fix errors on Linux/Mac (sample: https://smapi.io/log/mMdFUpgB) --> <Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="$(RootPath)\build\lib\System.Numerics.dll" DestinationFolder="$(PackagePath)\bundle\smapi-internal" /> <Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="$(RootPath)\build\lib\System.Runtime.Caching.dll" DestinationFolder="$(PackagePath)\bundle\smapi-internal" /> diff --git a/docs/README.md b/docs/README.md index ddde6b09..386259a9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -63,7 +63,7 @@ contributing translations. locale | status ---------- | :---------------- default | ✓ [fully translated](../src/SMAPI/i18n/default.json) -Chinese | ❑ not translated +Chinese | ✓ [fully translated](../src/SMAPI/i18n/zh.json) French | ❑ not translated German | ✓ [fully translated](../src/SMAPI/i18n/de.json) Hungarian | ❑ not translated @@ -71,6 +71,6 @@ Italian | ❑ not translated Japanese | ❑ not translated Korean | ❑ not translated Portuguese | ❑ not translated -Russian | ❑ not translated +Russian | ✓ [fully translated](../src/SMAPI/i18n/ru.json) Spanish | ❑ not translated -Turkish | ❑ not translated +Turkish | ✓ [fully translated](../src/SMAPI/i18n/tr.json) diff --git a/docs/release-notes.md b/docs/release-notes.md index a891c495..1c106542 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,6 +1,22 @@ ← [README](README.md) # Release notes +## 3.0.1 +Released 02 December 2019 for Stardew Valley 1.4.0.1. + +* For players: + * Updated for Stardew Valley 1.4.0.1. + * Improved compatibility with some Linux terminals (thanks to archification and DanielHeath!). + * Updated translations. Thanks to berkayylmao (added Turkish), feathershine (added Chinese), and Osiris901 (added Russian)! + +* For the web UI: + * Rebuilt web infrastructure to handle higher traffic. + * If a log can't be uploaded to Pastebin (e.g. due to rate limits), it's now uploaded to Amazon S3 instead. Logs uploaded to S3 expire after one month. + * Fixed JSON validator not letting you drag & drop a file. + +* For modders: + * `SemanticVersion` now supports [semver 2.0](https://semver.org/) build metadata. + ## 3.0 Released 26 November 2019 for Stardew Valley 1.4. @@ -80,6 +96,7 @@ For modders: * Update checks are now faster in some cases. * Updated mod compatibility list. * Updated SMAPI/game version map. + * Updated translations. Thanks to eren-kemer (added German)! * Fixes: * Fixed some assets not updated when you switch language to English. * Fixed lag in some cases due to incorrect asset caching when playing in non-English. @@ -102,7 +119,7 @@ For modders: * Clicking a mod link now automatically adds it to the visible mods if the list is filtered. * JSON validator: - * Added JSON validator at [json.smapi.io](https://json.smapi.io), which lets you validate a JSON file against predefined mod formats. + * Added JSON validator at [smapi.io/json](https://smapi.io/json), which lets you validate a JSON file against predefined mod formats. * Added support for the `manifest.json` format. * Added support for the Content Patcher format (thanks to TehPers!). * Added support for referencing a schema in a JSON Schema-compatible text editor. @@ -365,7 +382,7 @@ Released 19 November 2018 for Stardew Valley 1.3.32. * Updated compatibility list. * For the web UI: - * Added a [mod compatibility page](https://mods.smapi.io) and [privacy page](https://smapi.io/privacy). + * Added a [mod compatibility page](https://smapi.io/mods) and [privacy page](https://smapi.io/privacy). * The log parser now has a separate filter for game messages. * The log parser now shows content pack authors (thanks to danvolchek!). * Tweaked log parser UI (thanks to danvolchek!). @@ -549,7 +566,7 @@ Released 11 April 2018 for Stardew Valley 1.2.30–1.2.33. * Fixed error when two content packs use different capitalization for the same required mod ID. * Fixed rare crash if the game duplicates an item. -* For the [log parser](https://log.smapi.io): +* For the [log parser](https://smapi.io/log): * Tweaked UI. ## 2.5.4 @@ -561,7 +578,7 @@ Released 26 March 2018 for Stardew Valley 1.2.30–1.2.33. * Fixed error when mods remove an asset editor/loader. * Fixed minimum game version incorrectly increased in SMAPI 2.5.3. -* For the [log parser](https://log.smapi.io): +* For the [log parser](https://smapi.io/log): * Fixed error when log text contains certain tokens. * For modders: @@ -583,7 +600,7 @@ Released 13 March 2018 for Stardew Valley ~~1.2.30~~–1.2.33. * Fixed Linux ["magic number is wrong" errors](https://github.com/mono/mono/issues/6752) by changing default terminal order. * Updated compatibility list and added update checks for more mods. -* For the [log parser](https://log.smapi.io): +* For the [log parser](https://smapi.io/log): * Fixed incorrect filtering in some cases. * Fixed error if mods have duplicate names. * Fixed parse bugs if a mod has no author name. @@ -597,7 +614,7 @@ Released 25 February 2018 for Stardew Valley 1.2.30–1.2.33. * For modders: * Fixed issue where replacing an asset through `asset.AsImage()` or `asset.AsDictionary()` didn't take effect. -* For the [log parser](https://log.smapi.io): +* For the [log parser](https://smapi.io/log): * Fixed blank page after uploading a log in some cases. ## 2.5.1 @@ -628,7 +645,7 @@ Released 24 February 2018 for Stardew Valley 1.2.30–1.2.33. * Fixed unhelpful error when a translation file has duplicate keys due to case-insensitivity. * Fixed some JSON field names being case-sensitive. -* For the [log parser](https://log.smapi.io): +* For the [log parser](https://smapi.io/log): * Added support for SMAPI 2.5 content packs. * Reduced download size when viewing a parsed log with repeated errors. * Improved parse error handling. @@ -649,7 +666,7 @@ Released 24 January 2018 for Stardew Valley 1.2.30–1.2.33. * Fixed intermittent errors (e.g. 'collection has been modified') with some mods when loading a save. * Fixed compatibility with Linux Terminator terminal. -* For the [log parser](https://log.smapi.io): +* For the [log parser](https://smapi.io/log): * Fixed error parsing logs with zero installed mods. * For modders: @@ -684,7 +701,7 @@ Released 26 December 2017 for Stardew Valley 1.2.30–1.2.33. * Fixed issue where a mod could change the cursor position reported to other mods. * Updated compatibility list. -* For the [log parser](https://log.smapi.io): +* For the [log parser](https://smapi.io/log): * Fixed broken favicon. ## 2.2 @@ -698,7 +715,7 @@ Released 02 December 2017 for Stardew Valley 1.2.30–1.2.33. * Improved error when a mod has an invalid `EntryDLL` filename format. * Updated compatibility list. -* For the [log parser](https://log.smapi.io): +* For the [log parser](https://smapi.io/log): * Logs no longer expire after a week. * Fixed error when uploading very large logs. * Slightly improved the UI. @@ -713,7 +730,7 @@ Released 02 December 2017 for Stardew Valley 1.2.30–1.2.33. Released 01 November 2017 for Stardew Valley 1.2.30–1.2.33. * For players: - * Added a [log parser](https://log.smapi.io) site. + * Added a [log parser](https://smapi.io/log) site. * Added better Steam instructions to the SMAPI installer. * Renamed the bundled _TrainerMod_ to _ConsoleCommands_ to make its purpose clearer. * Removed the game's test messages from the console log. diff --git a/docs/technical/web.md b/docs/technical/web.md index 78d93625..97e0704a 100644 --- a/docs/technical/web.md +++ b/docs/technical/web.md @@ -14,13 +14,13 @@ and update check API. ## Log parser The log parser provides a web UI for uploading, parsing, and sharing SMAPI logs. The logs are -persisted in a compressed form to Pastebin. The log parser lives at https://log.smapi.io. +persisted in a compressed form to Pastebin. The log parser lives at https://smapi.io/log. ## JSON validator ### Overview The JSON validator provides a web UI for uploading and sharing JSON files, and validating them as plain JSON or against a predefined format like `manifest.json` or Content Patcher's `content.json`. -The JSON validator lives at https://json.smapi.io. +The JSON validator lives at https://smapi.io/json. ### Schema file format Schema files are defined in `wwwroot/schemas` using the [JSON Schema](https://json-schema.org/) @@ -111,7 +111,7 @@ format | schema URL ## Web API ### Overview -SMAPI provides a web API at `api.smapi.io` for use by SMAPI and external tools. The URL includes a +SMAPI provides a web API at `smapi.io/api` for use by SMAPI and external tools. The URL includes a `{version}` token, which is the SMAPI version for backwards compatibility. This API is publicly accessible but not officially released; it may change at any time. @@ -184,7 +184,7 @@ may be useful to external tools. Example request: ```js -POST https://api.smapi.io/v3.0/mods +POST https://smapi.io/api/v3.0/mods { "mods": [ { @@ -350,8 +350,7 @@ To launch the environment: mongod --dbpath C:\dev\smapi-cache ``` 2. Launch `SMAPI.Web` from Visual Studio to run a local version of the site. - <small>(Local URLs will use HTTP instead of HTTPS, and subdomains will become routes, like - `log.smapi.io` → `localhost:59482/log`.)</small> + <small>(Local URLs will use HTTP instead of HTTPS.)</small> ### Production environment A production environment includes the web servers and cache database hosted online for public @@ -367,7 +366,6 @@ Initial setup: ------------------------------- | ----------------- `LogParser:PastebinDevKey` | The [Pastebin developer key](https://pastebin.com/api#1) used to authenticate with the Pastebin API. `LogParser:PastebinUserKey` | The [Pastebin user key](https://pastebin.com/api#8) used to authenticate with the Pastebin API. Can be left blank to post anonymously. - `LogParser:SectionUrl` | The root URL of the log page, like `https://log.smapi.io/`. `ModUpdateCheck:GitHubPassword` | The password with which to authenticate to GitHub when fetching release info. `ModUpdateCheck:GitHubUsername` | The username with which to authenticate to GitHub when fetching release info. `MongoDB:Host` | The hostname for the MongoDB instance. diff --git a/src/SMAPI.Installer/unix-install.sh b/src/SMAPI.Installer/unix-install.sh index e3a5d8cc..6d0c86ce 100644 --- a/src/SMAPI.Installer/unix-install.sh +++ b/src/SMAPI.Installer/unix-install.sh @@ -12,6 +12,9 @@ elif type type >/dev/null 2>&1; then COMMAND="type" fi +# if $TERM is not set to xterm, mono will bail out when attempting to write to the console. +export TERM=xterm + # validate Mono & run installer if $COMMAND mono >/dev/null 2>&1; then mono internal/unix-install.exe diff --git a/src/SMAPI.Installer/unix-launcher.sh b/src/SMAPI.Installer/unix-launcher.sh index f81828f0..bebba9fe 100644 --- a/src/SMAPI.Installer/unix-launcher.sh +++ b/src/SMAPI.Installer/unix-launcher.sh @@ -62,7 +62,7 @@ else fi # select terminal (prefer $TERMINAL for overrides and testing, then xterm for best compatibility, then known supported terminals) - for terminal in "$TERMINAL" xterm gnome-terminal kitty terminator xfce4-terminal konsole terminal termite x-terminal-emulator; do + for terminal in "$TERMINAL" xterm gnome-terminal kitty terminator xfce4-terminal konsole terminal termite alacritty x-terminal-emulator; do if $COMMAND "$terminal" 2>/dev/null; then # Find the true shell behind x-terminal-emulator if [ "$(basename "$(readlink -f $(which "$terminal"))")" != "x-terminal-emulator" ]; then @@ -100,6 +100,14 @@ else # Kitty overrides the TERM varible unless you set it explicitly kitty -o term=xterm $LAUNCHER ;; + alacritty) + # Alacritty doesn't like the double quotes or the variable + if [ "$ARCH" == "x86_64" ]; then + alacritty -e sh -c 'TERM=xterm ./StardewModdingAPI.bin.x86_64 $*' + else + alacritty -e sh -c 'TERM=xterm ./StardewModdingAPI.bin.x86 $*' + fi + ;; xterm|xfce4-terminal|gnome-terminal|terminal|termite) $LAUNCHTERM -e "sh -c 'TERM=xterm $LAUNCHER'" ;; diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json index 802de3a6..badea825 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.0.0", + "Version": "3.0.1", "Description": "Adds SMAPI console commands that let you manipulate the game.", "UniqueID": "SMAPI.ConsoleCommands", "EntryDll": "ConsoleCommands.dll", - "MinimumApiVersion": "3.0.0" + "MinimumApiVersion": "3.0.1" } diff --git a/src/SMAPI.Mods.SaveBackup/manifest.json b/src/SMAPI.Mods.SaveBackup/manifest.json index eddd3443..252c359f 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.0.0", + "Version": "3.0.1", "Description": "Automatically backs up all your saves once per day into its folder.", "UniqueID": "SMAPI.SaveBackup", "EntryDll": "SaveBackup.dll", - "MinimumApiVersion": "3.0.0" + "MinimumApiVersion": "3.0.1" } diff --git a/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs b/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs index c91ec27f..48afcaa2 100644 --- a/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs +++ b/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs @@ -25,44 +25,50 @@ namespace SMAPI.Tests.Utilities [TestCase("1.2.3-some-tag.4", ExpectedResult = "1.2.3-some-tag.4")] [TestCase("1.2.3-SoME-tAg.4", ExpectedResult = "1.2.3-SoME-tAg.4")] [TestCase("1.2.3-some-tag.4 ", ExpectedResult = "1.2.3-some-tag.4")] + [TestCase("1.2.3-some-tag.4+build.004", ExpectedResult = "1.2.3-some-tag.4+build.004")] + [TestCase("1.2+3.4.5-build.004", ExpectedResult = "1.2.0+3.4.5-build.004")] public string Constructor_FromString(string input) { return new SemanticVersion(input).ToString(); } [Test(Description = "Assert that the constructor sets the expected values for all valid versions when constructed from the individual numbers.")] - [TestCase(1, 0, 0, null, ExpectedResult = "1.0.0")] - [TestCase(3000, 4000, 5000, null, ExpectedResult = "3000.4000.5000")] - [TestCase(1, 2, 3, "", ExpectedResult = "1.2.3")] - [TestCase(1, 2, 3, " ", ExpectedResult = "1.2.3")] - [TestCase(1, 2, 3, "0", ExpectedResult = "1.2.3-0")] - [TestCase(1, 2, 3, "some-tag.4", ExpectedResult = "1.2.3-some-tag.4")] - [TestCase(1, 2, 3, "sOMe-TaG.4", ExpectedResult = "1.2.3-sOMe-TaG.4")] - [TestCase(1, 2, 3, "some-tag.4 ", ExpectedResult = "1.2.3-some-tag.4")] - public string Constructor_FromParts(int major, int minor, int patch, string tag) + [TestCase(1, 0, 0, null, null, ExpectedResult = "1.0.0")] + [TestCase(3000, 4000, 5000, null, null, ExpectedResult = "3000.4000.5000")] + [TestCase(1, 2, 3, "", null, ExpectedResult = "1.2.3")] + [TestCase(1, 2, 3, " ", null, ExpectedResult = "1.2.3")] + [TestCase(1, 2, 3, "0", null, ExpectedResult = "1.2.3-0")] + [TestCase(1, 2, 3, "some-tag.4", null, ExpectedResult = "1.2.3-some-tag.4")] + [TestCase(1, 2, 3, "sOMe-TaG.4", null, ExpectedResult = "1.2.3-sOMe-TaG.4")] + [TestCase(1, 2, 3, "some-tag.4 ", null, ExpectedResult = "1.2.3-some-tag.4")] + [TestCase(1, 2, 3, "some-tag.4 ", "build.004", ExpectedResult = "1.2.3-some-tag.4+build.004")] + [TestCase(1, 2, 0, null, "3.4.5-build.004", ExpectedResult = "1.2.0+3.4.5-build.004")] + public string Constructor_FromParts(int major, int minor, int patch, string prerelease, string build) { // act - ISemanticVersion version = new SemanticVersion(major, minor, patch, tag); + ISemanticVersion version = new SemanticVersion(major, minor, patch, prerelease, build); // assert Assert.AreEqual(major, version.MajorVersion, "The major version doesn't match the given value."); Assert.AreEqual(minor, version.MinorVersion, "The minor version doesn't match the given value."); Assert.AreEqual(patch, version.PatchVersion, "The patch version doesn't match the given value."); - Assert.AreEqual(string.IsNullOrWhiteSpace(tag) ? null : tag.Trim(), version.PrereleaseTag, "The tag doesn't match the given value."); + Assert.AreEqual(string.IsNullOrWhiteSpace(prerelease) ? null : prerelease.Trim(), version.PrereleaseTag, "The prerelease tag doesn't match the given value."); + Assert.AreEqual(string.IsNullOrWhiteSpace(build) ? null : build.Trim(), version.BuildMetadata, "The build metadata doesn't match the given value."); return version.ToString(); } [Test(Description = "Assert that the constructor throws the expected exception for invalid versions when constructed from the individual numbers.")] - [TestCase(0, 0, 0, null)] - [TestCase(-1, 0, 0, null)] - [TestCase(0, -1, 0, null)] - [TestCase(0, 0, -1, null)] - [TestCase(1, 0, 0, "-tag")] - [TestCase(1, 0, 0, "tag spaces")] - [TestCase(1, 0, 0, "tag~")] - public void Constructor_FromParts_WithInvalidValues(int major, int minor, int patch, string tag) + [TestCase(0, 0, 0, null, null)] + [TestCase(-1, 0, 0, null, null)] + [TestCase(0, -1, 0, null, null)] + [TestCase(0, 0, -1, null, null)] + [TestCase(1, 0, 0, "-tag", null)] + [TestCase(1, 0, 0, "tag spaces", null)] + [TestCase(1, 0, 0, "tag~", null)] + [TestCase(1, 0, 0, null, "build~")] + public void Constructor_FromParts_WithInvalidValues(int major, int minor, int patch, string prerelease, string build) { - this.AssertAndLogException<FormatException>(() => new SemanticVersion(major, minor, patch, tag)); + this.AssertAndLogException<FormatException>(() => new SemanticVersion(major, minor, patch, prerelease, build)); } [Test(Description = "Assert that the constructor sets the expected values for all valid versions when constructed from an assembly version.")] @@ -98,6 +104,7 @@ namespace SMAPI.Tests.Utilities [TestCase("1.2.3--some-tag")] [TestCase("1.2.3-some-tag...")] [TestCase("1.2.3-some-tag...4")] + [TestCase("1.2.3-some-tag.4+build...4")] [TestCase("apple")] [TestCase("-apple")] [TestCase("-5")] @@ -119,6 +126,8 @@ namespace SMAPI.Tests.Utilities [TestCase("1.0-beta", "1.0-beta", ExpectedResult = 0)] [TestCase("1.0-beta.10", "1.0-beta.10", ExpectedResult = 0)] [TestCase("1.0-beta", "1.0-beta ", ExpectedResult = 0)] + [TestCase("1.0-beta+build.001", "1.0-beta+build.001", ExpectedResult = 0)] + [TestCase("1.0-beta+build.001", "1.0-beta+build.006", ExpectedResult = 0)] // build metadata must not affect precedence // less than [TestCase("0.5.7", "0.5.8", ExpectedResult = -1)] @@ -156,6 +165,8 @@ namespace SMAPI.Tests.Utilities [TestCase("1.0-beta", "1.0-beta", ExpectedResult = false)] [TestCase("1.0-beta.10", "1.0-beta.10", ExpectedResult = false)] [TestCase("1.0-beta", "1.0-beta ", ExpectedResult = false)] + [TestCase("1.0-beta+build.001", "1.0-beta+build.001", ExpectedResult = false)] // build metadata must not affect precedence + [TestCase("1.0-beta+build.001", "1.0-beta+build.006", ExpectedResult = false)] // build metadata must not affect precedence // less than [TestCase("0.5.7", "0.5.8", ExpectedResult = true)] @@ -192,6 +203,8 @@ namespace SMAPI.Tests.Utilities [TestCase("1.0-beta", "1.0-beta", ExpectedResult = false)] [TestCase("1.0-beta.10", "1.0-beta.10", ExpectedResult = false)] [TestCase("1.0-beta", "1.0-beta ", ExpectedResult = false)] + [TestCase("1.0-beta+build.001", "1.0-beta+build.001", ExpectedResult = false)] // build metadata must not affect precedence + [TestCase("1.0-beta+build.001", "1.0-beta+build.006", ExpectedResult = false)] // build metadata must not affect precedence // less than [TestCase("0.5.7", "0.5.8", ExpectedResult = false)] @@ -279,6 +292,8 @@ namespace SMAPI.Tests.Utilities [TestCase("1.11")] [TestCase("1.2")] [TestCase("1.2.15")] + [TestCase("1.4.0.1")] + [TestCase("1.4.0.6")] public void GameVersion(string versionStr) { // act @@ -286,7 +301,6 @@ namespace SMAPI.Tests.Utilities // assert Assert.AreEqual(versionStr, version.ToString(), "The game version did not round-trip to the same value."); - Assert.IsTrue(version.IsOlderThan(new SemanticVersion("1.2.30")), "The game version should be considered older than the later semantic versions."); } diff --git a/src/SMAPI.Toolkit.CoreInterfaces/ISemanticVersion.cs b/src/SMAPI.Toolkit.CoreInterfaces/ISemanticVersion.cs index 4ec87d7c..b8572d50 100644 --- a/src/SMAPI.Toolkit.CoreInterfaces/ISemanticVersion.cs +++ b/src/SMAPI.Toolkit.CoreInterfaces/ISemanticVersion.cs @@ -20,6 +20,9 @@ namespace StardewModdingAPI /// <summary>An optional prerelease tag.</summary> string PrereleaseTag { get; |
