From bad2ac2a29b8775be97133e4c4cfb67a4a7406ee Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 24 Feb 2019 19:56:08 -0500 Subject: remove deprecated APIs (#606) --- src/SMAPI/Metadata/InstructionMetadata.cs | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/SMAPI/Metadata') diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs index 272ceb09..72410d41 100644 --- a/src/SMAPI/Metadata/InstructionMetadata.cs +++ b/src/SMAPI/Metadata/InstructionMetadata.cs @@ -53,9 +53,6 @@ namespace StardewModdingAPI.Metadata yield return new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.locationSerializer), InstructionHandleResult.DetectedSaveSerialiser); yield return new EventFinder(typeof(ISpecialisedEvents).FullName, nameof(ISpecialisedEvents.UnvalidatedUpdateTicked), InstructionHandleResult.DetectedUnvalidatedUpdateTick); yield return new EventFinder(typeof(ISpecialisedEvents).FullName, nameof(ISpecialisedEvents.UnvalidatedUpdateTicking), InstructionHandleResult.DetectedUnvalidatedUpdateTick); -#if !SMAPI_3_0_STRICT - yield return new EventFinder(typeof(SpecialisedEvents).FullName, nameof(SpecialisedEvents.UnvalidatedUpdateTick), InstructionHandleResult.DetectedUnvalidatedUpdateTick); -#endif /**** ** detect paranoid issues -- cgit From 78f28357e4f87ed619144229ea65c1e1cb0f9dd3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 15 Apr 2019 22:36:50 -0400 Subject: update code for SDV 1.4 (#638) --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/SMAPI/Metadata') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index a64dc89b..c4086712 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -152,12 +152,12 @@ namespace StardewModdingAPI.Metadata case "characters\\farmer\\farmer_base": // Farmer if (Game1.player == null || !Game1.player.IsMale) return false; - return Game1.player.FarmerRenderer = new FarmerRenderer(key); + return Game1.player.FarmerRenderer = new FarmerRenderer(key, Game1.player); case "characters\\farmer\\farmer_girl_base": // Farmer if (Game1.player == null || Game1.player.IsMale) return false; - return Game1.player.FarmerRenderer = new FarmerRenderer(key); + return Game1.player.FarmerRenderer = new FarmerRenderer(key, Game1.player); case "characters\\farmer\\hairstyles": // Game1.loadContent return FarmerRenderer.hairStylesTexture = content.Load(key); -- cgit From 2b12bb32f67422a7d25eb7e2d8ea8e1c3e335708 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 17 May 2019 19:41:26 -0400 Subject: batch reload assets in some cases --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 263 ++++++++++++++++++++---------- 1 file changed, 181 insertions(+), 82 deletions(-) (limited to 'src/SMAPI/Metadata') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index c4086712..dbb27b14 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -34,6 +34,19 @@ namespace StardewModdingAPI.Metadata /// Encapsulates monitoring and logging. private readonly IMonitor Monitor; + /// Optimised bucket categories for batch reloading assets. + private enum AssetBucket + { + /// NPC overworld sprites. + Sprite, + + /// Villager dialogue portraits. + Portrait, + + /// Any other asset. + Other + }; + /********* ** Public methods @@ -51,15 +64,42 @@ namespace StardewModdingAPI.Metadata /// Reload one of the game's core assets (if applicable). /// The content manager through which to reload the asset. - /// The asset key to reload. - /// The asset type to reload. - /// Returns whether an asset was reloaded. - public bool Propagate(LocalizedContentManager content, string key, Type type) + /// The asset keys and types to reload. + /// Returns the number of reloaded assets. + public int Propagate(LocalizedContentManager content, IDictionary assets) { - object result = this.PropagateImpl(content, key, type); - if (result is bool b) - return b; - return result != null; + // group into optimised lists + var buckets = assets.GroupBy(p => + { + if (this.IsInFolder(p.Key, "Characters") || this.IsInFolder(p.Key, "Characters\\Monsters")) + return AssetBucket.Sprite; + + if (this.IsInFolder(p.Key, "Portraits")) + return AssetBucket.Portrait; + + return AssetBucket.Other; + }); + + // reload assets + int reloaded = 0; + foreach (var bucket in buckets) + { + switch (bucket.Key) + { + case AssetBucket.Sprite: + reloaded += this.ReloadNpcSprites(content, bucket.Select(p => p.Key)); + break; + + case AssetBucket.Portrait: + reloaded += this.ReloadNpcPortraits(content, bucket.Select(p => p.Key)); + break; + + default: + reloaded += bucket.Count(p => this.PropagateOther(content, p.Key, p.Value)); + break; + } + } + return reloaded; } @@ -71,7 +111,7 @@ namespace StardewModdingAPI.Metadata /// The asset key to reload. /// The asset type to reload. /// Returns whether an asset was loaded. The return value may be true or false, or a non-null value for true. - private object PropagateImpl(LocalizedContentManager content, string key, Type type) + private bool PropagateOther(LocalizedContentManager content, string key, Type type) { key = this.GetNormalisedPath(key); @@ -147,147 +187,185 @@ namespace StardewModdingAPI.Metadata ** Content\Characters\Farmer ****/ case "characters\\farmer\\accessories": // Game1.loadContent - return FarmerRenderer.accessoriesTexture = content.Load(key); + FarmerRenderer.accessoriesTexture = content.Load(key); + return true; case "characters\\farmer\\farmer_base": // Farmer if (Game1.player == null || !Game1.player.IsMale) return false; - return Game1.player.FarmerRenderer = new FarmerRenderer(key, Game1.player); + Game1.player.FarmerRenderer = new FarmerRenderer(key, Game1.player); + return true; case "characters\\farmer\\farmer_girl_base": // Farmer if (Game1.player == null || Game1.player.IsMale) return false; - return Game1.player.FarmerRenderer = new FarmerRenderer(key, Game1.player); + Game1.player.FarmerRenderer = new FarmerRenderer(key, Game1.player); + return true; case "characters\\farmer\\hairstyles": // Game1.loadContent - return FarmerRenderer.hairStylesTexture = content.Load(key); + FarmerRenderer.hairStylesTexture = content.Load(key); + return true; case "characters\\farmer\\hats": // Game1.loadContent - return FarmerRenderer.hatsTexture = content.Load(key); + FarmerRenderer.hatsTexture = content.Load(key); + return true; case "characters\\farmer\\shirts": // Game1.loadContent - return FarmerRenderer.shirtsTexture = content.Load(key); + FarmerRenderer.shirtsTexture = content.Load(key); + return true; /**** ** Content\Data ****/ case "data\\achievements": // Game1.loadContent - return Game1.achievements = content.Load>(key); + Game1.achievements = content.Load>(key); + return true; case "data\\bigcraftablesinformation": // Game1.loadContent - return Game1.bigCraftablesInformation = content.Load>(key); + Game1.bigCraftablesInformation = content.Load>(key); + return true; case "data\\cookingrecipes": // CraftingRecipe.InitShared - return CraftingRecipe.cookingRecipes = content.Load>(key); + CraftingRecipe.cookingRecipes = content.Load>(key); + return true; case "data\\craftingrecipes": // CraftingRecipe.InitShared - return CraftingRecipe.craftingRecipes = content.Load>(key); + CraftingRecipe.craftingRecipes = content.Load>(key); + return true; case "data\\npcdispositions": // NPC constructor return this.ReloadNpcDispositions(content, key); case "data\\npcgifttastes": // Game1.loadContent - return Game1.NPCGiftTastes = content.Load>(key); + Game1.NPCGiftTastes = content.Load>(key); + return true; case "data\\objectinformation": // Game1.loadContent - return Game1.objectInformation = content.Load>(key); + Game1.objectInformation = content.Load>(key); + return true; /**** ** Content\Fonts ****/ case "fonts\\spritefont1": // Game1.loadContent - return Game1.dialogueFont = content.Load(key); + Game1.dialogueFont = content.Load(key); + return true; case "fonts\\smallfont": // Game1.loadContent - return Game1.smallFont = content.Load(key); + Game1.smallFont = content.Load(key); + return true; case "fonts\\tinyfont": // Game1.loadContent - return Game1.tinyFont = content.Load(key); + Game1.tinyFont = content.Load(key); + return true; case "fonts\\tinyfontborder": // Game1.loadContent - return Game1.tinyFontBorder = content.Load(key); + Game1.tinyFontBorder = content.Load(key); + return true; /**** ** Content\Lighting ****/ case "loosesprites\\lighting\\greenlight": // Game1.loadContent - return Game1.cauldronLight = content.Load(key); + Game1.cauldronLight = content.Load(key); + return true; case "loosesprites\\lighting\\indoorwindowlight": // Game1.loadContent - return Game1.indoorWindowLight = content.Load(key); + Game1.indoorWindowLight = content.Load(key); + return true; case "loosesprites\\lighting\\lantern": // Game1.loadContent - return Game1.lantern = content.Load(key); + Game1.lantern = content.Load(key); + return true; case "loosesprites\\lighting\\sconcelight": // Game1.loadContent - return Game1.sconceLight = content.Load(key); + Game1.sconceLight = content.Load(key); + return true; case "loosesprites\\lighting\\windowlight": // Game1.loadContent - return Game1.windowLight = content.Load(key); + Game1.windowLight = content.Load(key); + return true; /**** ** Content\LooseSprites ****/ case "loosesprites\\controllermaps": // Game1.loadContent - return Game1.controllerMaps = content.Load(key); + Game1.controllerMaps = content.Load(key); + return true; case "loosesprites\\cursors": // Game1.loadContent - return Game1.mouseCursors = content.Load(key); + Game1.mouseCursors = content.Load(key); + return true; case "loosesprites\\daybg": // Game1.loadContent - return Game1.daybg = content.Load(key); + Game1.daybg = content.Load(key); + return true; case "loosesprites\\font_bold": // Game1.loadContent - return SpriteText.spriteTexture = content.Load(key); + SpriteText.spriteTexture = content.Load(key); + return true; case "loosesprites\\font_colored": // Game1.loadContent - return SpriteText.coloredTexture = content.Load(key); + SpriteText.coloredTexture = content.Load(key); + return true; case "loosesprites\\nightbg": // Game1.loadContent - return Game1.nightbg = content.Load(key); + Game1.nightbg = content.Load(key); + return true; case "loosesprites\\shadow": // Game1.loadContent - return Game1.shadowTexture = content.Load(key); + Game1.shadowTexture = content.Load(key); + return true; /**** ** Content\Critters ****/ case "tilesheets\\crops": // Game1.loadContent - return Game1.cropSpriteSheet = content.Load(key); + Game1.cropSpriteSheet = content.Load(key); + return true; case "tilesheets\\debris": // Game1.loadContent - return Game1.debrisSpriteSheet = content.Load(key); + Game1.debrisSpriteSheet = content.Load(key); + return true; case "tilesheets\\emotes": // Game1.loadContent - return Game1.emoteSpriteSheet = content.Load(key); + Game1.emoteSpriteSheet = content.Load(key); + return true; case "tilesheets\\furniture": // Game1.loadContent - return Furniture.furnitureTexture = content.Load(key); + Furniture.furnitureTexture = content.Load(key); + return true; case "tilesheets\\projectiles": // Game1.loadContent - return Projectile.projectileSheet = content.Load(key); + Projectile.projectileSheet = content.Load(key); + return true; case "tilesheets\\rain": // Game1.loadContent - return Game1.rainTexture = content.Load(key); + Game1.rainTexture = content.Load(key); + return true; case "tilesheets\\tools": // Game1.ResetToolSpriteSheet Game1.ResetToolSpriteSheet(); return true; case "tilesheets\\weapons": // Game1.loadContent - return Tool.weaponsTexture = content.Load(key); + Tool.weaponsTexture = content.Load(key); + return true; /**** ** Content\Maps ****/ case "maps\\menutiles": // Game1.loadContent - return Game1.menuTexture = content.Load(key); + Game1.menuTexture = content.Load(key); + return true; case "maps\\springobjects": // Game1.loadContent - return Game1.objectSpriteSheet = content.Load(key); + Game1.objectSpriteSheet = content.Load(key); + return true; case "maps\\walls_and_floors": // Wallpaper - return Wallpaper.wallpaperTexture = content.Load(key); + Wallpaper.wallpaperTexture = content.Load(key); + return true; /**** ** Content\Minigames @@ -315,35 +393,43 @@ namespace StardewModdingAPI.Metadata ** Content\TileSheets ****/ case "tilesheets\\animations": // Game1.loadContent - return Game1.animations = content.Load(key); + Game1.animations = content.Load(key); + return true; case "tilesheets\\buffsicons": // Game1.loadContent - return Game1.buffsIcons = content.Load(key); + Game1.buffsIcons = content.Load(key); + return true; case "tilesheets\\bushes": // new Bush() reflection.GetField>(typeof(Bush), "texture").SetValue(new Lazy(() => content.Load(key))); return true; case "tilesheets\\craftables": // Game1.loadContent - return Game1.bigCraftableSpriteSheet = content.Load(key); + Game1.bigCraftableSpriteSheet = content.Load(key); + return true; case "tilesheets\\fruittrees": // FruitTree - return FruitTree.texture = content.Load(key); + FruitTree.texture = content.Load(key); + return true; /**** ** Content\TerrainFeatures ****/ case "terrainfeatures\\flooring": // Flooring - return Flooring.floorsTexture = content.Load(key); + Flooring.floorsTexture = content.Load(key); + return true; case "terrainfeatures\\hoedirt": // from HoeDirt - return HoeDirt.lightTexture = content.Load(key); + HoeDirt.lightTexture = content.Load(key); + return true; case "terrainfeatures\\hoedirtdark": // from HoeDirt - return HoeDirt.darkTexture = content.Load(key); + HoeDirt.darkTexture = content.Load(key); + return true; case "terrainfeatures\\hoedirtsnow": // from HoeDirt - return HoeDirt.snowTexture = content.Load(key); + HoeDirt.snowTexture = content.Load(key); + return true; case "terrainfeatures\\mushroom_tree": // from Tree return this.ReloadTreeTextures(content, key, Tree.mushroomTree); @@ -376,15 +462,9 @@ namespace StardewModdingAPI.Metadata if (this.IsInFolder(key, "Buildings")) return this.ReloadBuildings(content, key); - if (this.IsInFolder(key, "Characters") || this.IsInFolder(key, "Characters\\Monsters")) - return this.ReloadNpcSprites(content, key); - if (this.KeyStartsWith(key, "LooseSprites\\Fence")) 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); @@ -536,46 +616,65 @@ namespace StardewModdingAPI.Metadata /// Reload the sprites for matching NPCs. /// The content manager through which to reload the asset. - /// The asset key to reload. - /// Returns whether any textures were reloaded. - private bool ReloadNpcSprites(LocalizedContentManager content, string key) + /// The asset keys to reload. + /// Returns the number of reloaded assets. + private int ReloadNpcSprites(LocalizedContentManager content, IEnumerable keys) { // get NPCs + HashSet lookup = new HashSet(keys, StringComparer.InvariantCultureIgnoreCase); NPC[] characters = this.GetCharacters() - .Where(npc => npc.Sprite != null && this.GetNormalisedPath(npc.Sprite.textureName.Value) == key) + .Where(npc => npc.Sprite != null && lookup.Contains(this.GetNormalisedPath(npc.Sprite.textureName.Value))) .ToArray(); if (!characters.Any()) - return false; + return 0; - // update portrait - Texture2D texture = content.Load(key); - foreach (NPC character in characters) - this.SetSpriteTexture(character.Sprite, texture); - return true; + // update sprite + int reloaded = 0; + foreach (NPC npc in characters) + { + this.SetSpriteTexture(npc.Sprite, content.Load(npc.Sprite.textureName.Value)); + reloaded++; + } + + return reloaded; } /// Reload the portraits for matching NPCs. /// The content manager through which to reload the asset. - /// The asset key to reload. - /// Returns whether any textures were reloaded. - private bool ReloadNpcPortraits(LocalizedContentManager content, string key) + /// The asset key to reload. + /// Returns the number of reloaded assets. + private int ReloadNpcPortraits(LocalizedContentManager content, IEnumerable keys) { // get NPCs - NPC[] villagers = this.GetCharacters() - .Where(npc => npc.isVillager() && this.GetNormalisedPath($"Portraits\\{this.Reflection.GetMethod(npc, "getTextureName").Invoke()}") == key) + HashSet lookup = new HashSet(keys, StringComparer.InvariantCultureIgnoreCase); + var villagers = + ( + from npc in this.GetCharacters() + where npc.isVillager() + let textureKey = this.GetNormalisedPath($"Portraits\\{this.getTextureName(npc)}") + where lookup.Contains(textureKey) + select new { npc, textureKey } + ) .ToArray(); if (!villagers.Any()) - return false; + return 0; // update portrait - Texture2D texture = content.Load(key); - foreach (NPC villager in villagers) + int reloaded = 0; + foreach (var entry in villagers) { - villager.resetPortrait(); - villager.Portrait = texture; + entry.npc.resetPortrait(); + entry.npc.Portrait = content.Load(entry.textureKey); + reloaded++; } + return reloaded; + } - return true; + private string getTextureName(NPC npc) + { + string name = npc.Name; + string str = name == "Old Mariner" ? "Mariner" : (name == "Dwarf King" ? "DwarfKing" : (name == "Mister Qi" ? "MrQi" : (name == "???" ? "Monsters\\Shadow Guy" : name))); + return str; } /// Reload tree textures. -- cgit From 732d66f1fe9c697eadeb05e4e0e05ccc7f3f6794 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 17 May 2019 23:53:49 -0400 Subject: remove reflection no longer needed in newest SDV 1.4 build (#638) --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 47 +++++++++++++------------------ 1 file changed, 19 insertions(+), 28 deletions(-) (limited to 'src/SMAPI/Metadata') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index dbb27b14..4f8f1427 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reflection; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI.Framework.Reflection; using StardewValley; @@ -139,21 +138,9 @@ namespace StardewModdingAPI.Metadata { if (!string.IsNullOrWhiteSpace(location.mapPath.Value) && this.GetNormalisedPath(location.mapPath.Value) == key) { - // reload map data - this.Reflection.GetMethod(location, "reloadMap").Invoke(); - this.Reflection.GetMethod(location, "updateWarps").Invoke(); - - // reload doors - { - Type interiorDoorDictType = Type.GetType($"StardewValley.InteriorDoorDictionary, {Constants.GameAssemblyName}", throwOnError: true); - ConstructorInfo constructor = interiorDoorDictType.GetConstructor(new[] { typeof(GameLocation) }); - if (constructor == null) - throw new InvalidOperationException("Can't reset location doors: constructor not found for InteriorDoorDictionary type."); - object instance = constructor.Invoke(new object[] { location }); - - this.Reflection.GetField(location, "interiorDoors").SetValue(instance); - } - + location.reloadMap(); + location.updateWarps(); + this.Reflection.GetField(location, nameof(location.interiorDoors)).SetValue(new InteriorDoorDictionary(location)); anyChanged = true; } } @@ -371,21 +358,25 @@ namespace StardewModdingAPI.Metadata ** Content\Minigames ****/ case "minigames\\clouds": // TitleMenu - if (Game1.activeClickableMenu is TitleMenu) { - reflection.GetField(Game1.activeClickableMenu, "cloudsTexture").SetValue(content.Load(key)); - return true; + if (Game1.activeClickableMenu is TitleMenu titleMenu) + { + titleMenu.cloudsTexture = content.Load(key); + return true; + } } return false; case "minigames\\titlebuttons": // TitleMenu - if (Game1.activeClickableMenu is TitleMenu titleMenu) { - Texture2D texture = content.Load(key); - reflection.GetField(titleMenu, "titleButtonsTexture").SetValue(texture); - foreach (TemporaryAnimatedSprite bird in reflection.GetField>(titleMenu, "birds").GetValue()) - bird.texture = texture; - return true; + if (Game1.activeClickableMenu is TitleMenu titleMenu) + { + Texture2D texture = content.Load(key); + titleMenu.titleButtonsTexture = texture; + foreach (TemporaryAnimatedSprite bird in titleMenu.birds) + bird.texture = texture; + return true; + } } return false; @@ -401,7 +392,7 @@ namespace StardewModdingAPI.Metadata return true; case "tilesheets\\bushes": // new Bush() - reflection.GetField>(typeof(Bush), "texture").SetValue(new Lazy(() => content.Load(key))); + Bush.texture = new Lazy(() => content.Load(key)); return true; case "tilesheets\\craftables": // Game1.loadContent @@ -581,7 +572,7 @@ namespace StardewModdingAPI.Metadata // update fence textures foreach (Fence fence in fences) - this.Reflection.GetField>(fence, "fenceTexture").SetValue(new Lazy(fence.loadFenceTexture)); + fence.fenceTexture = new Lazy(fence.loadFenceTexture); return true; } @@ -746,7 +737,7 @@ namespace StardewModdingAPI.Metadata int lastScheduleTime = villager.Schedule.Keys.Where(p => p <= Game1.timeOfDay).OrderByDescending(p => p).FirstOrDefault(); if (lastScheduleTime != 0) { - this.Reflection.GetField(villager, "scheduleTimeToTry").SetValue(this.Reflection.GetField(typeof(NPC), "NO_TRY").GetValue()); // use time that's passed in to checkSchedule + villager.scheduleTimeToTry = NPC.NO_TRY; // use time that's passed in to checkSchedule villager.checkSchedule(lastScheduleTime); } } -- cgit From 24160cacdce0b2e31a3f7dc130fe84cb164bcf19 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 23 May 2019 14:56:44 -0400 Subject: fix tilesheets not seasonalised when a map is reloaded (#642) --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/SMAPI/Metadata') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 4f8f1427..71e51cea 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -139,6 +139,7 @@ namespace StardewModdingAPI.Metadata if (!string.IsNullOrWhiteSpace(location.mapPath.Value) && this.GetNormalisedPath(location.mapPath.Value) == key) { location.reloadMap(); + location.updateSeasonalTileSheets(); location.updateWarps(); this.Reflection.GetField(location, nameof(location.interiorDoors)).SetValue(new InteriorDoorDictionary(location)); anyChanged = true; -- cgit From f14260b3b4c0456da2cbf86259624dd723c7faf4 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 3 Jun 2019 23:22:53 -0400 Subject: fix typos --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 78 ++++++++++++++++--------------- 1 file changed, 40 insertions(+), 38 deletions(-) (limited to 'src/SMAPI/Metadata') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 71e51cea..bb269643 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -174,7 +174,7 @@ namespace StardewModdingAPI.Metadata /**** ** Content\Characters\Farmer ****/ - case "characters\\farmer\\accessories": // Game1.loadContent + case "characters\\farmer\\accessories": // Game1.LoadContent FarmerRenderer.accessoriesTexture = content.Load(key); return true; @@ -190,26 +190,26 @@ namespace StardewModdingAPI.Metadata Game1.player.FarmerRenderer = new FarmerRenderer(key, Game1.player); return true; - case "characters\\farmer\\hairstyles": // Game1.loadContent + case "characters\\farmer\\hairstyles": // Game1.LoadContent FarmerRenderer.hairStylesTexture = content.Load(key); return true; - case "characters\\farmer\\hats": // Game1.loadContent + case "characters\\farmer\\hats": // Game1.LoadContent FarmerRenderer.hatsTexture = content.Load(key); return true; - case "characters\\farmer\\shirts": // Game1.loadContent + case "characters\\farmer\\shirts": // Game1.LoadContent FarmerRenderer.shirtsTexture = content.Load(key); return true; /**** ** Content\Data ****/ - case "data\\achievements": // Game1.loadContent + case "data\\achievements": // Game1.LoadContent Game1.achievements = content.Load>(key); return true; - case "data\\bigcraftablesinformation": // Game1.loadContent + case "data\\bigcraftablesinformation": // Game1.LoadContent Game1.bigCraftablesInformation = content.Load>(key); return true; @@ -224,111 +224,111 @@ namespace StardewModdingAPI.Metadata case "data\\npcdispositions": // NPC constructor return this.ReloadNpcDispositions(content, key); - case "data\\npcgifttastes": // Game1.loadContent + case "data\\npcgifttastes": // Game1.LoadContent Game1.NPCGiftTastes = content.Load>(key); return true; - case "data\\objectinformation": // Game1.loadContent + case "data\\objectinformation": // Game1.LoadContent Game1.objectInformation = content.Load>(key); return true; /**** ** Content\Fonts ****/ - case "fonts\\spritefont1": // Game1.loadContent + case "fonts\\spritefont1": // Game1.LoadContent Game1.dialogueFont = content.Load(key); return true; - case "fonts\\smallfont": // Game1.loadContent + case "fonts\\smallfont": // Game1.LoadContent Game1.smallFont = content.Load(key); return true; - case "fonts\\tinyfont": // Game1.loadContent + case "fonts\\tinyfont": // Game1.LoadContent Game1.tinyFont = content.Load(key); return true; - case "fonts\\tinyfontborder": // Game1.loadContent + case "fonts\\tinyfontborder": // Game1.LoadContent Game1.tinyFontBorder = content.Load(key); return true; /**** - ** Content\Lighting + ** Content\LooseSprites\Lighting ****/ - case "loosesprites\\lighting\\greenlight": // Game1.loadContent + case "loosesprites\\lighting\\greenlight": // Game1.LoadContent Game1.cauldronLight = content.Load(key); return true; - case "loosesprites\\lighting\\indoorwindowlight": // Game1.loadContent + case "loosesprites\\lighting\\indoorwindowlight": // Game1.LoadContent Game1.indoorWindowLight = content.Load(key); return true; - case "loosesprites\\lighting\\lantern": // Game1.loadContent + case "loosesprites\\lighting\\lantern": // Game1.LoadContent Game1.lantern = content.Load(key); return true; - case "loosesprites\\lighting\\sconcelight": // Game1.loadContent + case "loosesprites\\lighting\\sconcelight": // Game1.LoadContent Game1.sconceLight = content.Load(key); return true; - case "loosesprites\\lighting\\windowlight": // Game1.loadContent + case "loosesprites\\lighting\\windowlight": // Game1.LoadContent Game1.windowLight = content.Load(key); return true; /**** ** Content\LooseSprites ****/ - case "loosesprites\\controllermaps": // Game1.loadContent + case "loosesprites\\controllermaps": // Game1.LoadContent Game1.controllerMaps = content.Load(key); return true; - case "loosesprites\\cursors": // Game1.loadContent + case "loosesprites\\cursors": // Game1.LoadContent Game1.mouseCursors = content.Load(key); return true; - case "loosesprites\\daybg": // Game1.loadContent + case "loosesprites\\daybg": // Game1.LoadContent Game1.daybg = content.Load(key); return true; - case "loosesprites\\font_bold": // Game1.loadContent + case "loosesprites\\font_bold": // Game1.LoadContent SpriteText.spriteTexture = content.Load(key); return true; - case "loosesprites\\font_colored": // Game1.loadContent + case "loosesprites\\font_colored": // Game1.LoadContent SpriteText.coloredTexture = content.Load(key); return true; - case "loosesprites\\nightbg": // Game1.loadContent + case "loosesprites\\nightbg": // Game1.LoadContent Game1.nightbg = content.Load(key); return true; - case "loosesprites\\shadow": // Game1.loadContent + case "loosesprites\\shadow": // Game1.LoadContent Game1.shadowTexture = content.Load(key); return true; /**** ** Content\Critters ****/ - case "tilesheets\\crops": // Game1.loadContent + case "tilesheets\\crops": // Game1.LoadContent Game1.cropSpriteSheet = content.Load(key); return true; - case "tilesheets\\debris": // Game1.loadContent + case "tilesheets\\debris": // Game1.LoadContent Game1.debrisSpriteSheet = content.Load(key); return true; - case "tilesheets\\emotes": // Game1.loadContent + case "tilesheets\\emotes": // Game1.LoadContent Game1.emoteSpriteSheet = content.Load(key); return true; - case "tilesheets\\furniture": // Game1.loadContent + case "tilesheets\\furniture": // Game1.LoadContent Furniture.furnitureTexture = content.Load(key); return true; - case "tilesheets\\projectiles": // Game1.loadContent + case "tilesheets\\projectiles": // Game1.LoadContent Projectile.projectileSheet = content.Load(key); return true; - case "tilesheets\\rain": // Game1.loadContent + case "tilesheets\\rain": // Game1.LoadContent Game1.rainTexture = content.Load(key); return true; @@ -336,18 +336,18 @@ namespace StardewModdingAPI.Metadata Game1.ResetToolSpriteSheet(); return true; - case "tilesheets\\weapons": // Game1.loadContent + case "tilesheets\\weapons": // Game1.LoadContent Tool.weaponsTexture = content.Load(key); return true; /**** ** Content\Maps ****/ - case "maps\\menutiles": // Game1.loadContent + case "maps\\menutiles": // Game1.LoadContent Game1.menuTexture = content.Load(key); return true; - case "maps\\springobjects": // Game1.loadContent + case "maps\\springobjects": // Game1.LoadContent Game1.objectSpriteSheet = content.Load(key); return true; @@ -384,11 +384,11 @@ namespace StardewModdingAPI.Metadata /**** ** Content\TileSheets ****/ - case "tilesheets\\animations": // Game1.loadContent + case "tilesheets\\animations": // Game1.LoadContent Game1.animations = content.Load(key); return true; - case "tilesheets\\buffsicons": // Game1.loadContent + case "tilesheets\\buffsicons": // Game1.LoadContent Game1.buffsIcons = content.Load(key); return true; @@ -396,7 +396,7 @@ namespace StardewModdingAPI.Metadata Bush.texture = new Lazy(() => content.Load(key)); return true; - case "tilesheets\\craftables": // Game1.loadContent + case "tilesheets\\craftables": // Game1.LoadContent Game1.bigCraftableSpriteSheet = content.Load(key); return true; @@ -483,7 +483,9 @@ namespace StardewModdingAPI.Metadata where TAnimal : NPC { // find matches - TAnimal[] animals = this.GetCharacters().OfType().ToArray(); + TAnimal[] animals = this.GetCharacters() + .OfType() + .ToArray(); if (!animals.Any()) return false; -- cgit From 31c882c8cea66bbd2805cc5aab11abbce248782c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 13 Jun 2019 19:35:51 -0400 Subject: fix map reloads not updating door warps (#643) --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'src/SMAPI/Metadata') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index bb269643..186cd4ee 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI.Framework.Reflection; using StardewValley; @@ -14,6 +15,7 @@ using StardewValley.Objects; using StardewValley.Projectiles; using StardewValley.TerrainFeatures; using xTile; +using xTile.ObjectModel; using xTile.Tiles; namespace StardewModdingAPI.Metadata @@ -138,10 +140,37 @@ namespace StardewModdingAPI.Metadata { if (!string.IsNullOrWhiteSpace(location.mapPath.Value) && this.GetNormalisedPath(location.mapPath.Value) == key) { + // general updates location.reloadMap(); location.updateSeasonalTileSheets(); location.updateWarps(); - this.Reflection.GetField(location, nameof(location.interiorDoors)).SetValue(new InteriorDoorDictionary(location)); + + // update interior doors + location.interiorDoors.Clear(); + foreach (var entry in new InteriorDoorDictionary(location)) + location.interiorDoors.Add(entry); + + // update doors (derived from GameLocation.loadObjects) + location.doors.Clear(); + for (int x = 0; x < location.map.Layers[0].LayerWidth; ++x) + { + for (int y = 0; y < location.map.Layers[0].LayerHeight; ++y) + { + if (location.map.GetLayer("Buildings").Tiles[x, y] != null) + { + location.map.GetLayer("Buildings").Tiles[x, y].Properties.TryGetValue("Action", out PropertyValue action); + if (action != null && action.ToString().Contains("Warp")) + { + string[] strArray = action.ToString().Split(' '); + if (strArray[0] == "WarpCommunityCenter") + location.doors.Add(new Point(x, y), "CommunityCenter"); + else if ((location.Name != "Mountain" || x != 8 || y != 20) && strArray.Length > 2) + location.doors.Add(new Point(x, y), strArray[3]); + } + } + } + } + anyChanged = true; } } -- cgit From 660e8087a1885fcf48b7d34b4ec726eda0e732d1 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 16 Jun 2019 23:16:35 -0400 Subject: update for location change in SDV 1.4 (#638) --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) (limited to 'src/SMAPI/Metadata') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 186cd4ee..9e84c67f 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI.Framework.Reflection; using StardewValley; @@ -15,7 +14,6 @@ using StardewValley.Objects; using StardewValley.Projectiles; using StardewValley.TerrainFeatures; using xTile; -using xTile.ObjectModel; using xTile.Tiles; namespace StardewModdingAPI.Metadata @@ -150,26 +148,9 @@ namespace StardewModdingAPI.Metadata foreach (var entry in new InteriorDoorDictionary(location)) location.interiorDoors.Add(entry); - // update doors (derived from GameLocation.loadObjects) + // update doors location.doors.Clear(); - for (int x = 0; x < location.map.Layers[0].LayerWidth; ++x) - { - for (int y = 0; y < location.map.Layers[0].LayerHeight; ++y) - { - if (location.map.GetLayer("Buildings").Tiles[x, y] != null) - { - location.map.GetLayer("Buildings").Tiles[x, y].Properties.TryGetValue("Action", out PropertyValue action); - if (action != null && action.ToString().Contains("Warp")) - { - string[] strArray = action.ToString().Split(' '); - if (strArray[0] == "WarpCommunityCenter") - location.doors.Add(new Point(x, y), "CommunityCenter"); - else if ((location.Name != "Mountain" || x != 8 || y != 20) && strArray.Length > 2) - location.doors.Add(new Point(x, y), strArray[3]); - } - } - } - } + location.updateDoors(); anyChanged = true; } -- cgit From e2f545484e1a63d55154e2b6a924dfb6d94f7a5a Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 12 Jul 2019 20:51:46 -0400 Subject: add asset propagation for critter textures (#652) --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 34 ++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'src/SMAPI/Metadata') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 9e84c67f..b000d503 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -316,8 +316,12 @@ namespace StardewModdingAPI.Metadata return true; /**** - ** Content\Critters + ** Content\TileSheets ****/ + case "tilesheets\\critters": // Critter constructor + this.ReloadCritterTextures(content, key); + return true; + case "tilesheets\\crops": // Game1.LoadContent Game1.cropSpriteSheet = content.Load(key); return true; @@ -562,6 +566,34 @@ namespace StardewModdingAPI.Metadata return false; } + /// Reload critter textures. + /// The content manager through which to reload the asset. + /// The asset key to reload. + /// Returns the number of reloaded assets. + private int ReloadCritterTextures(LocalizedContentManager content, string key) + { + // get critters + Critter[] critters = + ( + from location in this.GetLocations() + let locCritters = this.Reflection.GetField>(location, "critters").GetValue() + where locCritters != null + from Critter critter in locCritters + where this.GetNormalisedPath(critter.sprite.textureName) == key + select critter + ) + .ToArray(); + if (!critters.Any()) + return 0; + + // update sprites + Texture2D texture = content.Load(key); + foreach (var entry in critters) + this.SetSpriteTexture(entry.sprite, texture); + + return critters.Length; + } + /// Reload the sprites for a fence type. /// The asset key to reload. /// Returns whether any textures were reloaded. -- cgit From 1053232c2039a2815baf2cfa99fe8c554d1350a9 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 14 Jul 2019 14:55:31 -0400 Subject: add asset propagation for DayTimeMoneyBox buttons --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/SMAPI/Metadata') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index b000d503..3fbca04a 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -293,6 +293,11 @@ namespace StardewModdingAPI.Metadata case "loosesprites\\cursors": // Game1.LoadContent Game1.mouseCursors = content.Load(key); + foreach (DayTimeMoneyBox menu in Game1.onScreenMenus.OfType()) + { + foreach (ClickableTextureComponent button in new[] { menu.questButton, menu.zoomInButton, menu.zoomOutButton }) + button.texture = Game1.mouseCursors; + } return true; case "loosesprites\\daybg": // Game1.LoadContent -- cgit From fd77ae93d59222d70c86aebfc044f3af11063372 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 9 Aug 2019 01:18:05 -0400 Subject: fix typos and inconsistent spelling --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 42 +++++++++++++++---------------- src/SMAPI/Metadata/InstructionMetadata.cs | 10 ++++---- 2 files changed, 26 insertions(+), 26 deletions(-) (limited to 'src/SMAPI/Metadata') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 3fbca04a..b72590fd 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -24,8 +24,8 @@ namespace StardewModdingAPI.Metadata /********* ** Fields *********/ - /// Normalises an asset key to match the cache key. - private readonly Func GetNormalisedPath; + /// Normalizes an asset key to match the cache key. + private readonly Func GetNormalizedPath; /// Simplifies access to private game code. private readonly Reflector Reflection; @@ -33,7 +33,7 @@ namespace StardewModdingAPI.Metadata /// Encapsulates monitoring and logging. private readonly IMonitor Monitor; - /// Optimised bucket categories for batch reloading assets. + /// Optimized bucket categories for batch reloading assets. private enum AssetBucket { /// NPC overworld sprites. @@ -50,13 +50,13 @@ namespace StardewModdingAPI.Metadata /********* ** Public methods *********/ - /// Initialise the core asset data. - /// Normalises an asset key to match the cache key. + /// Initialize the core asset data. + /// Normalizes an asset key to match the cache key. /// Simplifies access to private code. /// Encapsulates monitoring and logging. - public CoreAssetPropagator(Func getNormalisedPath, Reflector reflection, IMonitor monitor) + public CoreAssetPropagator(Func getNormalizedPath, Reflector reflection, IMonitor monitor) { - this.GetNormalisedPath = getNormalisedPath; + this.GetNormalizedPath = getNormalizedPath; this.Reflection = reflection; this.Monitor = monitor; } @@ -67,7 +67,7 @@ namespace StardewModdingAPI.Metadata /// Returns the number of reloaded assets. public int Propagate(LocalizedContentManager content, IDictionary assets) { - // group into optimised lists + // group into optimized lists var buckets = assets.GroupBy(p => { if (this.IsInFolder(p.Key, "Characters") || this.IsInFolder(p.Key, "Characters\\Monsters")) @@ -112,7 +112,7 @@ namespace StardewModdingAPI.Metadata /// Returns whether an asset was loaded. The return value may be true or false, or a non-null value for true. private bool PropagateOther(LocalizedContentManager content, string key, Type type) { - key = this.GetNormalisedPath(key); + key = this.GetNormalizedPath(key); /**** ** Special case: current map tilesheet @@ -123,7 +123,7 @@ namespace StardewModdingAPI.Metadata { foreach (TileSheet tilesheet in Game1.currentLocation.map.TileSheets) { - if (this.GetNormalisedPath(tilesheet.ImageSource) == key) + if (this.GetNormalizedPath(tilesheet.ImageSource) == key) Game1.mapDisplayDevice.LoadTileSheet(tilesheet); } } @@ -136,7 +136,7 @@ namespace StardewModdingAPI.Metadata bool anyChanged = false; foreach (GameLocation location in this.GetLocations()) { - if (!string.IsNullOrWhiteSpace(location.mapPath.Value) && this.GetNormalisedPath(location.mapPath.Value) == key) + if (!string.IsNullOrWhiteSpace(location.mapPath.Value) && this.GetNormalizedPath(location.mapPath.Value) == key) { // general updates location.reloadMap(); @@ -162,7 +162,7 @@ namespace StardewModdingAPI.Metadata ** Propagate by key ****/ Reflector reflection = this.Reflection; - switch (key.ToLower().Replace("/", "\\")) // normalised key so we can compare statically + switch (key.ToLower().Replace("/", "\\")) // normalized key so we can compare statically { /**** ** Animals @@ -584,7 +584,7 @@ namespace StardewModdingAPI.Metadata let locCritters = this.Reflection.GetField>(location, "critters").GetValue() where locCritters != null from Critter critter in locCritters - where this.GetNormalisedPath(critter.sprite.textureName) == key + where this.GetNormalizedPath(critter.sprite.textureName) == key select critter ) .ToArray(); @@ -664,7 +664,7 @@ namespace StardewModdingAPI.Metadata // get NPCs HashSet lookup = new HashSet(keys, StringComparer.InvariantCultureIgnoreCase); NPC[] characters = this.GetCharacters() - .Where(npc => npc.Sprite != null && lookup.Contains(this.GetNormalisedPath(npc.Sprite.textureName.Value))) + .Where(npc => npc.Sprite != null && lookup.Contains(this.GetNormalizedPath(npc.Sprite.textureName.Value))) .ToArray(); if (!characters.Any()) return 0; @@ -692,7 +692,7 @@ namespace StardewModdingAPI.Metadata ( from npc in this.GetCharacters() where npc.isVillager() - let textureKey = this.GetNormalisedPath($"Portraits\\{this.getTextureName(npc)}") + let textureKey = this.GetNormalizedPath($"Portraits\\{this.getTextureName(npc)}") where lookup.Contains(textureKey) select new { npc, textureKey } ) @@ -852,17 +852,17 @@ namespace StardewModdingAPI.Metadata } } - /// Get whether a key starts with a substring after the substring is normalised. + /// Get whether a key starts with a substring after the substring is normalized. /// The key to check. - /// The substring to normalise and find. + /// The substring to normalize and find. private bool KeyStartsWith(string key, string rawSubstring) { - return key.StartsWith(this.GetNormalisedPath(rawSubstring), StringComparison.InvariantCultureIgnoreCase); + return key.StartsWith(this.GetNormalizedPath(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. + /// Get whether a normalized asset key is in the given folder. + /// The normalized asset key (like Animals/cat). + /// The key folder (like Animals); doesn't need to be normalized. /// Whether to return true if the key is inside a subfolder of the . private bool IsInFolder(string key, string folder, bool allowSubfolders = false) { diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs index 72410d41..95482708 100644 --- a/src/SMAPI/Metadata/InstructionMetadata.cs +++ b/src/SMAPI/Metadata/InstructionMetadata.cs @@ -48,11 +48,11 @@ namespace StardewModdingAPI.Metadata ****/ yield return new TypeFinder("Harmony.HarmonyInstance", InstructionHandleResult.DetectedGamePatch); yield return new TypeFinder("System.Runtime.CompilerServices.CallSite", InstructionHandleResult.DetectedDynamic); - yield return new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.serializer), InstructionHandleResult.DetectedSaveSerialiser); - yield return new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.farmerSerializer), InstructionHandleResult.DetectedSaveSerialiser); - yield return new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.locationSerializer), InstructionHandleResult.DetectedSaveSerialiser); - yield return new EventFinder(typeof(ISpecialisedEvents).FullName, nameof(ISpecialisedEvents.UnvalidatedUpdateTicked), InstructionHandleResult.DetectedUnvalidatedUpdateTick); - yield return new EventFinder(typeof(ISpecialisedEvents).FullName, nameof(ISpecialisedEvents.UnvalidatedUpdateTicking), InstructionHandleResult.DetectedUnvalidatedUpdateTick); + yield return new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.serializer), InstructionHandleResult.DetectedSaveSerializer); + yield return new FieldFinder(type