private void injectCharactersFarmerHats(IAssetData asset)
        {
            var       oldTex = asset.AsImage().Data;
            Texture2D newTex = new Texture2D(Game1.graphics.GraphicsDevice, oldTex.Width, Math.Max(oldTex.Height, 4096));

            asset.ReplaceWith(newTex);
            asset.AsImage().PatchImage(oldTex);
            Log.trace($"Hats are now ({oldTex.Width}, {Math.Max(oldTex.Height, 4096)})");

            foreach (var hat in Mod.instance.hats)
            {
                try
                {
                    Log.verbose($"Injecting {hat.Name} sprites @ {hatRect(hat.GetHatId())}");
                    asset.AsImage().PatchExtendedTileSheet(hat.texture, null, hatRect(hat.GetHatId()));

                    var rect   = hatRect(hat.GetHatId());
                    var target = TileSheetExtensions.GetAdjustedTileSheetTarget(asset.AssetName, rect);
                    int ts     = target.TileSheet;
                    hat.tilesheet  = asset.AssetName + (ts == 0 ? "" : (ts + 1).ToString());
                    hat.tilesheetX = rect.X;
                    hat.tilesheetY = target.Y;
                }
                catch (Exception e)
                {
                    Log.error($"Exception injecting sprite for {hat.Name}: {e}");
                }
            }
        }
        private void injectTileSheetsFruitTrees(IAssetData asset)
        {
            var       oldTex = asset.AsImage().Data;
            Texture2D newTex = new Texture2D(Game1.graphics.GraphicsDevice, oldTex.Width, Math.Max(oldTex.Height, 4096));

            asset.ReplaceWith(newTex);
            asset.AsImage().PatchImage(oldTex);

            foreach (var fruitTree in Mod.instance.fruitTrees)
            {
                try
                {
                    Log.verbose($"Injecting {fruitTree.Name} fruit tree images @ {fruitTreeRect(fruitTree.GetFruitTreeIndex())}");
                    asset.AsImage().PatchExtendedTileSheet(fruitTree.texture, null, fruitTreeRect(fruitTree.GetFruitTreeIndex()));

                    var rect = fruitTreeRect(fruitTree.GetFruitTreeIndex());
                    int ts   = TileSheetExtensions.GetAdjustedTileSheetTarget(asset.AssetName, rect).TileSheet;
                    fruitTree.tilesheet  = asset.AssetName + (ts == 0 ? "" : (ts + 1).ToString());
                    fruitTree.tilesheetX = rect.X;
                    fruitTree.tilesheetY = rect.Y;
                }
                catch (Exception e)
                {
                    Log.error($"Exception injecting fruit tree sprite for {fruitTree.Name}: {e}");
                }
            }
        }
        private void injectTileSheetsCrops(IAssetData asset)
        {
            var       oldTex = asset.AsImage().Data;
            Texture2D newTex = new Texture2D(Game1.graphics.GraphicsDevice, oldTex.Width, Math.Max(oldTex.Height, 4096));

            asset.ReplaceWith(newTex);
            asset.AsImage().PatchImage(oldTex);

            foreach (var crop in Mod.instance.crops)
            {
                try
                {
                    Log.verbose($"Injecting {crop.Name} crop images @ {cropRect(crop.GetCropSpriteIndex())}");
                    asset.AsImage().PatchExtendedTileSheet(crop.texture, null, cropRect(crop.GetCropSpriteIndex()));

                    var rect   = cropRect(crop.GetCropSpriteIndex());
                    var target = TileSheetExtensions.GetAdjustedTileSheetTarget(asset.AssetName, rect);
                    int ts     = target.TileSheet;
                    crop.tilesheet  = asset.AssetName + (ts == 0 ? "" : (ts + 1).ToString());
                    crop.tilesheetX = rect.X;
                    crop.tilesheetY = target.Y;
                }
                catch (Exception e)
                {
                    Log.error($"Exception injecting crop sprite for {crop.Name}: {e}");
                }
            }
        }
        private void injectMapsSpringobjects(IAssetData asset)
        {
            var oldTex = asset.AsImage().Data;

            asset.AsImage().ExtendImage(oldTex.Width, 4096);
            //Texture2D newTex = new Texture2D(Game1.graphics.GraphicsDevice, oldTex.Width, Math.Max(oldTex.Height, 4096));
            //asset.ReplaceWith(newTex);
            //asset.AsImage().PatchImage(oldTex);

            foreach (var obj in Mod.instance.objects)
            {
                try
                {
                    Log.verbose($"Injecting {obj.Name} sprites @ {objectRect(obj.GetObjectId())}");
                    asset.AsImage().PatchExtendedTileSheet(obj.texture, null, objectRect(obj.GetObjectId()));
                    if (obj.IsColored)
                    {
                        Log.verbose($"Injecting {obj.Name} color sprites @ {objectRect(obj.GetObjectId() + 1)}");
                        asset.AsImage().PatchExtendedTileSheet(obj.textureColor, null, objectRect(obj.GetObjectId() + 1));
                    }

                    var rect   = objectRect(obj.GetObjectId());
                    var target = TileSheetExtensions.GetAdjustedTileSheetTarget(asset.AssetName, rect);
                    int ts     = target.TileSheet;
                    obj.tilesheet  = asset.AssetName + (ts == 0 ? "" : (ts + 1).ToString());
                    obj.tilesheetX = rect.X;
                    obj.tilesheetY = target.Y;
                }
                catch (Exception e)
                {
                    Log.error($"Exception injecting sprite for {obj.Name}: {e}");
                }
            }

            foreach (var boots in Mod.instance.bootss)
            {
                try
                {
                    Log.verbose($"Injecting {boots.Name} sprites @ {objectRect(boots.GetObjectId())}");
                    asset.AsImage().PatchExtendedTileSheet(boots.texture, null, objectRect(boots.GetObjectId()));

                    var rect   = objectRect(boots.GetObjectId());
                    var target = TileSheetExtensions.GetAdjustedTileSheetTarget(asset.AssetName, rect);
                    int ts     = target.TileSheet;
                    boots.tilesheet  = asset.AssetName + (ts == 0 ? "" : (ts + 1).ToString());
                    boots.tilesheetX = rect.X;
                    boots.tilesheetY = target.Y;
                }
                catch (Exception e)
                {
                    Log.error($"Exception injecting sprite for {boots.Name}: {e}");
                }
            }
        }
        private static void FixTilesheetReference(ref Texture2D tex, ref Rectangle sourceRect)
        {
            if (sourceRect.Y + sourceRect.Height < 4096 && tex != StardewValley.FarmerRenderer.pantsTexture)
            {
                return;
            }

            var target = TileSheetExtensions.GetAdjustedTileSheetTarget(tex, sourceRect);

            tex          = TileSheetExtensions.GetTileSheet(tex, target.TileSheet);
            sourceRect.Y = target.Y;
        }
        public static void FixTilesheetReference(ref Texture2D tex, ref Rectangle sourceRect)
        {
            if (sourceRect.Y + sourceRect.Height < 4096)
            {
                return;
            }

            var target = TileSheetExtensions.GetAdjustedTileSheetTarget(tex, sourceRect);

            tex          = TileSheetExtensions.GetTileSheet(tex, target.TileSheet);
            sourceRect.Y = target.Y;
        }
        private void injectTileSheetsCraftables(IAssetData asset)
        {
            var       oldTex = asset.AsImage().Data;
            Texture2D newTex = new Texture2D(Game1.graphics.GraphicsDevice, oldTex.Width, Math.Max(oldTex.Height, 4096));

            asset.ReplaceWith(newTex);
            asset.AsImage().PatchImage(oldTex);
            Log.trace($"Big craftables are now ({oldTex.Width}, {Math.Max(oldTex.Height, 4096)})");

            foreach (var big in Mod.instance.bigCraftables)
            {
                try
                {
                    Log.verbose($"Injecting {big.Name} sprites @ {bigCraftableRect(big.GetCraftableId())}");
                    asset.AsImage().PatchExtendedTileSheet(big.texture, null, bigCraftableRect(big.GetCraftableId()));
                    if (big.ReserveExtraIndexCount > 0)
                    {
                        for (int i = 0; i < big.ReserveExtraIndexCount; ++i)
                        {
                            Log.verbose($"Injecting {big.Name} reserved extra sprite {i + 1} @ {bigCraftableRect(big.GetCraftableId() + i + 1)}");
                            asset.AsImage().PatchExtendedTileSheet(big.extraTextures[i], null, bigCraftableRect(big.GetCraftableId() + i + 1));
                        }
                    }

                    var rect = bigCraftableRect(big.GetCraftableId());
                    int ts   = TileSheetExtensions.GetAdjustedTileSheetTarget(asset.AssetName, rect).TileSheet;
                    big.tilesheet  = asset.AssetName + (ts == 0 ? "" : (ts + 1).ToString());
                    big.tilesheetX = rect.X;
                    big.tilesheetY = rect.Y;
                }
                catch (Exception e)
                {
                    Log.error($"Exception injecting sprite for {big.Name}: {e}");
                }
            }
        }
