summaryrefslogtreecommitdiff
path: root/src/SMAPI
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2021-03-19 20:16:13 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2021-03-19 20:16:13 -0400
commitc39b2b17663f79da92f3d0abe8c01ea73187cbab (patch)
tree4a69039c37ade2caff5cc98a8a5b9b4c4247579b /src/SMAPI
parentbb88e42f54c274db3c382eecb54b541dd2599163 (diff)
downloadSMAPI-c39b2b17663f79da92f3d0abe8c01ea73187cbab.tar.gz
SMAPI-c39b2b17663f79da92f3d0abe8c01ea73187cbab.tar.bz2
SMAPI-c39b2b17663f79da92f3d0abe8c01ea73187cbab.zip
update NPC pathfinding cache when map warps change
Diffstat (limited to 'src/SMAPI')
-rw-r--r--src/SMAPI/Framework/ContentCoordinator.cs31
-rw-r--r--src/SMAPI/Framework/SCore.cs1
-rw-r--r--src/SMAPI/Metadata/CoreAssetPropagator.cs38
3 files changed, 56 insertions, 14 deletions
diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs
index 5d4855ef..2920e670 100644
--- a/src/SMAPI/Framework/ContentCoordinator.cs
+++ b/src/SMAPI/Framework/ContentCoordinator.cs
@@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
+using System.Text;
using System.Threading;
using Microsoft.Xna.Framework.Content;
using StardewModdingAPI.Framework.Content;
@@ -341,13 +342,31 @@ namespace StardewModdingAPI.Framework
// reload core game assets
if (removedAssets.Any())
{
- IDictionary<string, bool> propagated = this.CoreAssets.Propagate(removedAssets.ToDictionary(p => p.Key, p => p.Value), ignoreWorld: Context.IsWorldFullyUnloaded);
-
- string[] invalidatedKeys = removedAssets.Keys.ToArray();
- string[] propagatedKeys = propagated.Where(p => p.Value).Select(p => p.Key).ToArray();
+ // propagate changes to the game
+ this.CoreAssets.Propagate(
+ assets: removedAssets.ToDictionary(p => p.Key, p => p.Value),
+ ignoreWorld: Context.IsWorldFullyUnloaded,
+ out IDictionary<string, bool> propagated,
+ out bool updatedNpcWarps
+ );
- string FormatKeyList(IEnumerable<string> keys) => string.Join(", ", keys.OrderBy(p => p, StringComparer.OrdinalIgnoreCase));
- this.Monitor.Log($"Invalidated {invalidatedKeys.Length} asset names ({FormatKeyList(invalidatedKeys)}); propagated {propagatedKeys.Length} core assets ({FormatKeyList(propagatedKeys)}).");
+ // log summary
+ StringBuilder report = new StringBuilder();
+ {
+ string[] invalidatedKeys = removedAssets.Keys.ToArray();
+ string[] propagatedKeys = propagated.Where(p => p.Value).Select(p => p.Key).ToArray();
+
+ string FormatKeyList(IEnumerable<string> keys) => string.Join(", ", keys.OrderBy(p => p, StringComparer.OrdinalIgnoreCase));
+
+ report.AppendLine($"Invalidated {invalidatedKeys.Length} asset names ({FormatKeyList(invalidatedKeys)}).");
+ report.AppendLine(propagated.Count > 0
+ ? $"Propagated {propagatedKeys.Length} core assets ({FormatKeyList(propagatedKeys)})."
+ : "Propagated 0 core assets."
+ );
+ if (updatedNpcWarps)
+ report.AppendLine("Updated NPC pathfinding cache.");
+ }
+ this.Monitor.Log(report.ToString().TrimEnd());
}
else
this.Monitor.Log("Invalidated 0 cache entries.");
diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs
index 5df4b61b..e98dc04c 100644
--- a/src/SMAPI/Framework/SCore.cs
+++ b/src/SMAPI/Framework/SCore.cs
@@ -482,6 +482,7 @@ namespace StardewModdingAPI.Framework
+ ")"
)
)
+ + "."
);
// reload affected assets
diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs
index debbaffd..52da3946 100644
--- a/src/SMAPI/Metadata/CoreAssetPropagator.cs
+++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs
@@ -80,8 +80,9 @@ namespace StardewModdingAPI.Metadata
/// <summary>Reload one of the game's core assets (if applicable).</summary>
/// <param name="assets">The asset keys and types to reload.</param>
/// <param name="ignoreWorld">Whether the in-game world is fully unloaded (e.g. on the title screen), so there's no need to propagate changes into the world.</param>
- /// <returns>Returns a lookup of asset names to whether they've been propagated.</returns>
- public IDictionary<string, bool> Propagate(IDictionary<string, Type> assets, bool ignoreWorld)
+ /// <param name="propagatedAssets">A lookup of asset names to whether they've been propagated.</param>
+ /// <param name="updatedNpcWarps">Whether the NPC pathfinding cache was reloaded.</param>
+ public void Propagate(IDictionary<string, Type> assets, bool ignoreWorld, out IDictionary<string, bool> propagatedAssets, out bool updatedNpcWarps)
{
// group into optimized lists
var buckets = assets.GroupBy(p =>
@@ -96,28 +97,36 @@ namespace StardewModdingAPI.Metadata
});
// reload assets
- IDictionary<string, bool> propagated = assets.ToDictionary(p => p.Key, _ => false, StringComparer.OrdinalIgnoreCase);
+ propagatedAssets = assets.ToDictionary(p => p.Key, _ => false, StringComparer.OrdinalIgnoreCase);
+ updatedNpcWarps = false;
foreach (var bucket in buckets)
{
switch (bucket.Key)
{
case AssetBucket.Sprite:
if (!ignoreWorld)
- this.ReloadNpcSprites(bucket.Select(p => p.Key), propagated);
+ this.ReloadNpcSprites(bucket.Select(p => p.Key), propagatedAssets);
break;
case AssetBucket.Portrait:
if (!ignoreWorld)
- this.ReloadNpcPortraits(bucket.Select(p => p.Key), propagated);
+ this.ReloadNpcPortraits(bucket.Select(p => p.Key), propagatedAssets);
break;
default:
foreach (var entry in bucket)
- propagated[entry.Key] = this.PropagateOther(entry.Key, entry.Value, ignoreWorld);
+ {
+ bool changed = this.PropagateOther(entry.Key, entry.Value, ignoreWorld, out bool curChangedMapWarps);
+ propagatedAssets[entry.Key] = changed;
+ updatedNpcWarps = updatedNpcWarps || curChangedMapWarps;
+ }
break;
}
}
- return propagated;
+
+ // reload NPC pathfinding cache if any map changed
+ if (updatedNpcWarps)
+ NPC.populateRoutesFromLocationToLocationList();
}
@@ -128,12 +137,14 @@ namespace StardewModdingAPI.Metadata
/// <param name="key">The asset key to reload.</param>
/// <param name="type">The asset type to reload.</param>
/// <param name="ignoreWorld">Whether the in-game world is fully unloaded (e.g. on the title screen), so there's no need to propagate changes into the world.</param>
+ /// <param name="changedWarps">Whether any map warps were changed as part of this propagation.</param>
/// <returns>Returns whether an asset was loaded. The return value may be true or false, or a non-null value for true.</returns>
[SuppressMessage("ReSharper", "StringLiteralTypo", Justification = "These deliberately match the asset names.")]
- private bool PropagateOther(string key, Type type, bool ignoreWorld)
+ private bool PropagateOther(string key, Type type, bool ignoreWorld, out bool changedWarps)
{
var content = this.MainContentManager;
key = this.AssertAndNormalizeAssetName(key);
+ changedWarps = false;
/****
** Special case: current map tilesheet
@@ -162,7 +173,18 @@ namespace StardewModdingAPI.Metadata
{
if (!string.IsNullOrWhiteSpace(location.mapPath.Value) && this.NormalizeAssetNameIgnoringEmpty(location.mapPath.Value) == key)
{
+ static ISet<string> GetWarpSet(GameLocation location)
+ {
+ return new HashSet<string>(
+ location.warps.Select(p => $"{p.X} {p.Y} {p.TargetName} {p.TargetX} {p.TargetY}")
+ );
+ }
+
+ var oldWarps = GetWarpSet(location);
this.ReloadMap(location);
+ var newWarps = GetWarpSet(location);
+
+ changedWarps = changedWarps || oldWarps.Count != newWarps.Count || oldWarps.Any(p => !newWarps.Contains(p));
anyChanged = true;
}
}