Skip to content

Commit 84a12e1

Browse files
committed
Merge branch 'develop' into stable
2 parents dfff36e + e947381 commit 84a12e1

10 files changed

Lines changed: 108 additions & 20 deletions

File tree

build/common.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ repo. It imports the other MSBuild files as needed.
77
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
88
<PropertyGroup>
99
<!--set general build properties -->
10-
<Version>4.0.4</Version>
10+
<Version>4.0.5</Version>
1111
<Product>SMAPI</Product>
1212
<LangVersion>latest</LangVersion>
1313
<AssemblySearchPaths>$(AssemblySearchPaths);{GAC}</AssemblySearchPaths>

docs/release-notes.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
[README](README.md)
22

33
# Release notes
4+
## 4.0.5
5+
Released 06 April 2024 for Stardew Valley 1.6.0 or later.
6+
7+
* For players:
8+
* The installer now deletes obsolete files from very old SMAPI versions again.
9+
* The installer now deletes Error Handler automatically if it's at the default path.
10+
* Fixed mods sometimes not applying logic inside new buildings.
11+
* Minor optimizations.
12+
* Updated mod compatibility list.
13+
14+
* For mod authors:
15+
* Fixed world-changed events (e.g. `ObjectListChanged`) not working correctly inside freshly-constructed buildings.
16+
417
## 4.0.4
518
Released 29 March 2024 for Stardew Valley 1.6.0 or later.
619

src/SMAPI.Installer/InteractiveInstaller.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,30 @@ private IEnumerable<string> GetUninstallPaths(DirectoryInfo installDir, Director
5353
yield return GetInstallPath("smapi-internal");
5454
yield return GetInstallPath("steam_appid.txt");
5555

56+
// obsolete files
57+
yield return GetInstallPath("libgdiplus.dylib"); // before 3.13 (macOS only)
58+
yield return GetInstallPath(Path.Combine("Mods", ".cache")); // 1.3-1.4
59+
yield return GetInstallPath(Path.Combine("Mods", "ErrorHandler")); // before 4.0 (no longer needed)
60+
yield return GetInstallPath(Path.Combine("Mods", "TrainerMod")); // before 2.0 (renamed to ConsoleCommands)
61+
yield return GetInstallPath("Mono.Cecil.Rocks.dll"); // 1.3-1.8
62+
yield return GetInstallPath("StardewModdingAPI-settings.json"); // 1.0-1.4
63+
yield return GetInstallPath("StardewModdingAPI.AssemblyRewriters.dll"); // 1.3-2.5.5
64+
yield return GetInstallPath("0Harmony.dll"); // moved in 2.8
65+
yield return GetInstallPath("0Harmony.pdb"); // moved in 2.8
66+
yield return GetInstallPath("Mono.Cecil.dll"); // moved in 2.8
67+
yield return GetInstallPath("Newtonsoft.Json.dll"); // moved in 2.8
68+
yield return GetInstallPath("StardewModdingAPI.config.json"); // moved in 2.8
69+
yield return GetInstallPath("StardewModdingAPI.crash.marker"); // moved in 2.8
70+
yield return GetInstallPath("StardewModdingAPI.metadata.json"); // moved in 2.8
71+
yield return GetInstallPath("StardewModdingAPI.update.marker"); // moved in 2.8
72+
yield return GetInstallPath("StardewModdingAPI.Toolkit.dll"); // moved in 2.8
73+
yield return GetInstallPath("StardewModdingAPI.Toolkit.pdb"); // moved in 2.8
74+
yield return GetInstallPath("StardewModdingAPI.Toolkit.xml"); // moved in 2.8
75+
yield return GetInstallPath("StardewModdingAPI.Toolkit.CoreInterfaces.dll"); // moved in 2.8
76+
yield return GetInstallPath("StardewModdingAPI.Toolkit.CoreInterfaces.pdb"); // moved in 2.8
77+
yield return GetInstallPath("StardewModdingAPI.Toolkit.CoreInterfaces.xml"); // moved in 2.8
78+
yield return GetInstallPath("StardewModdingAPI-x64.exe"); // before 3.13
79+
5680
// old log files
5781
yield return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley", "ErrorLogs");
5882
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"Name": "Console Commands",
33
"Author": "SMAPI",
4-
"Version": "4.0.4",
4+
"Version": "4.0.5",
55
"Description": "Adds SMAPI console commands that let you manipulate the game.",
66
"UniqueID": "SMAPI.ConsoleCommands",
77
"EntryDll": "ConsoleCommands.dll",
8-
"MinimumApiVersion": "4.0.4"
8+
"MinimumApiVersion": "4.0.5"
99
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"Name": "Save Backup",
33
"Author": "SMAPI",
4-
"Version": "4.0.4",
4+
"Version": "4.0.5",
55
"Description": "Automatically backs up all your saves once per day into its folder.",
66
"UniqueID": "SMAPI.SaveBackup",
77
"EntryDll": "SaveBackup.dll",
8-
"MinimumApiVersion": "4.0.4"
8+
"MinimumApiVersion": "4.0.5"
99
}

