From 99ebac7e071ae3548093f57e0f0699fb29b25bef Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 11 Aug 2018 23:52:45 -0400 Subject: add asset propagation for dialogue changes (#580) --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'src/SMAPI/Metadata') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 12abeb10..3821e4ab 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -320,14 +320,16 @@ namespace StardewModdingAPI.Metadata return this.ReloadNpcSprites(content, key, monster: true); if (key.StartsWith(this.GetNormalisedPath("LooseSprites\\Fence"), StringComparison.InvariantCultureIgnoreCase)) - return this.ReloadFenceTextures(content, key); + return this.ReloadFenceTextures(key); if (this.IsInFolder(key, "Portraits")) return this.ReloadNpcPortraits(content, key); // dynamic data + if (this.IsInFolder(key, "Characters\\Dialogue")) + return this.ReloadNpcDialogue(key); if (this.IsInFolder(key, "Characters\\schedules")) - return this.ReloadNpcSchedules(content, key); + return this.ReloadNpcSchedules(key); return false; } @@ -416,10 +418,9 @@ namespace StardewModdingAPI.Metadata } /// Reload the sprites for a fence type. - /// The content manager through which to reload the asset. /// The asset key to reload. /// Returns whether any textures were reloaded. - private bool ReloadFenceTextures(LocalizedContentManager content, string key) + private bool ReloadFenceTextures(string key) { // get fence type if (!int.TryParse(this.GetSegments(key)[1].Substring("Fence".Length), out int fenceType)) @@ -508,11 +509,27 @@ namespace StardewModdingAPI.Metadata /**** ** Reload data methods ****/ + /// Reload the dialogue data for matching NPCs. + /// The asset key to reload. + /// Returns whether any assets were reloaded. + private bool ReloadNpcDialogue(string key) + { + // get NPCs + string name = Path.GetFileName(key); + NPC[] villagers = this.GetCharacters().Where(npc => npc.Name == name && npc.isVillager()).ToArray(); + if (!villagers.Any()) + return false; + + // update dialogue + foreach (NPC villager in villagers) + villager.resetSeasonalDialogue(); // doesn't only affect seasonal dialogue + return true; + } + /// Reload the schedules for matching NPCs. - /// The content manager through which to reload the asset. /// The asset key to reload. /// Returns whether any assets were reloaded. - private bool ReloadNpcSchedules(LocalizedContentManager content, string key) + private bool ReloadNpcSchedules(string key) { // get NPCs string name = Path.GetFileName(key); -- cgit From a6f6b9cad7a83e19b84ef2b5b2c7c9ae54227de4 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 12 Aug 2018 00:41:53 -0400 Subject: fix asset propagation for child sprites (#573) --- docs/release-notes.md | 2 +- src/SMAPI/Metadata/CoreAssetPropagator.cs | 37 ++++++++++++++++++++----------- 2 files changed, 25 insertions(+), 14 deletions(-) (limited to 'src/SMAPI/Metadata') diff --git a/docs/release-notes.md b/docs/release-notes.md index 4c5671ec..9ac52ab1 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -13,7 +13,7 @@ * For modders: * Added support for `.json` data files in the content API (including Content Patcher). - * Added asset propagation for dialogue changes through the content API. + * Fixed changes through the content API not propagating correctly for dialogue and child sprites. * Added `--mods-path` command-line argument to allow switching between mod folders. * All enums are now JSON-serialised by name, since that's more user-friendly. Previously only certain predefined enums were serialised that way. JSON files which already have integer enums will still be parsed fine. * Fixed false compatibility error when constructing multidimensional arrays. diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 3821e4ab..e9d66975 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -313,13 +313,10 @@ namespace StardewModdingAPI.Metadata if (this.IsInFolder(key, "Buildings")) return this.ReloadBuildings(content, key); - if (this.IsInFolder(key, "Characters")) - return this.ReloadNpcSprites(content, key, monster: false); + if (this.IsInFolder(key, "Characters") || this.IsInFolder(key, "Characters\\Monsters")) + return this.ReloadNpcSprites(content, key); - if (this.IsInFolder(key, "Characters\\Monsters")) - return this.ReloadNpcSprites(content, key, monster: true); - - if (key.StartsWith(this.GetNormalisedPath("LooseSprites\\Fence"), StringComparison.InvariantCultureIgnoreCase)) + if (this.KeyStartsWith(key, "LooseSprites\\Fence")) return this.ReloadFenceTextures(key); if (this.IsInFolder(key, "Portraits")) @@ -328,6 +325,7 @@ namespace StardewModdingAPI.Metadata // dynamic data if (this.IsInFolder(key, "Characters\\Dialogue")) return this.ReloadNpcDialogue(key); + if (this.IsInFolder(key, "Characters\\schedules")) return this.ReloadNpcSchedules(key); @@ -447,13 +445,13 @@ namespace StardewModdingAPI.Metadata /// Reload the sprites for matching NPCs. /// The content manager through which to reload the asset. /// The asset key to reload. - /// Whether to match monsters (true) or non-monsters (false). /// Returns whether any textures were reloaded. - private bool ReloadNpcSprites(LocalizedContentManager content, string key, bool monster) + private bool ReloadNpcSprites(LocalizedContentManager content, string key) { // get NPCs - string name = this.GetNpcNameFromFileName(Path.GetFileName(key)); - NPC[] characters = this.GetCharacters().Where(npc => npc.Name == name && npc.IsMonster == monster).ToArray(); + NPC[] characters = this.GetCharacters() + .Where(npc => this.GetNormalisedPath(npc.Sprite.textureName.Value) == key) + .ToArray(); if (!characters.Any()) return false; @@ -471,15 +469,20 @@ namespace StardewModdingAPI.Metadata private bool ReloadNpcPortraits(LocalizedContentManager content, string key) { // get NPCs - string name = this.GetNpcNameFromFileName(Path.GetFileName(key)); - NPC[] villagers = this.GetCharacters().Where(npc => npc.Name == name && npc.isVillager()).ToArray(); + NPC[] villagers = this.GetCharacters() + .Where(npc => npc.isVillager() && this.GetNormalisedPath($"Portraits\\{this.Reflection.GetMethod(npc, "getTextureName").Invoke()}") == key) + .ToArray(); if (!villagers.Any()) return false; // update portrait Texture2D texture = content.Load(key); foreach (NPC villager in villagers) + { + villager.resetPortrait(); villager.Portrait = texture; + } + return true; } @@ -624,6 +627,14 @@ namespace StardewModdingAPI.Metadata } } + /// Get whether a key starts with a substring after the substring is normalised. + /// The key to check. + /// The substring to normalise and find. + private bool KeyStartsWith(string key, string rawSubstring) + { + return key.StartsWith(this.GetNormalisedPath(rawSubstring), StringComparison.InvariantCultureIgnoreCase); + } + /// Get whether a normalised asset key is in the given folder. /// The normalised asset key (like Animals/cat). /// The key folder (like Animals); doesn't need to be normalised. @@ -631,7 +642,7 @@ namespace StardewModdingAPI.Metadata private bool IsInFolder(string key, string folder, bool allowSubfolders = false) { return - key.StartsWith(this.GetNormalisedPath($"{folder}\\"), StringComparison.InvariantCultureIgnoreCase) + this.KeyStartsWith(key, $"{folder}\\") && (allowSubfolders || this.CountSegments(key) == this.CountSegments(folder) + 1); } -- cgit From f7111a2488bd16b30c28be1025e7dbf9c4ca1306 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 12 Aug 2018 01:31:52 -0400 Subject: add asset propagation for map tilesheets (#570) --- docs/release-notes.md | 5 ++++- src/SMAPI/Metadata/CoreAssetPropagator.cs | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'src/SMAPI/Metadata') diff --git a/docs/release-notes.md b/docs/release-notes.md index 9ac52ab1..ab47b5c7 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -13,7 +13,10 @@ * For modders: * Added support for `.json` data files in the content API (including Content Patcher). - * Fixed changes through the content API not propagating correctly for dialogue and child sprites. + * Added automatic propagation when changing assets through the content API for... + * child sprites; + * dialogue; + * map tilesheets. * Added `--mods-path` command-line argument to allow switching between mod folders. * All enums are now JSON-serialised by name, since that's more user-friendly. Previously only certain predefined enums were serialised that way. JSON files which already have integer enums will still be parsed fine. * Fixed false compatibility error when constructing multidimensional arrays. diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index e9d66975..8487b6be 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -13,6 +13,7 @@ using StardewValley.Menus; using StardewValley.Objects; using StardewValley.Projectiles; using StardewValley.TerrainFeatures; +using xTile.Tiles; namespace StardewModdingAPI.Metadata { @@ -63,6 +64,23 @@ namespace StardewModdingAPI.Metadata /// Returns any non-null value to indicate an asset was loaded. private object PropagateImpl(LocalizedContentManager content, string key) { + /**** + ** Special case: current map tilesheet + ** We only need to do this for the current location, since tilesheets are reloaded when you enter a location. + ** Just in case, we should still propagate by key even if a tilesheet is matched. + ****/ + if (Game1.currentLocation?.map?.TileSheets != null) + { + foreach (TileSheet tilesheet in Game1.currentLocation.map.TileSheets) + { + if (this.GetNormalisedPath(tilesheet.ImageSource) == key) + Game1.mapDisplayDevice.LoadTileSheet(tilesheet); + } + } + + /**** + ** Propagate by key + ****/ Reflector reflection = this.Reflection; switch (key.ToLower().Replace("/", "\\")) // normalised key so we can compare statically { -- cgit