summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/release-notes.md7
-rw-r--r--src/SMAPI.Installer/readme.txt4
-rw-r--r--src/SMAPI.Tests/Utilities/SemanticVersionTests.cs16
-rw-r--r--src/SMAPI.Web/Views/Index/Index.cshtml33
-rw-r--r--src/SMAPI.Web/Views/LogParser/Index.cshtml4
-rw-r--r--src/SMAPI.Web/wwwroot/Content/css/index.css55
-rw-r--r--src/SMAPI.Web/wwwroot/Content/css/log-parser.css4
-rw-r--r--src/SMAPI.Web/wwwroot/Content/images/direct-download-icon.pngbin0 -> 250 bytes
-rw-r--r--src/SMAPI.Web/wwwroot/Content/images/nexus-icon.pngbin0 -> 927 bytes
-rw-r--r--src/SMAPI.Web/wwwroot/Content/images/pufferchick-cool.pngbin2921 -> 1099 bytes
-rw-r--r--src/SMAPI.Web/wwwroot/Content/images/pufferchick.pngbin0 -> 831 bytes
-rw-r--r--src/SMAPI.Web/wwwroot/Content/js/index.js27
-rw-r--r--src/SMAPI/Events/IWorldEvents.cs3
-rw-r--r--src/SMAPI/Events/WorldDebrisListChangedEventArgs.cs38
-rw-r--r--src/SMAPI/Framework/Events/EventManager.cs4
-rw-r--r--src/SMAPI/Framework/Events/ModWorldEvents.cs7
-rw-r--r--src/SMAPI/Framework/SGame.cs11
-rw-r--r--src/SMAPI/Framework/StateTracking/LocationTracker.cs5
-rw-r--r--src/SMAPI/Framework/WatcherCore.cs2
-rw-r--r--src/SMAPI/StardewModdingAPI.csproj9
-rw-r--r--src/SMAPI/StardewModdingAPI.metadata.json7
-rw-r--r--src/SMAPI/packages.config1
-rw-r--r--src/StardewModdingAPI.Toolkit/SemanticVersion.cs27
23 files changed, 240 insertions, 24 deletions
diff --git a/docs/release-notes.md b/docs/release-notes.md
index a343cff3..df832c34 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -8,6 +8,7 @@
* Added friendly error when game can't start audio.
* Added console warning for mods which don't have update checks configured.
* Improved how mod warnings are shown in the console.
+ * Fixed `SEHException` errors and performance issues in some cases.
* Fixed console color scheme on Mac or in PowerShell, configurable via `StardewModdingAPI.config.json`.
* Fixed installer error on Linux/Mac in some cases.
* Fixed installer not finding some game paths.
@@ -46,6 +47,7 @@
* Fixed some common non-mod build output being included in release zip.
* Fixed mods able to intercept other mods' assets via the internal asset keys.
* Fixed mods able to indirectly change other mods' data through shared content caches.
+ * Fixed `SemanticVersion` allowing invalid versions in some cases.
* **Breaking changes** (see [migration guide](https://stardewvalleywiki.com/Modding:Migrate_to_Stardew_Valley_1.3)):
* Dropped some deprecated APIs.
* `LocationEvents` have been rewritten.
@@ -58,9 +60,10 @@
* Fixed `world_setseason` not normalising the season value.
* For the web UI:
- * Redesigned log parser upload page to make it more intuitive for new players.
- * Changed log parser filters to show `DEBUG` messages by default.
+ * Improved log parser design to make it more intuitive.
* Improved layout on small screens.
+ * Added option to download from Nexus.
+ * Changed log parser filters to show `DEBUG` messages by default.
* Fixed log parser issue when content packs have no description.
* Fixed log parser mangling crossplatform paths in some cases.
diff --git a/src/SMAPI.Installer/readme.txt b/src/SMAPI.Installer/readme.txt
index 12053a8c..2ee5473c 100644
--- a/src/SMAPI.Installer/readme.txt
+++ b/src/SMAPI.Installer/readme.txt
@@ -16,7 +16,7 @@ SMAPI lets you run Stardew Valley with mods. Don't forget to download mods separ
Player's guide
--------------------------------
-See https://stardewvalleywiki.com/Modding:Player_Guide.
+See https://stardewvalleywiki.com/Modding:Player_Guide
Manual install
@@ -24,7 +24,7 @@ Manual install
THIS IS NOT RECOMMENDED FOR MOST PLAYERS. See instructions above instead.
If you really want to install SMAPI manually, here's how.
-1. Download the latest version of SMAPI: https://github.com/Pathoschild/SMAPI/releases.
+1. Download the latest version of SMAPI: https://github.com/Pathoschild/SMAPI/releases
2. Unzip the .zip file somewhere (not in your game folder).
3. Copy the files from the "internal/Windows" folder (on Windows) or "internal/Mono" folder (on
Linux/Mac) into your game folder. The `StardewModdingAPI.exe` file should be right next to the
diff --git a/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs b/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs
index feab452a..35d74b60 100644
--- a/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs
+++ b/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs
@@ -22,6 +22,7 @@ namespace StardewModdingAPI.Tests.Utilities
[TestCase("3000.4000.5000", ExpectedResult = "3000.4000.5000")]
[TestCase("1.2-some-tag.4", ExpectedResult = "1.2-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 ", ExpectedResult = "1.2.3-some-tag.4")]
public string Constructor_FromString(string input)
{
@@ -35,6 +36,7 @@ namespace StardewModdingAPI.Tests.Utilities
[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)
{
@@ -49,6 +51,19 @@ namespace StardewModdingAPI.Tests.Utilities
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)
+ {
+ this.AssertAndLogException<FormatException>(() => new SemanticVersion(major, minor, patch, tag));
+ }
+
[Test(Description = "Assert that the constructor sets the expected values for all valid versions when constructed from an assembly version.")]
[TestCase(1, 0, 0, ExpectedResult = "1.0")]
[TestCase(1, 2, 3, ExpectedResult = "1.2.3")]
@@ -79,6 +94,7 @@ namespace StardewModdingAPI.Tests.Utilities
[TestCase("1.2.3.apple")]
[TestCase("1..2..3")]
[TestCase("1.2.3-")]
+ [TestCase("1.2.3--some-tag")]
[TestCase("1.2.3-some-tag...")]
[TestCase("1.2.3-some-tag...4")]
[TestCase("apple")]
diff --git a/src/SMAPI.Web/Views/Index/Index.cshtml b/src/SMAPI.Web/Views/Index/Index.cshtml
index 6dc0a338..411448fa 100644
--- a/src/SMAPI.Web/Views/Index/Index.cshtml
+++ b/src/SMAPI.Web/Views/Index/Index.cshtml
@@ -3,9 +3,9 @@
}
@model StardewModdingAPI.Web.ViewModels.IndexModel
@section Head {
- <link rel="stylesheet" href="~/Content/css/index.css" />
+ <link rel="stylesheet" href="~/Content/css/index.css?r=20180615" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" crossorigin="anonymous"></script>
- <script src="~/Content/js/index.js"></script>
+ <script src="~/Content/js/index.js?r=20180615"></script>
}
<p id="blurb">
@@ -15,16 +15,29 @@
</p>
<div id="call-to-action">
- <a href="@Model.StableVersion.DownloadUrl" class="main-cta download">Download SMAPI @Model.StableVersion.Version</a><br />
+ <div class="cta-dropdown">
+ <a href="@Model.StableVersion.DownloadUrl" class="main-cta download">Download SMAPI @Model.StableVersion.Version</a><br/>
+ <div class="dropdown-content">
+ <a href="https://www.nexusmods.com/stardewvalley/mods/2400"><img src="Content/images/nexus-icon.png" /> Download from Nexus</a>
+ <a href="@Model.StableVersion.DownloadUrl"><img src="Content/images/direct-download-icon.png" /> Direct download</a>
+ </div>
+ </div><br />
+
@if (Model.BetaVersion != null)
{
- <a href="@Model.BetaVersion.DownloadUrl" class="secondary-cta download">Download SMAPI @Model.BetaVersion.Version<br /><small>for Stardew Valley 1.3 beta</small></a><br />
+ <div class="cta-dropdown secondary-cta-dropdown">
+ <a href="@Model.BetaVersion.DownloadUrl" class="secondary-cta download">Download SMAPI @Model.BetaVersion.Version<br/><small>for Stardew Valley 1.3 beta</small></a><br/>
+ <div class="dropdown-content">
+ <a href="https://www.nexusmods.com/stardewvalley/mods/2400"><img src="Content/images/nexus-icon.png" /> Download from Nexus</a>
+ <a href="@Model.BetaVersion.DownloadUrl"><img src="Content/images/direct-download-icon.png" /> Direct download</a>
+ </div>
+ </div><br />
}
<a href="https://stardewvalleywiki.com/Modding:Player_Guide" class="secondary-cta">Player guide</a><br />
- <img id="pufferchick" src="favicon.ico" />
+ <img id="pufferchick" src="Content/images/pufferchick.png" />
</div>
-<h2>Get help</h2>
+<h2 id="help">Get help</h2>
<ul>
<li><a href="https://stardewvalleywiki.com/Modding:SMAPI_compatibility">Mod compatibility list</a></li>
<li>Get help <a href="https://stardewvalleywiki.com/Modding:Community#Discord">on Discord</a> or <a href="https://community.playstarbound.com/threads/smapi-stardew-modding-api.108375/">in the forums</a></li>
@@ -32,7 +45,7 @@
@if (Model.BetaVersion == null)
{
- <h2>What's new in SMAPI @Model.StableVersion.Version?</h2>
+ <h2 id="whatsnew">What's new in SMAPI @Model.StableVersion.Version?</h2>
<div class="github-description">
@Html.Raw(Markdig.Markdown.ToHtml(Model.StableVersion.Description))
</div>
@@ -40,7 +53,7 @@
}
else
{
- <h2>What's new in...</h2>
+ <h2 id="whatsnew">What's new in...</h2>
<h3>SMAPI @Model.StableVersion.Version?</h3>
<div class="github-description">
@Html.Raw(Markdig.Markdown.ToHtml(Model.StableVersion.Description))
@@ -54,7 +67,7 @@ else
<p>See the <a href="https://github.com/Pathoschild/SMAPI/blob/develop/docs/release-notes.md#release-notes">release notes</a> and <a href="https://stardewvalleywiki.com/Modding:SMAPI_compatibility">mod compatibility list</a> for more info.</p>
}
-<h2>Donate to support SMAPI ♥</h2>
+<h2 id="donate">Donate to support SMAPI ♥</h2>
<p>
SMAPI is an open-source project by Pathoschild. It will always be free, but donations
are much appreciated to help pay for development, server hosting, domain fees, coffee, etc.
@@ -85,7 +98,7 @@ else
and a few anonymous users for their ongoing support; you're awesome! 🏅
</p>
-<h2>For mod creators</h2>
+<h2 id="modcreators">For mod creators</h2>
<ul>
<li><a href="@Model.StableVersion.DevDownloadUrl">SMAPI @Model.StableVersion.Version for developers</a> (includes <a href="https://docs.microsoft.com/en-us/visualstudio/ide/using-intellisense">intellisense</a> and full console output)</li>
@if (Model.BetaVersion != null)
diff --git a/src/SMAPI.Web/Views/LogParser/Index.cshtml b/src/SMAPI.Web/Views/LogParser/Index.cshtml
index 7307817c..4d95901e 100644
--- a/src/SMAPI.Web/Views/LogParser/Index.cshtml
+++ b/src/SMAPI.Web/Views/LogParser/Index.cshtml
@@ -12,10 +12,10 @@
{
<meta name="robots" content="noindex" />
}
- <link rel="stylesheet" href="~/Content/css/log-parser.css?r=20180603" />
+ <link rel="stylesheet" href="~/Content/css/log-parser.css?r=20180611" />
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" crossorigin="anonymous"></script>
- <script src="~/Content/js/log-parser.js?r=20180603"></script>
+ <script src="~/Content/js/log-parser.js?r=20180611"></script>
<script>
$(function() {
smapi.logParser({
diff --git a/src/SMAPI.Web/wwwroot/Content/css/index.css b/src/SMAPI.Web/wwwroot/Content/css/index.css
index 6340ed87..514e1a5c 100644
--- a/src/SMAPI.Web/wwwroot/Content/css/index.css
+++ b/src/SMAPI.Web/wwwroot/Content/css/index.css
@@ -18,7 +18,8 @@ h1 {
text-align: center;
}
-#call-to-action a {
+#call-to-action a.main-cta,
+#call-to-action a.secondary-cta {
box-shadow: #caefab 0 1px 0 0 inset;
background: linear-gradient(#77d42a 5%, #5cb811 100%) #77d42a;
border-radius: 6px;
@@ -40,6 +41,58 @@ h1 {
text-shadow: #2b665e 0 1px 0;
}
+.cta-dropdown {
+ position: relative;
+ display: inline-block;
+ margin-bottom: 1em;
+}
+
+.cta-dropdown a.download {
+ margin-bottom: 0 !important;
+}
+
+.cta-dropdown .dropdown-content {
+ display: none;
+ position: absolute;
+ text-align: left;
+ box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
+ border: 1px solid #566963;
+ background: #5cb811;
+ border-top: 0;
+ border-radius: 0 0 6px 6px;
+ margin-top: -6px;
+ z-index: 1;
+}
+
+.cta-dropdown .dropdown-content a:hover {
+ background-color: #ddd;
+}
+
+.cta-dropdown .dropdown-content img {
+ width: 0.85em;
+ height: 0.85em;
+}
+
+.cta-dropdown.secondary-cta-dropdown .dropdown-content a:hover {
+ background-color: #566963;
+}
+
+.cta-dropdown.secondary-cta-dropdown .dropdown-content {
+ background-color: #768d87;
+ border-color: #566963;
+}
+
+.cta-dropdown.secondary-cta-dropdown .dropdown-content a {
+ color: #fff;
+ text-shadow: #2b665e 0 1px 0;
+}
+
+.cta-dropdown .dropdown-content a {
+ padding: 0.75em 1em;
+ text-decoration: none;
+ display: block;
+}
+
/*********
** Subsections
*********/
diff --git a/src/SMAPI.Web/wwwroot/Content/css/log-parser.css b/src/SMAPI.Web/wwwroot/Content/css/log-parser.css
index 5c4f8aea..09bb97f5 100644
--- a/src/SMAPI.Web/wwwroot/Content/css/log-parser.css
+++ b/src/SMAPI.Web/wwwroot/Content/css/log-parser.css
@@ -1,6 +1,10 @@
/*********
** Main layout
*********/
+#content {
+ max-width: 100%;
+}
+
caption {
text-align: left;
padding-top: 2px;
diff --git a/src/SMAPI.Web/wwwroot/Content/images/direct-download-icon.png b/src/SMAPI.Web/wwwroot/Content/images/direct-download-icon.png
new file mode 100644
index 00000000..6c30ca36
--- /dev/null
+++ b/src/SMAPI.Web/wwwroot/Content/images/direct-download-icon.png
Binary files differ
diff --git a/src/SMAPI.Web/wwwroot/Content/images/nexus-icon.png b/src/SMAPI.Web/wwwroot/Content/images/nexus-icon.png
new file mode 100644
index 00000000..10c66712
--- /dev/null
+++ b/src/SMAPI.Web/wwwroot/Content/images/nexus-icon.png
Binary files differ
diff --git a/src/SMAPI.Web/wwwroot/Content/images/pufferchick-cool.png b/src/SMAPI.Web/wwwroot/Content/images/pufferchick-cool.png
index 63eb8970..f359146c 100644
--- a/src/SMAPI.Web/wwwroot/Content/images/pufferchick-cool.png
+++ b/src/SMAPI.Web/wwwroot/Content/images/pufferchick-cool.png
Binary files differ
diff --git a/src/SMAPI.Web/wwwroot/Content/images/pufferchick.png b/src/SMAPI.Web/wwwroot/Content/images/pufferchick.png
new file mode 100644
index 00000000..1de9cf47
--- /dev/null
+++ b/src/SMAPI.Web/wwwroot/Content/images/pufferchick.png
Binary files differ
diff --git a/src/SMAPI.Web/wwwroot/Content/js/index.js b/src/SMAPI.Web/wwwroot/Content/js/index.js
index 016d5fa4..d0734b02 100644
--- a/src/SMAPI.Web/wwwroot/Content/js/index.js
+++ b/src/SMAPI.Web/wwwroot/Content/js/index.js
@@ -1,11 +1,34 @@
$(document).ready(function () {
+ /* enable pufferchick */
var pufferchick = $("#pufferchick");
- $(".download").hover(
+ $(".cta-dropdown").hover(
function () {
pufferchick.attr("src", "Content/images/pufferchick-cool.png");
},
function () {
- pufferchick.attr("src", "favicon.ico");
+ pufferchick.attr("src", "Content/images/pufferchick.png");
}
);
+
+ /* enable download dropdowns */
+ $(".cta-dropdown a.download").each(function(i, button) {
+ button = $(button);
+ var wrapper = button.parent(".cta-dropdown");
+ var button = wrapper.find(".download");
+ var dropdownContent = wrapper.find(".dropdown-content");
+
+ $(window).on("click", function(e) {
+ var target = $(e.target);
+
+ // toggle dropdown on button click
+ if (target.is(button) || $.contains(button.get(0), target.get(0))) {
+ e.preventDefault();
+ dropdownContent.toggle();
+ }
+
+ // else hide dropdown
+ else
+ dropdownContent.hide();
+ });
+ });
});
diff --git a/src/SMAPI/Events/IWorldEvents.cs b/src/SMAPI/Events/IWorldEvents.cs
index 067a79bc..d4efb53b 100644
--- a/src/SMAPI/Events/IWorldEvents.cs
+++ b/src/SMAPI/Events/IWorldEvents.cs
@@ -11,6 +11,9 @@ namespace StardewModdingAPI.Events
/// <summary>Raised after buildings are added or removed in a location.</summary>
event EventHandler<WorldBuildingListChangedEventArgs> BuildingListChanged;
+ /// <summary>Raised after debris are added or removed in a location.</summary>
+ event EventHandler<WorldDebrisListChangedEventArgs> DebrisListChanged;
+
/// <summary>Raised after large terrain features (like bushes) are added or removed in a location.</summary>
event EventHandler<WorldLargeTerrainFeatureListChangedEventArgs> LargeTerrainFeatureListChanged;
diff --git a/src/SMAPI/Events/WorldDebrisListChangedEventArgs.cs b/src/SMAPI/Events/WorldDebrisListChangedEventArgs.cs
new file mode 100644
index 00000000..aad9c24d
--- /dev/null
+++ b/src/SMAPI/Events/WorldDebrisListChangedEventArgs.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using StardewValley;
+
+namespace StardewModdingAPI.Events
+{
+ /// <summary>Event arguments for a <see cref="IWorldEvents.DebrisListChanged"/> event.</summary>
+ public class WorldDebrisListChangedEventArgs : EventArgs
+ {
+ /*********
+ ** Accessors
+ *********/
+ /// <summary>The location which changed.</summary>
+ public GameLocation Location { get; }
+
+ /// <summary>The debris added to the location.</summary>
+ public IEnumerable<Debris> Added { get; }
+
+ /// <summary>The debris removed from the location.</summary>
+ public IEnumerable<Debris> Removed { get; }
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="location">The location which changed.</param>
+ /// <param name="added">The debris added to the location.</param>
+ /// <param name="removed">The debris removed from the location.</param>
+ public WorldDebrisListChangedEventArgs(GameLocation location, IEnumerable<Debris> added, IEnumerable<Debris> removed)
+ {
+ this.Location = location;
+ this.Added = added.ToArray();
+ this.Removed = removed.ToArray();
+ }
+ }
+}
diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs
index 9f67244a..b05d82ce 100644
--- a/src/SMAPI/Framework/Events/EventManager.cs
+++ b/src/SMAPI/Framework/Events/EventManager.cs
@@ -20,6 +20,9 @@ namespace StardewModdingAPI.Framework.Events
/// <summary>Raised after buildings are added or removed in a location.</summary>
public readonly ManagedEvent<WorldBuildingListChangedEventArgs> World_BuildingListChanged;
+ /// <summary>Raised after debris are added or removed in a location.</summary>
+ public readonly ManagedEvent<WorldDebrisListChangedEventArgs> World_DebrisListChanged;
+
/// <summary>Raised after large terrain features (like bushes) are added or removed in a location.</summary>
public readonly ManagedEvent<WorldLargeTerrainFeatureListChangedEventArgs> World_LargeTerrainFeatureListChanged;
@@ -255,6 +258,7 @@ namespace StardewModdingAPI.Framework.Events
this.Input_MouseWheelScrolled = ManageEventOf<InputMouseWheelScrolledEventArgs>(nameof(IModEvents.Input), nameof(IInputEvents.MouseWheelScrolled));
this.World_BuildingListChanged = ManageEventOf<WorldBuildingListChangedEventArgs>(nameof(IModEvents.World), nameof(IWorldEvents.LocationListChanged));
+ this.World_DebrisListChanged = ManageEventOf<WorldDebrisListChangedEventArgs>(nameof(IModEvents.World), nameof(IWorldEvents.DebrisListChanged));
this.World_LargeTerrainFeatureListChanged = ManageEventOf<WorldLargeTerrainFeatureListChangedEventArgs>(nameof(IModEvents.World), nameof(IWorldEvents.LargeTerrainFeatureListChanged));
this.World_LocationListChanged = ManageEventOf<WorldLocationListChangedEventArgs>(nameof(IModEvents.World), nameof(IWorldEvents.BuildingListChanged));
this.World_NpcListChanged = ManageEventOf<WorldNpcListChangedEventArgs>(nameof(IModEvents.World), nameof(IWorldEvents.NpcListChanged));
diff --git a/src/SMAPI/Framework/Events/ModWorldEvents.cs b/src/SMAPI/Framework/Events/ModWorldEvents.cs
index e1a53e0c..dc9c0f4c 100644
--- a/src/SMAPI/Framework/Events/ModWorldEvents.cs
+++ b/src/SMAPI/Framework/Events/ModWorldEvents.cs
@@ -23,6 +23,13 @@ namespace StardewModdingAPI.Framework.Events
remove => this.EventManager.World_BuildingListChanged.Remove(value);
}
+ /// <summary>Raised after debris are added or removed in a location.</summary>
+ public event EventHandler<WorldDebrisListChangedEventArgs> DebrisListChanged
+ {
+ add => this.EventManager.World_DebrisListChanged.Add(value, this.Mod);
+ remove => this.EventManager.World_DebrisListChanged.Remove(value);
+ }
+
/// <summary>Raised after large terrain features (like bushes) are added or removed in a location.</summary>
public event EventHandler<WorldLargeTerrainFeatureListChangedEventArgs> LargeTerrainFeatureListChanged
{
diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs
index 588d30c8..984c1f57 100644
--- a/src/SMAPI/Framework/SGame.cs
+++ b/src/SMAPI/Framework/SGame.cs
@@ -536,6 +536,17 @@ namespace StardewModdingAPI.Framework
this.Events.Legacy_Location_BuildingsChanged.Raise(new EventArgsLocationBuildingsChanged(location, added, removed));
}
+ // debris changed
+ if (watcher.DebrisWatcher.IsChanged)
+ {
+ GameLocation location = watcher.Location;
+ Debris[] added = watcher.DebrisWatcher.Added.ToArray();
+ Debris[] removed = watcher.DebrisWatcher.Removed.ToArray();
+ watcher.DebrisWatcher.Reset();
+
+ this.Events.World_DebrisListChanged.Raise(new WorldDebrisListChangedEventArgs(location, added, removed));
+ }
+
// large terrain features changed
if (watcher.LargeTerrainFeaturesWatcher.IsChanged)
{
diff --git a/src/SMAPI/Framework/StateTracking/LocationTracker.cs b/src/SMAPI/Framework/StateTracking/LocationTracker.cs
index 1b4c0b19..708c0716 100644
--- a/src/SMAPI/Framework/StateTracking/LocationTracker.cs
+++ b/src/SMAPI/Framework/StateTracking/LocationTracker.cs
@@ -33,6 +33,9 @@ namespace StardewModdingAPI.Framework.StateTracking
/// <summary>Tracks added or removed buildings.</summary>
public ICollectionWatcher<Building> BuildingsWatcher { get; }
+ /// <summary>Tracks added or removed debris.</summary>
+ public ICollectionWatcher<Debris> DebrisWatcher { get; }
+
/// <summary>Tracks added or removed large terrain features.</summary>
public ICollectionWatcher<LargeTerrainFeature> LargeTerrainFeaturesWatcher { get; }
@@ -59,6 +62,7 @@ namespace StardewModdingAPI.Framework.StateTracking
this.BuildingsWatcher = location is BuildableGameLocation buildableLocation
? WatcherFactory.ForNetCollection(buildableLocation.buildings)
: (ICollectionWatcher<Building>)WatcherFactory.ForObservableCollection(new ObservableCollection<Building>());
+ this.DebrisWatcher = WatcherFactory.ForNetCollection(location.debris);
this.LargeTerrainFeaturesWatcher = WatcherFactory.ForNetCollection(location.largeTerrainFeatures);
this.NpcsWatcher = WatcherFactory.ForNetCollection(location.characters);
this.ObjectsWatcher = WatcherFactory.ForNetDictionary(location.netObjects);
@@ -67,6 +71,7 @@ namespace StardewModdingAPI.Framework.StateTracking
this.Watchers.AddRange(new IWatcher[]
{
this.BuildingsWatcher,
+ this.DebrisWatcher,
this.LargeTerrainFeaturesWatcher,
this.NpcsWatcher,
this.ObjectsWatcher,
diff --git a/src/SMAPI/Framework/WatcherCore.cs b/src/SMAPI/Framework/WatcherCore.cs
index 64b063cf..e06423b9 100644
--- a/src/SMAPI/Framework/WatcherCore.cs
+++ b/src/SMAPI/Framework/WatcherCore.cs
@@ -13,7 +13,7 @@ namespace StardewModdingAPI.Framework
internal class WatcherCore
{
/*********
- ** Public methods
+ ** Properties
*********/
/// <summary>The underlying watchers for convenience. These are accessible individually as separate properties.</summary>
private readonly List<IWatcher> Watchers = new List<IWatcher>();
diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj
index 67c48a57..fcd54c34 100644
--- a/src/SMAPI/StardewModdingAPI.csproj
+++ b/src/SMAPI/StardewModdingAPI.csproj
@@ -27,6 +27,7 @@
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
+ <LargeAddressAware Condition="'$(OS)' == 'Windows_NT'">true</LargeAddressAware>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget>
@@ -97,6 +98,7 @@
<Compile Include="Events\IInputEvents.cs" />
<Compile Include="Events\IWorldEvents.cs" />
<Compile Include="Events\MultiplayerEvents.cs" />
+ <Compile Include="Events\WorldDebrisListChangedEventArgs.cs" />
<Compile Include="Events\WorldNpcListChangedEventArgs.cs" />
<Compile Include="Events\WorldLargeTerrainFeatureListChangedEventArgs.cs" />
<Compile Include="Events\WorldTerrainFeatureListChangedEventArgs.cs" />
@@ -343,4 +345,11 @@
<Import Project="..\SMAPI.Internal\SMAPI.Internal.projitems" Label="Shared" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\build\common.targets" />
+ <Import Project="..\packages\LargeAddressAware.1.0.3\build\LargeAddressAware.targets" Condition="Exists('..\packages\LargeAddressAware.1.0.3\build\LargeAddressAware.targets')" />
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('..\packages\LargeAddressAware.1.0.3\build\LargeAddressAware.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\LargeAddressAware.1.0.3\build\LargeAddressAware.targets'))" />
+ </Target>
</Project> \ No newline at end of file
diff --git a/src/SMAPI/StardewModdingAPI.metadata.json b/src/SMAPI/StardewModdingAPI.metadata.json
index adf5fdd1..8ac5c734 100644
--- a/src/SMAPI/StardewModdingAPI.metadata.json
+++ b/src/SMAPI/StardewModdingAPI.metadata.json
@@ -168,8 +168,8 @@
"Automate": {
"ID": "Pathoschild.Automate",
- "Default | UpdateKey": "Nexus:1063",
- "~1.9.1 | Status": "AssumeBroken" // broke in SDV 1.3
+ "Default | UpdateKey": "Nexus:1063",
+ "~1.10-beta.7 | Status": "AssumeBroken" // broke in SDV 1.3.20
},
"Automated Doors": {
@@ -685,7 +685,8 @@
"Fishing Adjust": {
"ID": "shuaiz.FishingAdjustMod",
- "Default | UpdateKey": "Nexus:1350"
+ "Default | UpdateKey": "Nexus:1350",
+ "~2.0.1 | Status": "AssumeBroken" // Method not found: 'Void Harmony.HarmonyInstance.Patch(System.Reflection.MethodBase, Harmony.HarmonyMethod, Harmony.HarmonyMethod, Harmony.HarmonyMethod)'
},
"Fishing Tuner Redux": {
diff --git a/src/SMAPI/packages.config b/src/SMAPI/packages.config
index 3e876922..3347b037 100644
--- a/src/SMAPI/packages.config
+++ b/src/SMAPI/packages.config
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
+ <package id="LargeAddressAware" version="1.0.3" targetFramework="net45" />
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net45" />
<package id="Newtonsoft.Json" version="11.0.2" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/StardewModdingAPI.Toolkit/SemanticVersion.cs b/src/StardewModdingAPI.Toolkit/SemanticVersion.cs
index bd85f990..de480416 100644
--- a/src/StardewModdingAPI.Toolkit/SemanticVersion.cs
+++ b/src/StardewModdingAPI.Toolkit/SemanticVersion.cs
@@ -10,8 +10,11 @@ namespace StardewModdingAPI.Toolkit
/*********
** Properties
*********/
+ /// <summary>A regex pattern matching a valid prerelease tag.</summary>
+ internal const string TagPattern = @"(?>[a-z0-9]+[\-\.]?)+";
+
/// <summary>A regex pattern matching a version within a larger string.</summary>
- internal const string UnboundedVersionPattern = @"(?>(?<major>0|[1-9]\d*))\.(?>(?<minor>0|[1-9]\d*))(?>(?:\.(?<patch>0|[1-9]\d*))?)(?:-(?<prerelease>(?>[a-z0-9]+[\-\.]?)+))?";
+ internal const string UnboundedVersionPattern = @"(?>(?<major>0|[1-9]\d*))\.(?>(?<minor>0|[1-9]\d*))(?>(?:\.(?<patch>0|[1-9]\d*))?)(?:-(?<prerelease>" + SemanticVersion.TagPattern + "))?";
/// <summary>A regular expression matching a semantic version string.</summary>
/// <remarks>
@@ -54,6 +57,8 @@ namespace StardewModdingAPI.Toolkit
this.Minor = minor;
this.Patch = patch;
this.Tag = this.GetNormalisedTag(tag);
+
+ this.AssertValid();
}
/// <summary>Construct an instance.</summary>
@@ -67,6 +72,8 @@ namespace StardewModdingAPI.Toolkit
this.Major = version.Major;
this.Minor = version.Minor;
this.Patch = version.Build;
+
+ this.AssertValid();
}
/// <summary>Construct an instance.</summary>
@@ -87,6 +94,8 @@ namespace StardewModdingAPI.Toolkit
this.Minor = match.Groups["minor"].Success ? int.Parse(match.Groups["minor"].Value) : 0;
this.Patch = match.Groups["patch"].Success ? int.Parse(match.Groups["patch"].Value) : 0;
this.Tag = match.Groups["prerelease"].Success ? this.GetNormalisedTag(match.Groups["prerelease"].Value) : null;
+
+ this.AssertValid();
}
/// <summary>Get an integer indicating whether this version precedes (less than 0), supercedes (more than 0), or is equivalent to (0) the specified version.</summary>
@@ -235,5 +244,21 @@ namespace StardewModdingAPI.Toolkit
// fallback (this should never happen)
return string.Compare(this.ToString(), new SemanticVersion(otherMajor, otherMinor, otherPatch, otherTag).ToString(), StringComparison.InvariantCultureIgnoreCase);
}
+
+ /// <summary>Assert that the current version is valid.</summary>
+ private void AssertValid()
+ {
+ if (this.Major < 0 || this.Minor < 0 || this.Patch < 0)
+ throw new FormatException($"{this} isn't a valid semantic version. The major, minor, and patch numbers can't be negative.");
+ if (this.Major == 0 && this.Minor == 0 && this.Patch == 0)
+ throw new FormatException($"{this} isn't a valid semantic version. At least one of the major, minor, and patch numbers must be more than zero.");
+ if (this.Tag != null)
+ {
+ if (this.Tag.Trim() == "")
+ throw new FormatException($"{this} isn't a valid semantic version. The tag cannot be a blank string (but may be omitted).");
+ if (!Regex.IsMatch(this.Tag, $"^{SemanticVersion.TagPattern}$", RegexOptions.IgnoreCase))
+ throw new FormatException($"{this} isn't a valid semantic version. The tag is invalid.");
+ }
+ }
}
}