src/SMAPI.Web/wwwroot/SMAPI.metadata.json

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,14 +208,19 @@
208208
},
209209
"Bulk Animal Purchase": {
210210
"ID": "aedenthorn.BulkAnimalPurchase",
211-
"~1.1.2 | Status": "AssumeBroken",
212-
"~1.1.2 | StatusReasonDetails": "Harmony patches fail at runtime"
211+
"~0.2.1 | Status": "AssumeBroken",
212+
"~0.2.1 | StatusReasonDetails": "Harmony patches fail at runtime"
213213
},
214214
"Build On Any Tile": {
215215
"ID": "Esca.BuildOnAnyTile",
216216
"~1.1.2 | Status": "AssumeBroken",
217217
"~1.1.2 | StatusReasonDetails": "Harmony patches fail at runtime"
218218
},
219+
"Carry Chest": {
220+
"ID": "spacechase0.CarryChest",
221+
"~1.3.6 | Status": "AssumeBroken",
222+
"~1.3.6 | StatusReasonDetails": "loses items when chest is placed"
223+
},
219224
"Categories in Recipes": {
220225
"ID": "Traktori.CategoriesInRecipes",
221226
"~1.0.0 | Status": "AssumeBroken",
@@ -256,10 +261,10 @@
256261
"~0.1.1 | Status": "AssumeBroken",
257262
"~0.1.1 | StatusReasonDetails": "Harmony patches fail at runtime"
258263
},
259-
"Enemy health Bars": {
264+
"Enemy Health Bars": {
260265
"ID": "Speeder.HealthBars",
261-
"~1.9.1 | Status": "AssumeBroken",
262-
"~1.9.1 | StatusReasonDetails": "causes runtime errors"
266+
"~1.9.1-unofficial.2-libraryaddict | Status": "AssumeBroken",
267+
"~1.9.1-unofficial.2-libraryaddict | StatusReasonDetails": "causes runtime errors"
263268
},
264269
"Extreme Weather": {
265270
"ID": "BlaDe.ExtremeWeather",

src/SMAPI/Constants.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ internal static class EarlyConstants
4949
internal static int? LogScreenId { get; set; }
5050

5151
/// <summary>SMAPI's current raw semantic version.</summary>
52-
internal static string RawApiVersion = "4.0.4";
52+
internal static string RawApiVersion = "4.0.5";
5353
}
5454

5555
/// <summary>Contains SMAPI's constants and assumptions.</summary>

src/SMAPI/Framework/StateTracking/ChestTracker.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ public void Update()
7474
public void Reset()
7575
{
7676
// update stack sizes
77-
foreach (Item item in this.StackSizes.Keys.ToArray().Concat(this.Added))
77+
foreach (Item item in this.StackSizes.Keys)
78+
this.StackSizes[item] = item.Stack;
79+
foreach (Item item in this.Added)
7880
this.StackSizes[item] = item.Stack;
7981

8082
// update watcher

src/SMAPI/Framework/StateTracking/Snapshots/WorldLocationsSnapshot.cs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System.Collections.Generic;
2-
using System.Linq;
32
using StardewModdingAPI.Framework.StateTracking.Comparers;
43
using StardewValley;
54

@@ -14,6 +13,9 @@ internal class WorldLocationsSnapshot
1413
/// <summary>A map of tracked locations.</summary>
1514
private readonly Dictionary<GameLocation, LocationSnapshot> LocationsDict = new(new ObjectReferenceComparer<GameLocation>());
1615

16+
/// <summary>The pooled list instance for <see cref="GetMissingLocations"/>.</summary>
17+
private static readonly List<GameLocation> PooledMissingLocations = new();
18+
1719

1820
/*********
1921
** Accessors
@@ -36,7 +38,7 @@ public void Update(WorldLocationsTracker watcher)
3638
this.LocationList.Update(watcher.IsLocationListChanged, watcher.Added, watcher.Removed);
3739

3840
// remove missing locations
39-
foreach (var key in this.LocationsDict.Keys.Where(key => !watcher.HasLocationTracker(key)).ToArray())
41+
foreach (var key in this.GetMissingLocations(watcher))
4042
this.LocationsDict.Remove(key);
4143

4244
// update locations
@@ -48,5 +50,26 @@ public void Update(WorldLocationsTracker watcher)
4850
snapshot.Update(locationWatcher);
4951
}
5052
}
53+
54+
55+
/*********
56+
** Private methods
57+
*********/
58+
/// <summary>Get the watched locations which no longer exist in the world, if any.</summary>
59+
/// <param name="watcher">The location list tracker.</param>
60+
private List<GameLocation> GetMissingLocations(WorldLocationsTracker watcher)
61+
{
62+
List<GameLocation> list = WorldLocationsSnapshot.PooledMissingLocations;
63+
if (list.Count > 0)
64+
list.Clear();
65+
66+
foreach (GameLocation location in this.LocationsDict.Keys)
67+
{
68+
if (!watcher.HasLocationTracker(location))
69+
list.Add(location);
70+
}
71+
72+
return list;
73+
}
5174
}
5275
}

