From 60fc4a64886d92e70475af5bbfeb29b2e3ef26cd Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 25 Mar 2018 14:59:06 -0400 Subject: update animal textures when changed through the content API (#459) --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 125 ++++++++++++++++++++++++------ 1 file changed, 102 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 38b205a5..e54e0286 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -7,6 +7,7 @@ using StardewModdingAPI.Framework.Reflection; using StardewValley; using StardewValley.BellsAndWhistles; using StardewValley.Buildings; +using StardewValley.Characters; using StardewValley.Locations; using StardewValley.Menus; using StardewValley.Objects; @@ -65,6 +66,16 @@ namespace StardewModdingAPI.Metadata Reflector reflection = this.Reflection; switch (key.ToLower().Replace("/", "\\")) // normalised key so we can compare statically { + /**** + ** Animals + ****/ + case "animals\\cat": + return this.ReloadPetOrHorseSprites(content, key); + case "animals\\dog": + return this.ReloadPetOrHorseSprites(content, key); + case "animals\\horse": + return this.ReloadPetOrHorseSprites(content, key); + /**** ** Buildings ****/ @@ -326,6 +337,9 @@ namespace StardewModdingAPI.Metadata } // dynamic textures + if (this.IsInFolder(key, "Animals")) + return this.ReloadFarmAnimalSprites(content, key); + if (this.IsInFolder(key, "Buildings")) return this.ReloadBuildings(content, key); @@ -351,6 +365,57 @@ namespace StardewModdingAPI.Metadata /**** ** Reload methods ****/ + /// Reload the sprites for matching pets or horses. + /// The animal type. + /// The content manager through which to reload the asset. + /// The asset key to reload. + /// Returns whether any textures were reloaded. + private bool ReloadPetOrHorseSprites(LocalizedContentManager content, string key) + where TAnimal : NPC + { + // find matches + TAnimal[] animals = this.GetCharacters().OfType().ToArray(); + if (!animals.Any()) + return false; + + // update sprites + Texture2D texture = content.Load(key); + foreach (TAnimal animal in animals) + this.SetSpriteTexture(animal.sprite, texture); + return true; + } + + /// Reload the sprites for matching farm animals. + /// The content manager through which to reload the asset. + /// The asset key to reload. + /// Returns whether any textures were reloaded. + /// Derived from . + private bool ReloadFarmAnimalSprites(LocalizedContentManager content, string key) + { + // find matches + FarmAnimal[] animals = this.GetFarmAnimals().ToArray(); + if (!animals.Any()) + return false; + + // update sprites + Lazy texture = new Lazy(() => content.Load(key)); + foreach (FarmAnimal animal in animals) + { + // get expected key + string expectedKey = animal.age < animal.ageWhenMature + ? $"Baby{(animal.type == "Duck" ? "White Chicken" : animal.type)}" + : animal.type; + if (animal.showDifferentTextureWhenReadyForHarvest && animal.currentProduce <= 0) + expectedKey = $"Sheared{expectedKey}"; + expectedKey = $"Animals\\{expectedKey}"; + + // reload asset + if (expectedKey == key) + this.SetSpriteTexture(animal.sprite, texture.Value); + } + return texture.IsValueCreated; + } + /// Reload building textures. /// The content manager through which to reload the asset. /// The asset key to reload. @@ -417,26 +482,14 @@ namespace StardewModdingAPI.Metadata { // get NPCs string name = this.GetNpcNameFromFileName(Path.GetFileName(key)); - NPC[] characters = - ( - from location in this.GetLocations() - from npc in location.characters - where npc.name == name && npc.IsMonster == monster - select npc - ) - .Distinct() - .ToArray(); + NPC[] characters = this.GetCharacters().Where(npc => npc.name == name && npc.IsMonster == monster).ToArray(); if (!characters.Any()) return false; // update portrait Texture2D texture = content.Load(key); foreach (NPC character in characters) -#if STARDEW_VALLEY_1_3 - this.Reflection.GetField(character.Sprite, "spriteTexture").SetValue(texture); -#else - character.Sprite.Texture = texture; -#endif + this.SetSpriteTexture(character.Sprite, texture); return true; } @@ -448,15 +501,7 @@ namespace StardewModdingAPI.Metadata { // get NPCs string name = this.GetNpcNameFromFileName(Path.GetFileName(key)); - NPC[] villagers = - ( - from location in this.GetLocations() - from npc in location.characters - where npc.name == name && npc.isVillager() - select npc - ) - .Distinct() - .ToArray(); + NPC[] villagers = this.GetCharacters().Where(npc => npc.name == name && npc.isVillager()).ToArray(); if (!villagers.Any()) return false; @@ -497,6 +542,18 @@ namespace StardewModdingAPI.Metadata /**** ** Helpers ****/ + /// Reload the texture for an animated sprite. + /// The animated sprite to update. + /// The texture to set. + private void SetSpriteTexture(AnimatedSprite sprite, Texture2D texture) + { +#if STARDEW_VALLEY_1_3 + this.Reflection.GetField(sprite, "spriteTexture").SetValue(texture); +#else + sprite.Texture = texture; +#endif + } + /// Get an NPC name from the name of their file under Content/Characters. /// The file name. /// Derived from . @@ -515,6 +572,28 @@ namespace StardewModdingAPI.Metadata } } + /// Get all NPCs in the game (excluding farm animals). + private IEnumerable GetCharacters() + { + return this.GetLocations().SelectMany(p => p.characters); + } + + /// Get all farm animals in the game. + private IEnumerable GetFarmAnimals() + { + foreach (GameLocation location in this.GetLocations()) + { + if (location is Farm farm) + { + foreach (FarmAnimal animal in farm.animals.Values) + yield return animal; + } + else if (location is AnimalHouse animalHouse) + foreach (FarmAnimal animal in animalHouse.animals.Values) + yield return animal; + } + } + /// Get all locations in the game. private IEnumerable GetLocations() { -- cgit