summaryrefslogtreecommitdiff
path: root/src/SMAPI/Metadata/CoreAssetPropagator.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI/Metadata/CoreAssetPropagator.cs')
-rw-r--r--src/SMAPI/Metadata/CoreAssetPropagator.cs261
1 files changed, 110 insertions, 151 deletions
diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs
index a6c4bb24..e7fac578 100644
--- a/src/SMAPI/Metadata/CoreAssetPropagator.cs
+++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs
@@ -87,22 +87,22 @@ namespace StardewModdingAPI.Metadata
/// <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="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)
+ public void Propagate(IDictionary<IAssetName, Type> assets, bool ignoreWorld, out IDictionary<IAssetName, bool> propagatedAssets, out bool updatedNpcWarps)
{
// group into optimized lists
var buckets = assets.GroupBy(p =>
{
- if (this.IsInFolder(p.Key, "Characters") || this.IsInFolder(p.Key, "Characters/Monsters"))
+ if (p.Key.IsDirectlyUnderPath("Characters") || p.Key.IsDirectlyUnderPath("Characters/Monsters"))
return AssetBucket.Sprite;
- if (this.IsInFolder(p.Key, "Portraits"))
+ if (p.Key.IsDirectlyUnderPath("Portraits"))
return AssetBucket.Portrait;
return AssetBucket.Other;
});
// reload assets
- propagatedAssets = assets.ToDictionary(p => p.Key, _ => false, StringComparer.OrdinalIgnoreCase);
+ propagatedAssets = assets.ToDictionary(p => p.Key, _ => false);
updatedNpcWarps = false;
foreach (var bucket in buckets)
{
@@ -149,16 +149,16 @@ namespace StardewModdingAPI.Metadata
** Private methods
*********/
/// <summary>Reload one of the game's core assets (if applicable).</summary>
- /// <param name="key">The asset key to reload.</param>
+ /// <param name="assetName">The asset name 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, out bool changedWarps)
+ private bool PropagateOther(IAssetName assetName, Type type, bool ignoreWorld, out bool changedWarps)
{
var content = this.MainContentManager;
- key = this.AssertAndNormalizeAssetName(key);
+ string key = assetName.Name;
changedWarps = false;
/****
@@ -170,7 +170,7 @@ namespace StardewModdingAPI.Metadata
{
foreach (TileSheet tilesheet in Game1.currentLocation.map.TileSheets)
{
- if (this.IsSameAssetKey(tilesheet.ImageSource, key))
+ if (assetName.IsEquivalentTo(tilesheet.ImageSource))
Game1.mapDisplayDevice.LoadTileSheet(tilesheet);
}
}
@@ -188,7 +188,7 @@ namespace StardewModdingAPI.Metadata
{
GameLocation location = info.Location;
- if (this.IsSameAssetKey(location.mapPath.Value, key))
+ if (assetName.IsEquivalentTo(location.mapPath.Value))
{
static ISet<string> GetWarpSet(GameLocation location)
{
@@ -213,14 +213,13 @@ namespace StardewModdingAPI.Metadata
/****
** Propagate by key
****/
- Reflector reflection = this.Reflection;
- switch (key.ToLower().Replace("\\", "/")) // normalized key so we can compare statically
+ switch (assetName.Name.ToLower().Replace("\\", "/")) // normalized key so we can compare statically
{
/****
** Animals
****/
case "animals/horse":
- return !ignoreWorld && this.ReloadPetOrHorseSprites<Horse>(content, key);
+ return !ignoreWorld && this.ReloadPetOrHorseSprites<Horse>(content, assetName);
/****
** Buildings
@@ -231,7 +230,7 @@ namespace StardewModdingAPI.Metadata
case "buildings/houses_paintmask": // Farm
{
- bool removedFromCache = this.RemoveFromPaintMaskCache(key);
+ bool removedFromCache = this.RemoveFromPaintMaskCache(assetName);
Farm farm = Game1.getFarm();
farm?.ApplyHousePaint();
@@ -250,7 +249,7 @@ namespace StardewModdingAPI.Metadata
case "characters/farmer/farmer_base_bald":
case "characters/farmer/farmer_girl_base":
case "characters/farmer/farmer_girl_base_bald":
- return !ignoreWorld && this.ReloadPlayerSprites(key);
+ return !ignoreWorld && this.ReloadPlayerSprites(assetName);
case "characters/farmer/hairstyles": // Game1.LoadContent
FarmerRenderer.hairStylesTexture = this.LoadAndDisposeIfNeeded(FarmerRenderer.hairStylesTexture, key);
@@ -313,7 +312,7 @@ namespace StardewModdingAPI.Metadata
return true;
case "data/npcdispositions": // NPC constructor
- return !ignoreWorld && this.ReloadNpcDispositions(content, key);
+ return !ignoreWorld && this.ReloadNpcDispositions(content, assetName);
case "data/npcgifttastes": // Game1.LoadContent
Game1.NPCGiftTastes = content.Load<Dictionary<string, string>>(key);
@@ -393,7 +392,7 @@ namespace StardewModdingAPI.Metadata
}
if (!ignoreWorld)
- this.ReloadDoorSprites(content, key);
+ this.ReloadDoorSprites(content, assetName);
return true;
case "loosesprites/cursors2": // Game1.LoadContent
@@ -425,7 +424,7 @@ namespace StardewModdingAPI.Metadata
return true;
case "loosesprites/suspensionbridge": // SuspensionBridge constructor
- return !ignoreWorld && this.ReloadSuspensionBridges(content, key);
+ return !ignoreWorld && this.ReloadSuspensionBridges(content, assetName);
/****
** Content\Maps
@@ -456,7 +455,7 @@ namespace StardewModdingAPI.Metadata
return false;
case "minigames/titlebuttons": // TitleMenu
- return this.ReloadTitleButtons(content, key);
+ return this.ReloadTitleButtons(content, assetName);
/****
** Content\Strings
@@ -480,14 +479,14 @@ namespace StardewModdingAPI.Metadata
return true;
case "tilesheets/chairtiles": // Game1.LoadContent
- return this.ReloadChairTiles(content, key, ignoreWorld);
+ return this.ReloadChairTiles(content, assetName, ignoreWorld);
case "tilesheets/craftables": // Game1.LoadContent
Game1.bigCraftableSpriteSheet = content.Load<Texture2D>(key);
return true;
case "tilesheets/critters": // Critter constructor
- return !ignoreWorld && this.ReloadCritterTextures(content, key) > 0;
+ return !ignoreWorld && this.ReloadCritterTextures(content, assetName) > 0;
case "tilesheets/crops": // Game1.LoadContent
Game1.cropSpriteSheet = content.Load<Texture2D>(key);
@@ -541,7 +540,7 @@ namespace StardewModdingAPI.Metadata
return true;
case "terrainfeatures/grass": // from Grass
- return !ignoreWorld && this.ReloadGrassTextures(content, key);
+ return !ignoreWorld && this.ReloadGrassTextures(content, assetName);
case "terrainfeatures/hoedirt": // from HoeDirt
HoeDirt.lightTexture = content.Load<Texture2D>(key);
@@ -556,27 +555,27 @@ namespace StardewModdingAPI.Metadata
return true;
case "terrainfeatures/mushroom_tree": // from Tree
- return !ignoreWorld && this.ReloadTreeTextures(content, key, Tree.mushroomTree);
+ return !ignoreWorld && this.ReloadTreeTextures(content, assetName, Tree.mushroomTree);
case "terrainfeatures/tree_palm": // from Tree
- return !ignoreWorld && this.ReloadTreeTextures(content, key, Tree.palmTree);
+ return !ignoreWorld && this.ReloadTreeTextures(content, assetName, Tree.palmTree);
case "terrainfeatures/tree1_fall": // from Tree
case "terrainfeatures/tree1_spring": // from Tree
case "terrainfeatures/tree1_summer": // from Tree
case "terrainfeatures/tree1_winter": // from Tree
- return !ignoreWorld && this.ReloadTreeTextures(content, key, Tree.bushyTree);
+ return !ignoreWorld && this.ReloadTreeTextures(content, assetName, Tree.bushyTree);
case "terrainfeatures/tree2_fall": // from Tree
case "terrainfeatures/tree2_spring": // from Tree
case "terrainfeatures/tree2_summer": // from Tree
case "terrainfeatures/tree2_winter": // from Tree
- return !ignoreWorld && this.ReloadTreeTextures(content, key, Tree.leafyTree);
+ return !ignoreWorld && this.ReloadTreeTextures(content, assetName, Tree.leafyTree);
case "terrainfeatures/tree3_fall": // from Tree
case "terrainfeatures/tree3_spring": // from Tree
case "terrainfeatures/tree3_winter": // from Tree
- return !ignoreWorld && this.ReloadTreeTextures(content, key, Tree.pineTree);
+ return !ignoreWorld && this.ReloadTreeTextures(content, assetName, Tree.pineTree);
}
/****
@@ -585,25 +584,25 @@ namespace StardewModdingAPI.Metadata
if (!ignoreWorld)
{
// dynamic textures
- if (this.KeyStartsWith(key, "animals/cat"))
- return this.ReloadPetOrHorseSprites<Cat>(content, key);
- if (this.KeyStartsWith(key, "animals/dog"))
- return this.ReloadPetOrHorseSprites<Dog>(content, key);
- if (this.IsInFolder(key, "Animals"))
- return this.ReloadFarmAnimalSprites(content, key);
+ if (assetName.StartsWith("animals/cat"))
+ return this.ReloadPetOrHorseSprites<Cat>(content, assetName);
+ if (assetName.StartsWith("animals/dog"))
+ return this.ReloadPetOrHorseSprites<Dog>(content, assetName);
+ if (assetName.IsDirectlyUnderPath("Animals"))
+ return this.ReloadFarmAnimalSprites(content, assetName);
- if (this.IsInFolder(key, "Buildings"))
- return this.ReloadBuildings(key);
+ if (assetName.IsDirectlyUnderPath("Buildings"))
+ return this.ReloadBuildings(assetName);
- if (this.KeyStartsWith(key, "LooseSprites/Fence"))
- return this.ReloadFenceTextures(key);
+ if (assetName.StartsWith("LooseSprites/Fence"))
+ return this.ReloadFenceTextures(assetName);
// dynamic data
- if (this.IsInFolder(key, "Characters/Dialogue"))
- return this.ReloadNpcDialogue(key);
+ if (assetName.IsDirectlyUnderPath("Characters/Dialogue"))
+ return this.ReloadNpcDialogue(assetName);
- if (this.IsInFolder(key, "Characters/schedules"))
- return this.ReloadNpcSchedules(key);
+ if (assetName.IsDirectlyUnderPath("Characters/schedules"))
+ return this.ReloadNpcSchedules(assetName);
}
return false;
@@ -618,14 +617,14 @@ namespace StardewModdingAPI.Metadata
****/
/// <summary>Reload buttons on the title screen.</summary>
/// <param name="content">The content manager through which to reload the asset.</param>
- /// <param name="key">The asset key to reload.</param>
+ /// <param name="assetName">The asset name to reload.</param>
/// <returns>Returns whether any textures were reloaded.</returns>
/// <remarks>Derived from the <see cref="TitleMenu"/> constructor and <see cref="TitleMenu.setUpIcons"/>.</remarks>
- private bool ReloadTitleButtons(LocalizedContentManager content, string key)
+ private bool ReloadTitleButtons(LocalizedContentManager content, IAssetName assetName)
{
if (Game1.activeClickableMenu is TitleMenu titleMenu)
{
- Texture2D texture = content.Load<Texture2D>(key);
+ Texture2D texture = content.Load<Texture2D>(assetName.Name);
titleMenu.titleButtonsTexture = texture;
titleMenu.backButton.texture = texture;
@@ -645,21 +644,21 @@ namespace StardewModdingAPI.Metadata
/// <summary>Reload the sprites for matching pets or horses.</summary>
/// <typeparam name="TAnimal">The animal type.</typeparam>
/// <param name="content">The content manager through which to reload the asset.</param>
- /// <param name="key">The asset key to reload.</param>
+ /// <param name="assetName">The asset name to reload.</param>
/// <returns>Returns whether any textures were reloaded.</returns>
- private bool ReloadPetOrHorseSprites<TAnimal>(LocalizedContentManager content, string key)
+ private bool ReloadPetOrHorseSprites<TAnimal>(LocalizedContentManager content, IAssetName assetName)
where TAnimal : NPC
{
// find matches
TAnimal[] animals = this.GetCharacters()
.OfType<TAnimal>()
- .Where(p => this.IsSameAssetKey(p.Sprite?.Texture?.Name, key))
+ .Where(p => assetName.IsEquivalentTo(p.Sprite?.Texture?.Name))
.ToArray();
if (!animals.Any())
return false;
// update sprites
- Texture2D texture = content.Load<Texture2D>(key);
+ Texture2D texture = content.Load<Texture2D>(assetName.Name);
foreach (TAnimal animal in animals)
animal.Sprite.spriteTexture = texture;
return true;
@@ -667,10 +666,10 @@ namespace StardewModdingAPI.Metadata
/// <summary>Reload the sprites for matching farm animals.</summary>
/// <param name="content">The content manager through which to reload the asset.</param>
- /// <param name="key">The asset key to reload.</param>
+ /// <param name="assetName">The asset name to reload.</param>
/// <returns>Returns whether any textures were reloaded.</returns>
/// <remarks>Derived from <see cref="FarmAnimal.reload"/>.</remarks>
- private bool ReloadFarmAnimalSprites(LocalizedContentManager content, string key)
+ private bool ReloadFarmAnimalSprites(LocalizedContentManager content, IAssetName assetName)
{
// find matches
FarmAnimal[] animals = this.GetFarmAnimals().ToArray();
@@ -678,7 +677,7 @@ namespace StardewModdingAPI.Metadata
return false;
// update sprites
- Lazy<Texture2D> texture = new Lazy<Texture2D>(() => content.Load<Texture2D>(key));
+ Lazy<Texture2D> texture = new Lazy<Texture2D>(() => content.Load<Texture2D>(assetName.Name));
foreach (FarmAnimal animal in animals)
{
// get expected key
@@ -690,23 +689,23 @@ namespace StardewModdingAPI.Metadata
expectedKey = $"Animals/{expectedKey}";
// reload asset
- if (this.IsSameAssetKey(expectedKey, key))
+ if (assetName.IsEquivalentTo(expectedKey))
animal.Sprite.spriteTexture = texture.Value;
}
return texture.IsValueCreated;
}
/// <summary>Reload building textures.</summary>
- /// <param name="key">The asset key to reload.</param>
+ /// <param name="assetName">The asset name to reload.</param>
/// <returns>Returns whether any textures were reloaded.</returns>
- private bool ReloadBuildings(string key)
+ private bool ReloadBuildings(IAssetName assetName)
{
// get paint mask info
const string paintMaskSuffix = "_PaintMask";
- bool isPaintMask = key.EndsWith(paintMaskSuffix, StringComparison.OrdinalIgnoreCase);
+ bool isPaintMask = assetName.BaseName.EndsWith(paintMaskSuffix, StringComparison.OrdinalIgnoreCase);
// get building type
- string type = Path.GetFileName(key);
+ string type = Path.GetFileName(assetName.Name)!;
if (isPaintMask)
type = type.Substring(0, type.Length - paintMaskSuffix.Length);
@@ -718,7 +717,7 @@ namespace StardewModdingAPI.Metadata
.ToArray();
// remove from paint mask cache
- bool removedFromCache = this.RemoveFromPaintMaskCache(key);
+ bool removedFromCache = this.RemoveFromPaintMaskCache(assetName);
// reload textures
if (buildings.Any())
@@ -734,12 +733,12 @@ namespace StardewModdingAPI.Metadata
/// <summary>Reload map seat textures.</summary>
/// <param name="content">The content manager through which to reload the asset.</param>
- /// <param name="key">The asset key to reload.</param>
+ /// <param name="assetName">The asset name 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 whether any textures were reloaded.</returns>
- private bool ReloadChairTiles(LocalizedContentManager content, string key, bool ignoreWorld)
+ private bool ReloadChairTiles(LocalizedContentManager content, IAssetName assetName, bool ignoreWorld)
{
- MapSeat.mapChairTexture = content.Load<Texture2D>(key);
+ MapSeat.mapChairTexture = content.Load<Texture2D>(assetName.Name);
if (!ignoreWorld)
{
@@ -747,7 +746,7 @@ namespace StardewModdingAPI.Metadata
{
foreach (MapSeat seat in location.mapSeats.Where(p => p != null))
{
- if (this.IsSameAssetKey(seat._loadedTextureFile, key))
+ if (assetName.IsEquivalentTo(seat._loadedTextureFile))
seat.overlayTexture = MapSeat.mapChairTexture;
}
}
@@ -758,9 +757,9 @@ namespace StardewModdingAPI.Metadata
/// <summary>Reload critter textures.</summary>
/// <param name="content">The content manager through which to reload the asset.</param>
- /// <param name="key">The asset key to reload.</param>
+ /// <param name="assetName">The asset name to reload.</param>
/// <returns>Returns the number of reloaded assets.</returns>
- private int ReloadCritterTextures(LocalizedContentManager content, string key)
+ private int ReloadCritterTextures(LocalizedContentManager content, IAssetName assetName)
{
// get critters
Critter[] critters =
@@ -768,7 +767,7 @@ namespace StardewModdingAPI.Metadata
from location in this.GetLocations()
where location.critters != null
from Critter critter in location.critters
- where this.IsSameAssetKey(critter.sprite?.Texture?.Name, key)
+ where assetName.IsEquivalentTo(critter.sprite?.Texture?.Name)
select critter
)
.ToArray();
@@ -776,7 +775,7 @@ namespace StardewModdingAPI.Metadata
return 0;
// update sprites
- Texture2D texture = content.Load<Texture2D>(key);
+ Texture2D texture = content.Load<Texture2D>(assetName.Name);
foreach (var entry in critters)
entry.sprite.spriteTexture = texture;
@@ -785,11 +784,11 @@ namespace StardewModdingAPI.Metadata
/// <summary>Reload the sprites for interior doors.</summary>
/// <param name="content">The content manager through which to reload the asset.</param>
- /// <param name="key">The asset key to reload.</param>
+ /// <param name="assetName">The asset name to reload.</param>
/// <returns>Returns whether any doors were affected.</returns>
- private bool ReloadDoorSprites(LocalizedContentManager content, string key)
+ private bool ReloadDoorSprites(LocalizedContentManager content, IAssetName assetName)
{
- Lazy<Texture2D> texture = new Lazy<Texture2D>(() => content.Load<Texture2D>(key));
+ Lazy<Texture2D> texture = new Lazy<Texture2D>(() => content.Load<Texture2D>(assetName.Name));
foreach (GameLocation location in this.GetLocations())
{
@@ -803,7 +802,7 @@ namespace StardewModdingAPI.Metadata
continue;
string curKey = this.Reflection.GetField<string>(door.Sprite, "textureName").GetValue();
- if (this.IsSameAssetKey(curKey, key))
+ if (assetName.IsEquivalentTo(curKey))
door.Sprite.texture = texture.Value;
}
}
@@ -827,12 +826,12 @@ namespace StardewModdingAPI.Metadata
}
/// <summary>Reload the sprites for a fence type.</summary>
- /// <param name="key">The asset key to reload.</param>
+ /// <param name="assetName">The asset name to reload.</param>
/// <returns>Returns whether any textures were reloaded.</returns>
- private bool ReloadFenceTextures(string key)
+ private bool ReloadFenceTextures(IAssetName assetName)
{
- // get fence type
- if (!int.TryParse(this.GetSegments(key)[1].Substring("Fence".Length), out int fenceType))
+ // get fence type (e.g. LooseSprites/Fence3 => 3)
+ if (!int.TryParse(this.GetSegments(assetName.BaseName)[1].Substring("Fence".Length), out int fenceType))
return false;
// get fences
@@ -855,22 +854,22 @@ namespace StardewModdingAPI.Metadata
/// <summary>Reload tree textures.</summary>
/// <param name="content">The content manager through which to reload the asset.</param>
- /// <param name="key">The asset key to reload.</param>
+ /// <param name="assetName">The asset name to reload.</param>
/// <returns>Returns whether any textures were reloaded.</returns>
- private bool ReloadGrassTextures(LocalizedContentManager content, string key)
+ private bool ReloadGrassTextures(LocalizedContentManager content, IAssetName assetName)
{
Grass[] grasses =
(
from location in this.GetLocations()
from grass in location.terrainFeatures.Values.OfType<Grass>()
- where this.IsSameAssetKey(grass.textureName(), key)
+ where assetName.IsEquivalentTo(grass.textureName())
select grass
)
.ToArray();
if (grasses.Any())
{
- Lazy<Texture2D> texture = new Lazy<Texture2D>(() => content.Load<Texture2D>(key));
+ Lazy<Texture2D> texture = new Lazy<Texture2D>(() => content.Load<Texture2D>(assetName.Name));
foreach (Grass grass in grasses)
grass.texture = texture;
return true;
@@ -932,11 +931,11 @@ namespace StardewModdingAPI.Metadata
/// <summary>Reload the disposition data for matching NPCs.</summary>
/// <param name="content">The content manager through which to reload the asset.</param>
- /// <param name="key">The asset key to reload.</param>
+ /// <param name="assetName">The asset name to reload.</param>
/// <returns>Returns whether any NPCs were affected.</returns>
- private bool ReloadNpcDispositions(LocalizedContentManager content, string key)
+ private bool ReloadNpcDispositions(LocalizedContentManager content, IAssetName assetName)
{
- IDictionary<string, string> data = content.Load<Dictionary<string, string>>(key);
+ IDictionary<string, string> data = content.Load<Dictionary<string, string>>(assetName.Name);
bool changed = false;
foreach (NPC npc in this.GetCharacters())
{
@@ -953,16 +952,16 @@ namespace StardewModdingAPI.Metadata
/// <summary>Reload the sprites for matching NPCs.</summary>
/// <param name="keys">The asset keys to reload.</param>
/// <param name="propagated">The asset keys which have been propagated.</param>
- private void ReloadNpcSprites(IEnumerable<string> keys, IDictionary<string, bool> propagated)
+ private void ReloadNpcSprites(IEnumerable<IAssetName> keys, IDictionary<IAssetName, bool> propagated)
{
// get NPCs
- HashSet<string> lookup = new HashSet<string>(keys, StringComparer.OrdinalIgnoreCase);
+ IDictionary<string, IAssetName> lookup = keys.ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase);
var characters =
(
from npc in this.GetCharacters()
let key = this.NormalizeAssetNameIgnoringEmpty(npc.Sprite?.Texture?.Name)
- where key != null && lookup.Contains(key)
- select new { Npc = npc, Key = key }
+ where key != null && lookup.ContainsKey(key)
+ select new { Npc = npc, AssetName = lookup[key] }
)
.ToArray();
if (!characters.Any())
@@ -971,56 +970,56 @@ namespace StardewModdingAPI.Metadata
// update sprite
foreach (var target in characters)
{
- target.Npc.Sprite.spriteTexture = this.LoadAndDisposeIfNeeded(target.Npc.Sprite.spriteTexture, target.Key);
- propagated[target.Key] = true;
+ target.Npc.Sprite.spriteTexture = this.LoadAndDisposeIfNeeded(target.Npc.Sprite.spriteTexture, target.AssetName.Name);
+ propagated[target.AssetName] = true;
}
}
/// <summary>Reload the portraits for matching NPCs.</summary>
/// <param name="keys">The asset key to reload.</param>
/// <param name="propagated">The asset keys which have been propagated.</param>
- private void ReloadNpcPortraits(IEnumerable<string> keys, IDictionary<string, bool> propagated)
+ private void ReloadNpcPortraits(IEnumerable<IAssetName> keys, IDictionary<IAssetName, bool> propagated)
{
// get NPCs
- HashSet<string> lookup = new HashSet<string>(keys, StringComparer.OrdinalIgnoreCase);
+ IDictionary<string, IAssetName> lookup = keys.ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase);
var characters =
(
from npc in this.GetCharacters()
where npc.isVillager()
let key = this.NormalizeAssetNameIgnoringEmpty(npc.Portrait?.Name)
- where key != null && lookup.Contains(key)
- select new { Npc = npc, Key = key }
+ where key != null && lookup.ContainsKey(key)
+ select new { Npc = npc, AssetName = lookup[key] }
)
.ToList();
// special case: Gil is a private NPC field on the AdventureGuild class (only used for the portrait)
{
string gilKey = this.NormalizeAssetNameIgnoringEmpty("Portraits/Gil");
- if (lookup.Contains(gilKey))
+ if (lookup.TryGetValue(gilKey, out IAssetName assetName))
{
GameLocation adventureGuild = Game1.getLocationFromName("AdventureGuild");
if (adventureGuild != null)
- characters.Add(new { Npc = this.Reflection.GetField<NPC>(adventureGuild, "Gil").GetValue(), Key = gilKey });
+ characters.Add(new { Npc = this.Reflection.GetField<NPC>(adventureGuild, "Gil").GetValue(), AssetName = assetName });
}
}
// update portrait
foreach (var target in characters)
{
- target.Npc.Portrait = this.LoadAndDisposeIfNeeded(target.Npc.Portrait, target.Key);
- propagated[target.Key] = true;
+ target.Npc.Portrait = this.LoadAndDisposeIfNeeded(target.Npc.Portrait, target.AssetName.Name);
+ propagated[target.AssetName] = true;
}
}
/// <summary>Reload the sprites for matching players.</summary>
- /// <param name="key">The asset key to reload.</param>
- private bool ReloadPlayerSprites(string key)
+ /// <param name="assetName">The asset name to reload.</param>
+ private bool ReloadPlayerSprites(IAssetName assetName)
{
Farmer[] players =
(
from player in Game1.getOnlineFarmers()
- where this.IsSameAssetKey(player.getTexture(), key)
+ where assetName.IsEquivalentTo(player.getTexture())
select player
)
.ToArray();
@@ -1036,11 +1035,11 @@ namespace StardewModdingAPI.Metadata
/// <summary>Reload suspension bridge textures.</summary>
/// <param name="content">The content manager through which to reload the asset.</param>
- /// <param name="key">The asset key to reload.</param>
+ /// <param name="assetName">The asset name to reload.</param>
/// <returns>Returns whether any textures were reloaded.</returns>
- private bool ReloadSuspensionBridges(LocalizedContentManager content, string key)
+ private bool ReloadSuspensionBridges(LocalizedContentManager content, IAssetName assetName)
{
- Lazy<Texture2D> texture = new Lazy<Texture2D>(() => content.Load<Texture2D>(key));
+ Lazy<Texture2D> texture = new Lazy<Texture2D>(() => content.Load<Texture2D>(assetName.Name));
foreach (GameLocation location in this.GetLocations(buildingInteriors: false))
{
@@ -1059,10 +1058,10 @@ namespace StardewModdingAPI.Metadata
/// <summary>Reload tree textures.</summary>
/// <param name="content">The content manager through which to reload the asset.</param>
- /// <param name="key">The asset key to reload.</param>
+ /// <param name="assetName">The asset name to reload.</param>
/// <param name="type">The type to reload.</param>
/// <returns>Returns whether any textures were reloaded.</returns>
- private bool ReloadTreeTextures(LocalizedContentManager content, string key, int type)
+ private bool ReloadTreeTextures(LocalizedContentManager content, IAssetName assetName, int type)
{
Tree[] trees = this.GetLocations()
.SelectMany(p => p.terrainFeatures.Values.OfType<Tree>())
@@ -1071,7 +1070,7 @@ namespace StardewModdingAPI.Metadata
if (trees.Any())
{
- Lazy<Texture2D> texture = new Lazy<Texture2D>(() => content.Load<Texture2D>(key));
+ Lazy<Texture2D> texture = new Lazy<Texture2D>(() => content.Load<Texture2D>(assetName.Name));
foreach (Tree tree in trees)
tree.texture = texture;
return true;
@@ -1084,12 +1083,12 @@ namespace StardewModdingAPI.Metadata
** Reload data methods
****/
/// <summary>Reload the dialogue data for matching NPCs.</summary>
- /// <param name="key">The asset key to reload.</param>
+ /// <param name="assetName">The asset name to reload.</param>
/// <returns>Returns whether any assets were reloaded.</returns>
- private bool ReloadNpcDialogue(string key)
+ private bool ReloadNpcDialogue(IAssetName assetName)
{
// get NPCs
- string name = Path.GetFileName(key);
+ string name = Path.GetFileName(assetName.Name);
NPC[] villagers = this.GetCharacters().Where(npc => npc.Name == name && npc.isVillager()).ToArray();
if (!villagers.Any())
return false;
@@ -1114,12 +1113,12 @@ namespace StardewModdingAPI.Metadata
}
/// <summary>Reload the schedules for matching NPCs.</summary>
- /// <param name="key">The asset key to reload.</param>
+ /// <param name="assetName">The asset name to reload.</param>
/// <returns>Returns whether any assets were reloaded.</returns>
- private bool ReloadNpcSchedules(string key)
+ private bool ReloadNpcSchedules(IAssetName assetName)
{
// get NPCs
- string name = Path.GetFileName(key);
+ string name = Path.GetFileName(assetName.Name);
NPC[] villagers = this.GetCharacters().Where(npc => npc.Name == name && npc.isVillager()).ToArray();
if (!villagers.Any())
return false;
@@ -1243,39 +1242,6 @@ namespace StardewModdingAPI.Metadata
return this.AssertAndNormalizeAssetName(path);
}
- /// <summary>Get whether a given asset key is equivalent to a normalized asset key, ignoring unimportant differences like capitalization and formatting.</summary>
- /// <param name="actualKey">The actual key to check.</param>
- /// <param name="normalizedKey">The key to match, already normalized via <see cref="AssertAndNormalizeAssetName"/> or <see cref="NormalizeAssetNameIgnoringEmpty"/>.</param>
- private bool IsSameAssetKey(string actualKey, string normalizedKey)
- {
- if (actualKey is null || normalizedKey is null)
- return false;
-
- return normalizedKey.Equals(PathUtilities.NormalizeAssetName(actualKey), StringComparison.OrdinalIgnoreCase);
- }
-
- /// <summary>Get whether a key starts with a substring after the substring is normalized.</summary>
- /// <param name="key">The key to check.</param>
- /// <param name="rawSubstring">The substring to normalize and find.</param>
- private bool KeyStartsWith(string key, string rawSubstring)
- {
- if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(rawSubstring))
- return false;
-
- return key.StartsWith(this.NormalizeAssetNameIgnoringEmpty(rawSubstring), StringComparison.OrdinalIgnoreCase);
- }
-
- /// <summary>Get whether a normalized asset key is in the given folder.</summary>
- /// <param name="key">The normalized asset key (like <c>Animals/cat</c>).</param>
- /// <param name="folder">The key folder (like <c>Animals</c>); doesn't need to be normalized.</param>
- /// <param name="allowSubfolders">Whether to return true if the key is inside a subfolder of the <paramref name="folder"/>.</param>
- private bool IsInFolder(string key, string folder, bool allowSubfolders = false)
- {
- return
- this.KeyStartsWith(key, $"{folder}/")
- && (allowSubfolders || this.CountSegments(key) == this.CountSegments(folder) + 1);
- }
-
/// <summary>Get the segments in a path (e.g. 'a/b' is 'a' and 'b').</summary>
/// <param name="path">The path to check.</param>
private string[] GetSegments(string path)
@@ -1285,13 +1251,6 @@ namespace StardewModdingAPI.Metadata
: Array.Empty<string>();
}
- /// <summary>Count the number of segments in a path (e.g. 'a/b' is 2).</summary>
- /// <param name="path">The path to check.</param>
- private int CountSegments(string path)
- {
- return this.GetSegments(path).Length;
- }
-
/// <summary>Load a texture, and dispose the old one if <see cref="AggressiveMemoryOptimizations"/> is enabled and it's different from the new instance.</summary>
/// <param name="oldTexture">The previous texture to dispose.</param>
/// <param name="key">The asset key to load.</param>
@@ -1315,8 +1274,8 @@ namespace StardewModdingAPI.Metadata
}
/// <summary>Remove a case-insensitive key from the paint mask cache.</summary>
- /// <param name="key">The paint mask asset key.</param>
- private bool RemoveFromPaintMaskCache(string key)
+ /// <param name="assetName">The paint mask asset name.</param>
+ private bool RemoveFromPaintMaskCache(IAssetName assetName)
{
// make cache case-insensitive
// This is needed for cache invalidation since mods may specify keys with a different capitalization
@@ -1324,7 +1283,7 @@ namespace StardewModdingAPI.Metadata
BuildingPainter.paintMaskLookup = new Dictionary<string, List<List<int>>>(BuildingPainter.paintMaskLookup, StringComparer.OrdinalIgnoreCase);
// remove key from cache
- return BuildingPainter.paintMaskLookup.Remove(key);
+ return BuildingPainter.paintMaskLookup.Remove(assetName.Name);
}
/// <summary>Metadata about a location used in asset propagation.</summary>