/// <summary>Loads an animal sub type's assets and validates.</summary> /// <param name="subType">The sub type to load assets for and to validate.</param> /// <returns>Whether the sub type was valid.</returns> private bool LoadAnimalSubType(AnimalSubType subType, IContentPack contentPack, string animalName) { // get sprites var sprites = new AnimalSprites( adultSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", $"{subType.Name}.png"), contentPack), babySpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", $"Baby {subType.Name}.png"), contentPack), harvestedSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", $"Harvested {subType.Name}.png"), contentPack), springAdultSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "spring", $"{subType.Name}.png"), contentPack), springHarvestedSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "spring", $"Harvested {subType.Name}.png"), contentPack), springBabySpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "spring", $"Baby {subType.Name}.png"), contentPack), summerAdultSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "summer", $"{subType.Name}.png"), contentPack), summerHarvestedSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "summer", $"Harvested {subType.Name}.png"), contentPack), summerBabySpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "summer", $"Baby {subType.Name}.png"), contentPack), fallAdultSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "fall", $"{subType.Name}.png"), contentPack), fallHarvestedSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "fall", $"Harvested {subType.Name}.png"), contentPack), fallBabySpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "fall", $"Baby {subType.Name}.png"), contentPack), winterAdultSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "winter", $"{subType.Name}.png"), contentPack), winterHarvestedSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "winter", $"Harvested {subType.Name}.png"), contentPack), winterBabySpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "winter", $"Baby {subType.Name}.png"), contentPack) ); // ensure sprites are valid if (!sprites.IsValid()) { this.Monitor.Log($"Sprites are not valid for Content pack: {contentPack.Manifest.Name} >> Animal: {animalName} >> Subtype: {subType.Name}", LogLevel.Error); return(false); } subType.Sprites = sprites; // resolve API tokens in data and validate it subType.ResolveTokens(); if (!subType.IsValid()) { this.Monitor.Log($"Data is not valid for Content pack: {contentPack.Manifest.Name} >> Animal: {animalName} >> Subtype: {subType.Name}", LogLevel.Error); return(false); } return(true); }
/// <summary>Load all the sprites for the new animals from the loaded content packs.</summary> private void LoadContentPacks() { foreach (IContentPack contentPack in this.Helper.ContentPacks.GetOwned()) { Monitor.Log($"Loading {contentPack.Manifest.Name}"); // loop through each animal folder in the current content pack foreach (var animalFolder in Directory.GetDirectories(contentPack.DirectoryPath)) { var animalFolderSplit = animalFolder.Split(Path.DirectorySeparatorChar); var animalName = animalFolderSplit[animalFolderSplit.Length - 1]; // ensure content.json file exists if (!File.Exists(Path.Combine(animalFolder, "content.json"))) { this.Monitor.Log($"Content pack: {contentPack.Manifest.Name} >> Animal: {animalName} doesn't contain a content.json file.", LogLevel.Error); continue; } // serialize and validate content.json file AnimalData animalData = contentPack.LoadAsset <AnimalData>(Path.Combine(animalName, "content.json")); bool isAnimalValid = animalData.IsValid(animalName); if (!isAnimalValid) { this.Monitor.Log($"Content.json is not valid for Content pack: {contentPack.Manifest.Name} >> Animal: {animalName}", LogLevel.Error); continue; } // loop through each sub type and add them (such as colour varients etc) List <AnimalSubType> animalSubTypes = new List <AnimalSubType>(); foreach (var type in animalData.Types) { // get sprites var sprites = new AnimalSprites( adultSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", $"{type}.png"), contentPack), babySpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", $"Baby {type}.png"), contentPack), harvestedSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", $"Harvested {type}.png"), contentPack), springAdultSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "spring", $"{type}.png"), contentPack), springHarvestedSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "spring", $"Harvested {type}.png"), contentPack), springBabySpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "spring", $"Baby {type}.png"), contentPack), summerAdultSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "summer", $"{type}.png"), contentPack), summerHarvestedSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "summer", $"Harvested {type}.png"), contentPack), summerBabySpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "summer", $"Baby {type}.png"), contentPack), fallAdultSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "fall", $"{type}.png"), contentPack), fallHarvestedSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "fall", $"Harvested {type}.png"), contentPack), fallBabySpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "fall", $"Baby {type}.png"), contentPack), winterAdultSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "winter", $"{type}.png"), contentPack), winterHarvestedSpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "winter", $"Harvested {type}.png"), contentPack), winterBabySpriteSheet: GetSpriteByPath(Path.Combine(animalName, "assets", "winter", $"Baby {type}.png"), contentPack) ); // ensure sprites are valid if (!sprites.IsValid()) { this.Monitor.Log($"Sprites are not valid for Content pack: {contentPack.Manifest.Name} >> Animal: {animalName} >> Subtype: {type}", LogLevel.Error); continue; } // get data AnimalSubTypeData data; if (File.Exists(Path.Combine(animalFolder, "assets", $"{type} content.json"))) { data = contentPack.LoadAsset <AnimalSubTypeData>(Path.Combine(animalName, "assets", $"{type} content.json")); } else if (File.Exists(Path.Combine(animalFolder, "assets", "content.json"))) { data = contentPack.LoadAsset <AnimalSubTypeData>(Path.Combine(animalName, "assets", "content.json")); } else { this.Monitor.Log($"Content pack: {contentPack.Manifest.Name} >> Animal: {animalName} >> Type: {type} doesn't have a content.json file.", LogLevel.Error); continue; } // resolve API tokens in data and validate it data.ResolveTokens(); if (!data.IsValid(type)) { this.Monitor.Log($"Data is not valid for Content pack: {contentPack.Manifest.Name} >> Animal: {animalName} >> Subtype: {type}", LogLevel.Error); continue; } // create subtype and add to animal var animalSubType = new AnimalSubType( name: type, data: data, sprites: sprites ); animalSubTypes.Add(animalSubType); } // ensure there were valid sub types if (animalSubTypes.Count == 0) { this.Monitor.Log($"No valid sub types for Content pack: {contentPack.Manifest.Name} >> Animal: {animalName}.\n Animal will not be added.", LogLevel.Error); continue; } // create, validate, and add the animal var animal = new Animal( name: animalName, data: animalData, shopIcon: GetSpriteByPath(Path.Combine(animalName, $"shopdisplay.png"), contentPack), subTypes: animalSubTypes ); if (!animal.IsValid()) { this.Monitor.Log($"Animal is not valid at Content pack: {contentPack.Manifest.Name} >> Animal: {animalName}", LogLevel.Error); continue; } Animals.Add(animal); } } }
/********* ** Internal Methods *********/ /// <summary>The prefix for the LoadTexture method.</summary> /// <param name="textureName">The name of the texture to load.</param> /// <param name="__instance">The <see cref="AnimatedSprite"/> instance being patched.</param> /// <returns>False meaning the original method won't get ran.</returns> internal static bool LoadTexturePrefix(AnimatedSprite __instance) { var loadedTexture = (string)typeof(AnimatedSprite).GetField("loadedTexture", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(__instance); if (loadedTexture == __instance.textureName.Value) { return(false); } var spriteTexture = (Texture2D)typeof(AnimatedSprite).GetField("spriteTexture", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(__instance); var contentManager = (ContentManager)typeof(AnimatedSprite).GetField("contentManager", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(__instance); // check if the texture to load is an animal if (__instance.textureName.Value != null && __instance.textureName.Value.Contains("Animals\\")) { var animalName = __instance.textureName.Value.Split('\\')[1]; var isCustomAnimal = false; AnimalSubType customAnimalSubType = null; // check if it's a custom animal var subType = ModEntry.Instance.Api.GetAnimalSubTypeByName(animalName); if (subType != null) { var currentSeason = Season.Spring; switch (Game1.currentSeason) { case "spring": currentSeason = Season.Spring; break; case "summer": currentSeason = Season.Summer; break; case "fall": currentSeason = Season.Fall; break; case "winter": currentSeason = Season.Winter; break; } // load the texture through FAVR, not the content pipeline spriteTexture = customAnimalSubType.Sprites.GetSpriteSheet( isBaby: animalName.Contains("Baby"), isHarvested: animalName.Contains("Sheared"), season: currentSeason ); } else { spriteTexture = contentManager.Load <Texture2D>(__instance.textureName.Value); } } else { spriteTexture = __instance.textureName.Value != null?contentManager.Load <Texture2D>(__instance.textureName.Value) : null; } loadedTexture = __instance.textureName.Value; typeof(AnimatedSprite).GetField("spriteTexture", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(__instance, spriteTexture); typeof(AnimatedSprite).GetField("loadedTexture", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(__instance, loadedTexture); if (spriteTexture == null) { return(false); } __instance.UpdateSourceRect(); return(false); }