Exemple #8
0
        public void Edit <T>(IAssetData asset)
        {
            if (asset.AssetNameEquals("Data\\ObjectInformation"))
            {
                var data = asset.AsDictionary <int, string>().Data;
                foreach (var obj in Mod.instance.objects)
                {
                    try
                    {
                        Log.verbose($"Injecting to objects: {obj.GetObjectId()}: {obj.GetObjectInformation()}");
                        data.Add(obj.GetObjectId(), obj.GetObjectInformation());
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting object information for {obj.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("Data\\ObjectContextTags"))
            {
                var data = asset.AsDictionary <string, string>().Data;
                foreach (var obj in Mod.instance.objects)
                {
                    try
                    {
                        string tags = string.Join(", ", obj.ContextTags);
                        Log.verbose($"Injecting to object context tags: {obj.Name}: {tags}");
                        if (data.ContainsKey(obj.Name) && data[obj.Name] == "")
                        {
                            data[obj.Name] = tags;
                        }
                        else
                        {
                            data.Add(obj.Name, tags);
                        }
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting object context tags for {obj.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("Data\\Crops"))
            {
                var data = asset.AsDictionary <int, string>().Data;
                foreach (var crop in Mod.instance.crops)
                {
                    try
                    {
                        Log.verbose($"Injecting to crops: {crop.GetSeedId()}: {crop.GetCropInformation()}");
                        data.Add(crop.GetSeedId(), crop.GetCropInformation());
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting crop for {crop.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("Data\\fruitTrees"))
            {
                var data = asset.AsDictionary <int, string>().Data;
                foreach (var fruitTree in Mod.instance.fruitTrees)
                {
                    try
                    {
                        Log.verbose($"Injecting to fruit trees: {fruitTree.GetSaplingId()}: {fruitTree.GetFruitTreeInformation()}");
                        data.Add(fruitTree.GetSaplingId(), fruitTree.GetFruitTreeInformation());
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting fruit tree for {fruitTree.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("Data\\CookingRecipes"))
            {
                var data = asset.AsDictionary <string, string>().Data;
                foreach (var obj in Mod.instance.objects)
                {
                    try
                    {
                        if (obj.Recipe == null)
                        {
                            continue;
                        }
                        if (obj.Category != ObjectData.Category_.Cooking)
                        {
                            continue;
                        }
                        Log.verbose($"Injecting to cooking recipes: {obj.Name}: {obj.Recipe.GetRecipeString(obj)}");
                        data.Add(obj.Name, obj.Recipe.GetRecipeString(obj));
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting cooking recipe for {obj.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("Data\\CraftingRecipes"))
            {
                var data = asset.AsDictionary <string, string>().Data;
                foreach (var obj in Mod.instance.objects)
                {
                    try
                    {
                        if (obj.Recipe == null)
                        {
                            continue;
                        }
                        if (obj.Category == ObjectData.Category_.Cooking)
                        {
                            continue;
                        }
                        Log.verbose($"Injecting to crafting recipes: {obj.Name}: {obj.Recipe.GetRecipeString(obj)}");
                        data.Add(obj.Name, obj.Recipe.GetRecipeString(obj));
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting crafting recipe for {obj.Name}: {e}");
                    }
                }
                foreach (var big in Mod.instance.bigCraftables)
                {
                    try
                    {
                        if (big.Recipe == null)
                        {
                            continue;
                        }
                        Log.verbose($"Injecting to crafting recipes: {big.Name}: {big.Recipe.GetRecipeString(big)}");
                        data.Add(big.Name, big.Recipe.GetRecipeString(big));
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting crafting recipe for {big.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("Data\\BigCraftablesInformation"))
            {
                var data = asset.AsDictionary <int, string>().Data;
                foreach (var big in Mod.instance.bigCraftables)
                {
                    try
                    {
                        Log.verbose($"Injecting to big craftables: {big.GetCraftableId()}: {big.GetCraftableInformation()}");
                        data.Add(big.GetCraftableId(), big.GetCraftableInformation());
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting object information for {big.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("Data\\hats"))
            {
                var data = asset.AsDictionary <int, string>().Data;
                foreach (var hat in Mod.instance.hats)
                {
                    try
                    {
                        Log.verbose($"Injecting to hats: {hat.GetHatId()}: {hat.GetHatInformation()}");
                        data.Add(hat.GetHatId(), hat.GetHatInformation());
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting hat information for {hat.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("Data\\weapons"))
            {
                var data = asset.AsDictionary <int, string>().Data;
                foreach (var weapon in Mod.instance.weapons)
                {
                    try
                    {
                        Log.verbose($"Injecting to weapons: {weapon.GetWeaponId()}: {weapon.GetWeaponInformation()}");
                        data.Add(weapon.GetWeaponId(), weapon.GetWeaponInformation());
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting weapon information for {weapon.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("Data\\NPCGiftTastes"))
            {
                var data = asset.AsDictionary <string, string>().Data;
                // TODO: This could be optimized from mn to... m + n?
                // Basically, iterate through objects and create Dictionary<NPC name, GiftData[]>
                // Iterate through objects, each section and add to dict[npc][approp. section]
                // Point is, I'm doing this the lazy way right now
                var newData = new Dictionary <string, string>(data);
                foreach (var npc in data)
                {
                    if (npc.Key.StartsWith("Universal_"))
                    {
                        continue;
                    }

                    string[] sections = npc.Value.Split('/');
                    if (sections.Length != 11)
                    {
                        Log.warn($"Bad gift taste data for {npc.Key}!");
                        continue;
                    }

                    string        loveStr    = sections[0];
                    List <string> loveIds    = new List <string>(sections[1].Split(' '));
                    string        likeStr    = sections[2];
                    List <string> likeIds    = new List <string>(sections[3].Split(' '));
                    string        dislikeStr = sections[4];
                    List <string> dislikeIds = new List <string>(sections[5].Split(' '));
                    string        hateStr    = sections[6];
                    List <string> hateIds    = new List <string>(sections[7].Split(' '));
                    string        neutralStr = sections[8];
                    List <string> neutralIds = new List <string>(sections[9].Split(' '));

                    foreach (var obj in Mod.instance.objects)
                    {
                        if (obj.GiftTastes == null)
                        {
                            continue;
                        }
                        if (obj.GiftTastes.Love != null && obj.GiftTastes.Love.Contains(npc.Key))
                        {
                            loveIds.Add(obj.GetObjectId().ToString());
                        }
                        if (obj.GiftTastes.Like != null && obj.GiftTastes.Like.Contains(npc.Key))
                        {
                            likeIds.Add(obj.GetObjectId().ToString());
                        }
                        if (obj.GiftTastes.Neutral != null && obj.GiftTastes.Neutral.Contains(npc.Key))
                        {
                            neutralIds.Add(obj.GetObjectId().ToString());
                        }
                        if (obj.GiftTastes.Dislike != null && obj.GiftTastes.Dislike.Contains(npc.Key))
                        {
                            dislikeIds.Add(obj.GetObjectId().ToString());
                        }
                        if (obj.GiftTastes.Hate != null && obj.GiftTastes.Hate.Contains(npc.Key))
                        {
                            hateIds.Add(obj.GetObjectId().ToString());
                        }
                    }

                    string loveIdStr    = string.Join(" ", loveIds);
                    string likeIdStr    = string.Join(" ", likeIds);
                    string dislikeIdStr = string.Join(" ", dislikeIds);
                    string hateIdStr    = string.Join(" ", hateIds);
                    string neutralIdStr = string.Join(" ", neutralIds);
                    newData[npc.Key] = $"{loveStr}/{loveIdStr}/{likeStr}/{likeIdStr}/{dislikeStr}/{dislikeIdStr}/{hateStr}/{hateIdStr}/{neutralStr}/{neutralIdStr}/ ";

                    Log.verbose($"Adding gift tastes for {npc.Key}: {newData[npc.Key]}");
                }
                asset.ReplaceWith(newData);
            }
            else if (asset.AssetNameEquals("Data\\ClothingInformation"))
            {
                var data = asset.AsDictionary <int, string>().Data;
                foreach (var shirt in Mod.instance.shirts)
                {
                    try
                    {
                        Log.verbose($"Injecting to clothing information: {shirt.GetClothingId()}: {shirt.GetClothingInformation()}");
                        data.Add(shirt.GetClothingId(), shirt.GetClothingInformation());
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting clothing information for {shirt.Name}: {e}");
                    }
                }
                foreach (var pants in Mod.instance.pantss)
                {
                    try
                    {
                        Log.verbose($"Injecting to clothing information: {pants.GetClothingId()}: {pants.GetClothingInformation()}");
                        data.Add(pants.GetClothingId(), pants.GetClothingInformation());
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting clothing information for {pants.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("Data\\TailoringRecipes"))
            {
                var data = asset.GetData <List <TailorItemRecipe> >();
                foreach (var recipe in Mod.instance.tailoring)
                {
                    try
                    {
                        Log.verbose($"Injecting to tailoring recipe: {recipe.ToGameData()}");
                        data.Add(recipe.ToGameData());
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting tailoring recipe: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("Data\\Boots"))
            {
                var data = asset.AsDictionary <int, string>().Data;
                foreach (var boots in Mod.instance.bootss)
                {
                    try
                    {
                        Log.verbose($"Injecting to boots: {boots.GetObjectId()}: {boots.GetBootsInformation()}");
                        data.Add(boots.GetObjectId(), boots.GetBootsInformation());
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting boots information for {boots.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("Maps\\springobjects"))
            {
                var       oldTex = asset.AsImage().Data;
                Texture2D newTex = new Texture2D(Game1.graphics.GraphicsDevice, oldTex.Width, Math.Max(oldTex.Height, 4096));
                asset.ReplaceWith(newTex);
                asset.AsImage().PatchImage(oldTex);

                foreach (var obj in Mod.instance.objects)
                {
                    try
                    {
                        Log.verbose($"Injecting {obj.Name} sprites @ {objectRect(obj.GetObjectId())}");
                        asset.AsImage().PatchImage(obj.texture, null, objectRect(obj.GetObjectId()));
                        if (obj.IsColored)
                        {
                            Log.verbose($"Injecting {obj.Name} color sprites @ {objectRect(obj.GetObjectId() + 1)}");
                            asset.AsImage().PatchImage(obj.textureColor, null, objectRect(obj.GetObjectId() + 1));
                        }

                        var rect = objectRect(obj.GetObjectId());
                        int ts   = 0;// TileSheetExtensions.GetAdjustedTileSheetTarget(asset.AssetName, rect).TileSheet;
                        obj.tilesheet  = asset.AssetName + (ts == 0 ? "" : (ts + 1).ToString());
                        obj.tilesheetX = rect.X;
                        obj.tilesheetY = rect.Y;
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting sprite for {obj.Name}: {e}");
                    }
                }

                foreach (var boots in Mod.instance.bootss)
                {
                    try
                    {
                        Log.verbose($"Injecting {boots.Name} sprites @ {objectRect(boots.GetObjectId())}");
                        asset.AsImage().PatchImage(boots.texture, null, objectRect(boots.GetObjectId()));

                        var rect = objectRect(boots.GetObjectId());
                        int ts   = 0;// TileSheetExtensions.GetAdjustedTileSheetTarget(asset.AssetName, rect).TileSheet;
                        boots.tilesheet  = asset.AssetName + (ts == 0 ? "" : (ts + 1).ToString());
                        boots.tilesheetX = rect.X;
                        boots.tilesheetY = rect.Y;
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting sprite for {boots.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("TileSheets\\crops"))
            {
                var       oldTex = asset.AsImage().Data;
                Texture2D newTex = new Texture2D(Game1.graphics.GraphicsDevice, oldTex.Width, Math.Max(oldTex.Height, 4096));
                asset.ReplaceWith(newTex);
                asset.AsImage().PatchImage(oldTex);

                foreach (var crop in Mod.instance.crops)
                {
                    try
                    {
                        Log.verbose($"Injecting {crop.Name} crop images @ {cropRect(crop.GetCropSpriteIndex())}");
                        asset.AsImage().PatchExtendedTileSheet(crop.texture, null, cropRect(crop.GetCropSpriteIndex()));

                        var rect = cropRect(crop.GetCropSpriteIndex());
                        int ts   = TileSheetExtensions.GetAdjustedTileSheetTarget(asset.AssetName, rect).TileSheet;
                        crop.tilesheet  = asset.AssetName + (ts == 0 ? "" : (ts + 1).ToString());
                        crop.tilesheetX = rect.X;
                        crop.tilesheetY = rect.Y;
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting crop sprite for {crop.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("TileSheets\\fruitTrees"))
            {
                var       oldTex = asset.AsImage().Data;
                Texture2D newTex = new Texture2D(Game1.graphics.GraphicsDevice, oldTex.Width, Math.Max(oldTex.Height, 4096));
                asset.ReplaceWith(newTex);
                asset.AsImage().PatchImage(oldTex);

                foreach (var fruitTree in Mod.instance.fruitTrees)
                {
                    try
                    {
                        Log.verbose($"Injecting {fruitTree.Name} fruit tree images @ {fruitTreeRect(fruitTree.GetFruitTreeIndex())}");
                        asset.AsImage().PatchExtendedTileSheet(fruitTree.texture, null, fruitTreeRect(fruitTree.GetFruitTreeIndex()));

                        var rect = fruitTreeRect(fruitTree.GetFruitTreeIndex());
                        int ts   = TileSheetExtensions.GetAdjustedTileSheetTarget(asset.AssetName, rect).TileSheet;
                        fruitTree.tilesheet  = asset.AssetName + (ts == 0 ? "" : (ts + 1).ToString());
                        fruitTree.tilesheetX = rect.X;
                        fruitTree.tilesheetY = rect.Y;
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting fruit tree sprite for {fruitTree.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("TileSheets\\Craftables"))
            {
                var       oldTex = asset.AsImage().Data;
                Texture2D newTex = new Texture2D(Game1.graphics.GraphicsDevice, oldTex.Width, Math.Max(oldTex.Height, 4096));
                asset.ReplaceWith(newTex);
                asset.AsImage().PatchImage(oldTex);
                Log.trace($"Big craftables are now ({oldTex.Width}, {Math.Max(oldTex.Height, 4096)})");

                foreach (var big in Mod.instance.bigCraftables)
                {
                    try
                    {
                        Log.verbose($"Injecting {big.Name} sprites @ {bigCraftableRect(big.GetCraftableId())}");
                        asset.AsImage().PatchImage(big.texture, null, bigCraftableRect(big.GetCraftableId()));
                        if (big.ReserveNextIndex)
                        {
                            Log.verbose($"Injecting {big.Name} reserved extra sprite @ {bigCraftableRect(big.GetCraftableId() + 1)}");
                            asset.AsImage().PatchImage(big.texture2, null, bigCraftableRect(big.GetCraftableId() + 1));
                        }

                        var rect = bigCraftableRect(big.GetCraftableId());
                        int ts   = 0;// TileSheetExtensions.GetAdjustedTileSheetTarget(asset.AssetName, rect).TileSheet;
                        big.tilesheet  = asset.AssetName + (ts == 0 ? "" : (ts + 1).ToString());
                        big.tilesheetX = rect.X;
                        big.tilesheetY = rect.Y;
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting sprite for {big.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("Characters\\Farmer\\hats"))
            {
                var       oldTex = asset.AsImage().Data;
                Texture2D newTex = new Texture2D(Game1.graphics.GraphicsDevice, oldTex.Width, Math.Max(oldTex.Height, 4096));
                asset.ReplaceWith(newTex);
                asset.AsImage().PatchImage(oldTex);
                Log.trace($"Hats are now ({oldTex.Width}, {Math.Max(oldTex.Height, 4096)})");

                foreach (var hat in Mod.instance.hats)
                {
                    try
                    {
                        Log.verbose($"Injecting {hat.Name} sprites @ {hatRect(hat.GetHatId())}");
                        asset.AsImage().PatchImage(hat.texture, null, hatRect(hat.GetHatId()));

                        var rect = hatRect(hat.GetHatId());
                        int ts   = 0;// TileSheetExtensions.GetAdjustedTileSheetTarget(asset.AssetName, rect).TileSheet;
                        hat.tilesheet  = asset.AssetName + (ts == 0 ? "" : (ts + 1).ToString());
                        hat.tilesheetX = rect.X;
                        hat.tilesheetY = rect.Y;
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting sprite for {hat.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("TileSheets\\weapons"))
            {
                var       oldTex = asset.AsImage().Data;
                Texture2D newTex = new Texture2D(Game1.graphics.GraphicsDevice, oldTex.Width, Math.Max(oldTex.Height, 4096));
                asset.ReplaceWith(newTex);
                asset.AsImage().PatchImage(oldTex);
                Log.trace($"Weapons are now ({oldTex.Width}, {Math.Max(oldTex.Height, 4096)})");

                foreach (var weapon in Mod.instance.weapons)
                {
                    try
                    {
                        Log.verbose($"Injecting {weapon.Name} sprites @ {weaponRect(weapon.GetWeaponId())}");
                        asset.AsImage().PatchImage(weapon.texture, null, weaponRect(weapon.GetWeaponId()));

                        var rect = weaponRect(weapon.GetWeaponId());
                        int ts   = 0;// TileSheetExtensions.GetAdjustedTileSheetTarget(asset.AssetName, rect).TileSheet;
                        weapon.tilesheet  = asset.AssetName + (ts == 0 ? "" : (ts + 1).ToString());
                        weapon.tilesheetX = rect.X;
                        weapon.tilesheetY = rect.Y;
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting sprite for {weapon.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("Characters\\Farmer\\shirts"))
            {
                var       oldTex = asset.AsImage().Data;
                Texture2D newTex = new Texture2D(Game1.graphics.GraphicsDevice, oldTex.Width, Math.Max(oldTex.Height, 4096));
                asset.ReplaceWith(newTex);
                asset.AsImage().PatchImage(oldTex);
                Log.trace($"Shirts are now ({oldTex.Width}, {Math.Max(oldTex.Height, 4096)})");

                foreach (var shirt in Mod.instance.shirts)
                {
                    try
                    {
                        string rects = shirtRectPlain(shirt.GetMaleIndex()).ToString();
                        if (shirt.Dyeable)
                        {
                            rects += ", " + shirtRectDye(shirt.GetMaleIndex()).ToString();
                        }
                        if (shirt.HasFemaleVariant)
                        {
                            rects += ", " + shirtRectPlain(shirt.GetFemaleIndex()).ToString();
                            if (shirt.Dyeable)
                            {
                                rects += ", " + shirtRectDye(shirt.GetFemaleIndex()).ToString();
                            }
                        }

                        Log.verbose($"Injecting {shirt.Name} sprites @ {rects}");
                        asset.AsImage().PatchExtendedTileSheet(shirt.textureMale, null, shirtRectPlain(shirt.GetMaleIndex()));
                        if (shirt.Dyeable)
                        {
                            asset.AsImage().PatchExtendedTileSheet(shirt.textureMaleColor, null, shirtRectDye(shirt.GetMaleIndex()));
                        }
                        if (shirt.HasFemaleVariant)
                        {
                            asset.AsImage().PatchExtendedTileSheet(shirt.textureFemale, null, shirtRectPlain(shirt.GetFemaleIndex()));
                            if (shirt.Dyeable)
                            {
                                asset.AsImage().PatchExtendedTileSheet(shirt.textureFemaleColor, null, shirtRectDye(shirt.GetFemaleIndex()));
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting sprite for {shirt.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("Characters\\Farmer\\pants"))
            {
                var       oldTex = asset.AsImage().Data;
                Texture2D newTex = new Texture2D(Game1.graphics.GraphicsDevice, oldTex.Width, Math.Max(oldTex.Height, 4096));
                asset.ReplaceWith(newTex);
                asset.AsImage().PatchImage(oldTex);
                Log.trace($"Pants are now ({oldTex.Width}, {Math.Max(oldTex.Height, 4096)})");

                foreach (var pants in Mod.instance.pantss)
                {
                    try
                    {
                        Log.verbose($"Injecting {pants.Name} sprites @ {pantsRect(pants.GetTextureIndex())}");
                        asset.AsImage().PatchExtendedTileSheet(pants.texture, null, pantsRect(pants.GetTextureIndex()));
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting sprite for {pants.Name}: {e}");
                    }
                }
            }
            else if (asset.AssetNameEquals("Characters\\Farmer\\shoeColors"))
            {
                var       oldTex = asset.AsImage().Data;
                Texture2D newTex = new Texture2D(Game1.graphics.GraphicsDevice, oldTex.Width, Math.Max(oldTex.Height, 4096));
                asset.ReplaceWith(newTex);
                asset.AsImage().PatchImage(oldTex);
                Log.trace($"Boots are now ({oldTex.Width}, {Math.Max(oldTex.Height, 4096)})");

                foreach (var boots in Mod.instance.bootss)
                {
                    try
                    {
                        Log.verbose($"Injecting {boots.Name} sprites @ {bootsRect(boots.GetTextureIndex())}");
                        asset.AsImage().PatchExtendedTileSheet(boots.textureColor, null, bootsRect(boots.GetTextureIndex()));
                    }
                    catch (Exception e)
                    {
                        Log.error($"Exception injecting sprite for {boots.Name}: {e}");
                    }
                }
            }
        }