Merge branch 'develop' into stable

This commit is contained in:
Jesse Plamondon-Willard
2024-04-06 19:58:10 -04:00
10 changed files with 108 additions and 20 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ repo. It imports the other MSBuild files as needed.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!--set general build properties -->
<Version>4.0.4</Version>
<Version>4.0.5</Version>
<Product>SMAPI</Product>
<LangVersion>latest</LangVersion>
<AssemblySearchPaths>$(AssemblySearchPaths);{GAC}</AssemblySearchPaths>
+13
View File
@@ -1,6 +1,19 @@
← [README](README.md)
# Release notes
## 4.0.5
Released 06 April 2024 for Stardew Valley 1.6.0 or later.
* For players:
* The installer now deletes obsolete files from very old SMAPI versions again.
* The installer now deletes Error Handler automatically if it's at the default path.
* Fixed mods sometimes not applying logic inside new buildings.
* Minor optimizations.
* Updated mod compatibility list.
* For mod authors:
* Fixed world-changed events (e.g. `ObjectListChanged`) not working correctly inside freshly-constructed buildings.
## 4.0.4
Released 29 March 2024 for Stardew Valley 1.6.0 or later.
@@ -53,6 +53,30 @@ namespace StardewModdingApi.Installer
yield return GetInstallPath("smapi-internal");
yield return GetInstallPath("steam_appid.txt");
// obsolete files
yield return GetInstallPath("libgdiplus.dylib"); // before 3.13 (macOS only)
yield return GetInstallPath(Path.Combine("Mods", ".cache")); // 1.3-1.4
yield return GetInstallPath(Path.Combine("Mods", "ErrorHandler")); // before 4.0 (no longer needed)
yield return GetInstallPath(Path.Combine("Mods", "TrainerMod")); // before 2.0 (renamed to ConsoleCommands)
yield return GetInstallPath("Mono.Cecil.Rocks.dll"); // 1.3-1.8
yield return GetInstallPath("StardewModdingAPI-settings.json"); // 1.0-1.4
yield return GetInstallPath("StardewModdingAPI.AssemblyRewriters.dll"); // 1.3-2.5.5
yield return GetInstallPath("0Harmony.dll"); // moved in 2.8
yield return GetInstallPath("0Harmony.pdb"); // moved in 2.8
yield return GetInstallPath("Mono.Cecil.dll"); // moved in 2.8
yield return GetInstallPath("Newtonsoft.Json.dll"); // moved in 2.8
yield return GetInstallPath("StardewModdingAPI.config.json"); // moved in 2.8
yield return GetInstallPath("StardewModdingAPI.crash.marker"); // moved in 2.8
yield return GetInstallPath("StardewModdingAPI.metadata.json"); // moved in 2.8
yield return GetInstallPath("StardewModdingAPI.update.marker"); // moved in 2.8
yield return GetInstallPath("StardewModdingAPI.Toolkit.dll"); // moved in 2.8
yield return GetInstallPath("StardewModdingAPI.Toolkit.pdb"); // moved in 2.8
yield return GetInstallPath("StardewModdingAPI.Toolkit.xml"); // moved in 2.8
yield return GetInstallPath("StardewModdingAPI.Toolkit.CoreInterfaces.dll"); // moved in 2.8
yield return GetInstallPath("StardewModdingAPI.Toolkit.CoreInterfaces.pdb"); // moved in 2.8
yield return GetInstallPath("StardewModdingAPI.Toolkit.CoreInterfaces.xml"); // moved in 2.8
yield return GetInstallPath("StardewModdingAPI-x64.exe"); // before 3.13
// old log files
yield return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley", "ErrorLogs");
}
+2 -2
View File
@@ -1,9 +1,9 @@
{
"Name": "Console Commands",
"Author": "SMAPI",
"Version": "4.0.4",
"Version": "4.0.5",
"Description": "Adds SMAPI console commands that let you manipulate the game.",
"UniqueID": "SMAPI.ConsoleCommands",
"EntryDll": "ConsoleCommands.dll",
"MinimumApiVersion": "4.0.4"
"MinimumApiVersion": "4.0.5"
}
+2 -2
View File
@@ -1,9 +1,9 @@
{
"Name": "Save Backup",
"Author": "SMAPI",
"Version": "4.0.4",
"Version": "4.0.5",
"Description": "Automatically backs up all your saves once per day into its folder.",
"UniqueID": "SMAPI.SaveBackup",
"EntryDll": "SaveBackup.dll",
"MinimumApiVersion": "4.0.4"
"MinimumApiVersion": "4.0.5"
}
+10 -5
View File
@@ -208,14 +208,19 @@
},
"Bulk Animal Purchase": {
"ID": "aedenthorn.BulkAnimalPurchase",
"~1.1.2 | Status": "AssumeBroken",
"~1.1.2 | StatusReasonDetails": "Harmony patches fail at runtime"
"~0.2.1 | Status": "AssumeBroken",
"~0.2.1 | StatusReasonDetails": "Harmony patches fail at runtime"
},
"Build On Any Tile": {
"ID": "Esca.BuildOnAnyTile",
"~1.1.2 | Status": "AssumeBroken",
"~1.1.2 | StatusReasonDetails": "Harmony patches fail at runtime"
},
"Carry Chest": {
"ID": "spacechase0.CarryChest",
"~1.3.6 | Status": "AssumeBroken",
"~1.3.6 | StatusReasonDetails": "loses items when chest is placed"
},
"Categories in Recipes": {
"ID": "Traktori.CategoriesInRecipes",
"~1.0.0 | Status": "AssumeBroken",
@@ -256,10 +261,10 @@
"~0.1.1 | Status": "AssumeBroken",
"~0.1.1 | StatusReasonDetails": "Harmony patches fail at runtime"
},
"Enemy health Bars": {
"Enemy Health Bars": {
"ID": "Speeder.HealthBars",
"~1.9.1 | Status": "AssumeBroken",
"~1.9.1 | StatusReasonDetails": "causes runtime errors"
"~1.9.1-unofficial.2-libraryaddict | Status": "AssumeBroken",
"~1.9.1-unofficial.2-libraryaddict | StatusReasonDetails": "causes runtime errors"
},
"Extreme Weather": {
"ID": "BlaDe.ExtremeWeather",
+1 -1
View File
@@ -49,7 +49,7 @@ namespace StardewModdingAPI
internal static int? LogScreenId { get; set; }
/// <summary>SMAPI's current raw semantic version.</summary>
internal static string RawApiVersion = "4.0.4";
internal static string RawApiVersion = "4.0.5";
}
/// <summary>Contains SMAPI's constants and assumptions.</summary>
@@ -74,7 +74,9 @@ namespace StardewModdingAPI.Framework.StateTracking
public void Reset()
{
// update stack sizes
foreach (Item item in this.StackSizes.Keys.ToArray().Concat(this.Added))
foreach (Item item in this.StackSizes.Keys)
this.StackSizes[item] = item.Stack;
foreach (Item item in this.Added)
this.StackSizes[item] = item.Stack;
// update watcher
@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using StardewModdingAPI.Framework.StateTracking.Comparers;
using StardewValley;
@@ -14,6 +13,9 @@ namespace StardewModdingAPI.Framework.StateTracking.Snapshots
/// <summary>A map of tracked locations.</summary>
private readonly Dictionary<GameLocation, LocationSnapshot> LocationsDict = new(new ObjectReferenceComparer<GameLocation>());
/// <summary>The pooled list instance for <see cref="GetMissingLocations"/>.</summary>
private static readonly List<GameLocation> PooledMissingLocations = new();
/*********
** Accessors
@@ -36,7 +38,7 @@ namespace StardewModdingAPI.Framework.StateTracking.Snapshots
this.LocationList.Update(watcher.IsLocationListChanged, watcher.Added, watcher.Removed);
// remove missing locations
foreach (var key in this.LocationsDict.Keys.Where(key => !watcher.HasLocationTracker(key)).ToArray())
foreach (var key in this.GetMissingLocations(watcher))
this.LocationsDict.Remove(key);
// update locations
@@ -48,5 +50,26 @@ namespace StardewModdingAPI.Framework.StateTracking.Snapshots
snapshot.Update(locationWatcher);
}
}
/*********
** Private methods
*********/
/// <summary>Get the watched locations which no longer exist in the world, if any.</summary>
/// <param name="watcher">The location list tracker.</param>
private List<GameLocation> GetMissingLocations(WorldLocationsTracker watcher)
{
List<GameLocation> list = WorldLocationsSnapshot.PooledMissingLocations;
if (list.Count > 0)
list.Clear();
foreach (GameLocation location in this.LocationsDict.Keys)
{
if (!watcher.HasLocationTracker(location))
list.Add(location);
}
return list;
}
}
}
@@ -30,6 +30,9 @@ namespace StardewModdingAPI.Framework.StateTracking
/// <summary>A lookup of registered buildings and their indoor location.</summary>
private readonly Dictionary<Building, GameLocation?> BuildingIndoors = new(new ObjectReferenceComparer<Building>());
/// <summary>The pooled list instance for <see cref="GetLocationsWhoseBuildingsChanged"/>.</summary>
private static readonly List<LocationTracker> PooledLocationsWithBuildingsChanged = new();
/*********
** Accessors
@@ -95,21 +98,23 @@ namespace StardewModdingAPI.Framework.StateTracking
}
// detect building changed
foreach (LocationTracker watcher in this.Locations.Where(p => p.BuildingsWatcher.IsChanged).ToArray())
foreach (LocationTracker watcher in this.GetLocationsWhoseBuildingsChanged())
{
this.Remove(watcher.BuildingsWatcher.Removed);
this.Add(watcher.BuildingsWatcher.Added);
}
// detect building interiors changed (e.g. construction completed)
foreach ((Building building, GameLocation? oldIndoors) in this.BuildingIndoors.Where(p => !object.Equals(p.Key.indoors.Value, p.Value)))
foreach ((Building building, GameLocation? oldIndoors) in this.BuildingIndoors)
{
GameLocation? newIndoors = building.indoors.Value;
if (object.ReferenceEquals(oldIndoors, newIndoors))
continue;
if (oldIndoors != null)
this.Added.Add(oldIndoors);
if (newIndoors != null)
this.Removed.Add(newIndoors);
this.Remove(oldIndoors);
this.Add(newIndoors);
this.BuildingIndoors[building] = newIndoors;
}
}
@@ -259,5 +264,21 @@ namespace StardewModdingAPI.Framework.StateTracking
foreach (LocationTracker watcher in this.Locations)
yield return watcher;
}
/// <summary>Get the locations whose building list changed, if any.</summary>
private List<LocationTracker> GetLocationsWhoseBuildingsChanged()
{
List<LocationTracker> list = WorldLocationsTracker.PooledLocationsWithBuildingsChanged;
if (list.Count > 0)
list.Clear();
foreach (LocationTracker watcher in this.LocationDict.Values)
{
if (watcher.IsChanged)
list.Add(watcher);
}
return list;
}
}
}