src/SMAPI/Framework/StateTracking/WorldLocationsTracker.cs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ internal class WorldLocationsTracker : IWatcher
3030
/// <summary>A lookup of registered buildings and their indoor location.</summary>
3131
private readonly Dictionary<Building, GameLocation?> BuildingIndoors = new(new ObjectReferenceComparer<Building>());
3232

33+
/// <summary>The pooled list instance for <see cref="GetLocationsWhoseBuildingsChanged"/>.</summary>
34+
private static readonly List<LocationTracker> PooledLocationsWithBuildingsChanged = new();
35+
3336

3437
/*********
3538
** Accessors
@@ -95,21 +98,23 @@ public void Update()
9598
}
9699

97100
// detect building changed
98-
foreach (LocationTracker watcher in this.Locations.Where(p => p.BuildingsWatcher.IsChanged).ToArray())
101+
foreach (LocationTracker watcher in this.GetLocationsWhoseBuildingsChanged())
99102
{
100103
this.Remove(watcher.BuildingsWatcher.Removed);
101104
this.Add(watcher.BuildingsWatcher.Added);
102105
}
103106

104107
// detect building interiors changed (e.g. construction completed)
105-
foreach ((Building building, GameLocation? oldIndoors) in this.BuildingIndoors.Where(p => !object.Equals(p.Key.indoors.Value, p.Value)))
108+
foreach ((Building building, GameLocation? oldIndoors) in this.BuildingIndoors)
106109
{
107110
GameLocation? newIndoors = building.indoors.Value;
111+
if (object.ReferenceEquals(oldIndoors, newIndoors))
112+
continue;
113+
114+
this.Remove(oldIndoors);
115+
this.Add(newIndoors);
108116

109-
if (oldIndoors != null)
110-
this.Added.Add(oldIndoors);
111-
if (newIndoors != null)
112-
this.Removed.Add(newIndoors);
117+
this.BuildingIndoors[building] = newIndoors;
113118
}
114119
}
115120

@@ -259,5 +264,21 @@ private IEnumerable<IWatcher> GetWatchers()
259264
foreach (LocationTracker watcher in this.Locations)
260265
yield return watcher;
261266
}
267+
268+
/// <summary>Get the locations whose building list changed, if any.</summary>
269+
private List<LocationTracker> GetLocationsWhoseBuildingsChanged()
270+
{
271+
List<LocationTracker> list = WorldLocationsTracker.PooledLocationsWithBuildingsChanged;
272+
if (list.Count > 0)
273+
list.Clear();
274+
275+
foreach (LocationTracker watcher in this.LocationDict.Values)
276+
{
277+
if (watcher.IsChanged)
278+
list.Add(watcher);
279+
}
280+
281+
return list;
282+
}
262283
}
263284
}

0 commit comments

Comments
 (0)