Пример #1
0
        private static void breakStone_Postfix(GameLocation __instance, ref bool __result, int indexOfStone, int x, int y, Farmer who, Random r)
        {
            SMonitor.Log($"Checking for custom ore in stone {indexOfStone}");

            CustomOreNode node = customOreNodesList.Find(n => n.parentSheetIndex == indexOfStone);

            if (node == null)
            {
                return;
            }

            SMonitor.Log($"Got custom ore in stone {indexOfStone}");


            OreLevelRange gotRange = null;

            foreach (OreLevelRange range in node.oreLevelRanges)
            {
                if (IsInRange(range, __instance, false))
                {
                    gotRange = range;
                    break;
                }
            }
            if (gotRange == null)
            {
                SMonitor.Log($"No range for {indexOfStone}!", LogLevel.Warn);

                return;
            }

            int addedOres = who.professions.Contains(18) ? 1 : 0;

            SMonitor.Log($"custom node has {node.dropItems.Count} potential items.");
            foreach (DropItem item in node.dropItems)
            {
                if (Game1.random.NextDouble() < item.dropChance * gotRange.dropChanceMult / 100)
                {
                    SMonitor.Log($"dropping item {item.itemIdOrName}");

                    if (!int.TryParse(item.itemIdOrName, out int itemId))
                    {
                        foreach (KeyValuePair <int, string> kvp in Game1.objectInformation)
                        {
                            if (kvp.Value.StartsWith(item.itemIdOrName + "/"))
                            {
                                itemId = kvp.Key;
                                break;
                            }
                        }
                    }

                    Game1.createMultipleObjectDebris(itemId, x, y, addedOres + (int)Math.Round(r.Next(item.minAmount, (Math.Max(item.minAmount + 1, item.maxAmount + 1)) + ((r.NextDouble() < who.LuckLevel / 100f) ? item.luckyAmount : 0) + ((r.NextDouble() < who.MiningLevel / 100f) ? item.minerAmount : 0)) * gotRange.dropMult), who.UniqueMultiplayerID, __instance);
                }
            }
            int experience = (int)Math.Round(node.exp * gotRange.expMult);

            who.gainExperience(3, experience);
            __result = experience > 0;
        }
Пример #2
0
 /// <summary>Edit a matched asset.</summary>
 /// <param name="asset">A helper which encapsulates metadata about an asset and enables changes to it.</param>
 public void Edit <T>(IAssetData asset)
 {
     if (asset.AssetNameEquals("Maps/springobjects") && CustomOreNodes.Count > 0)
     {
         var editor    = asset.AsImage();
         int extension = (Config.SpriteSheetOffsetRows * 16) + ((CustomOreNodes.Count / (editor.Data.Width / 16) + 1) * 16);
         editor.ExtendImage(minWidth: editor.Data.Width, minHeight: SpringObjectsHeight + extension);
         SMonitor.Log($"extended springobjects by {extension}");
         for (int i = 0; i < CustomOreNodes.Count; i++)
         {
             CustomOreNode node = CustomOreNodes[i];
             SMonitor.Log($"Patching springobjects with {node.spritePath}");
             Texture2D customTexture;
             customTexture = node.texture;
             int x = (i % (editor.Data.Width / 16)) * 16;
             int y = SpringObjectsHeight + (Config.SpriteSheetOffsetRows * 16) + (i / (editor.Data.Width / 16)) * 16;
             editor.PatchImage(customTexture, sourceArea: new Rectangle(node.spriteX, node.spriteY, node.spriteW, node.spriteH), targetArea: new Rectangle(x, y, 16, 16));
             SMonitor.Log($"patched springobjects with {node.spritePath}");
         }
     }
     else if (asset.AssetNameEquals("Data/ObjectInformation"))
     {
         var editor = asset.AsDictionary <int, string>();
         for (int i = 0; i < CustomOreNodes.Count; i++)
         {
             editor.Data[i + 816] = $"Stone/0/15/Basic/Stone/{CustomOreNodes[i].nodeDesc}";
         }
     }
 }
Пример #3
0
 private static void Object_Prefix(ref int parentSheetIndex, string Givenname)
 {
     if (Environment.StackTrace.Contains("chooseStoneType"))
     {
         return;
     }
     if (Givenname == "Stone" || parentSheetIndex == 294 || parentSheetIndex == 295)
     {
         float currentChance = 0;
         for (int i = 0; i < customOreNodesList.Count; i++)
         {
             CustomOreNode node     = customOreNodesList[i];
             OreLevelRange gotRange = null;
             foreach (OreLevelRange range in node.oreLevelRanges)
             {
                 if (range.minLevel < 1)
                 {
                     gotRange = range;
                     break;
                 }
             }
             if (gotRange == null)
             {
                 continue;
             }
             currentChance += node.spawnChance * gotRange.spawnChanceMult;
             if (Game1.random.NextDouble() < currentChance / 100f)
             {
                 int index = node.parentSheetIndex;
                 parentSheetIndex = index;
                 break;
             }
         }
     }
 }
Пример #4
0
        private void GameLoop_GameLaunched(object sender, StardewModdingAPI.Events.GameLaunchedEventArgs e)
        {
            CustomOreNodes.Clear();
            CustomOreData data;

            try
            {
                data = Helper.Content.Load <CustomOreData>("custom_ore_nodes.json", ContentSource.ModFolder);
                foreach (string nodeInfo in data.nodes)
                {
                    CustomOreNode node = new CustomOreNode(nodeInfo);
                    if (node.spriteType == "mod")
                    {
                        node.texture = Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.ModFolder);
                    }
                    else
                    {
                        node.texture = this.Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.GameContent);
                    }
                    CustomOreNodes.Add(node);
                }
                Monitor.Log($"Got {CustomOreNodes.Count} ores from mod", LogLevel.Debug);
            }
            catch (Exception ex)
            {
                SMonitor.Log("custom_ore_nodes.json error." + ex, LogLevel.Debug);
            }

            foreach (IContentPack contentPack in this.Helper.ContentPacks.GetOwned())
            {
                try
                {
                    this.Monitor.Log($"Reading content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}");
                    data = contentPack.ReadJsonFile <CustomOreData>("custom_ore_nodes.json");
                    foreach (string nodeInfo in data.nodes)
                    {
                        CustomOreNode node = new CustomOreNode(nodeInfo);
                        if (node.spriteType == "mod")
                        {
                            node.texture = contentPack.LoadAsset <Texture2D>(node.spritePath);
                        }
                        else
                        {
                            node.texture = Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.GameContent);
                        }
                        CustomOreNodes.Add(node);
                    }
                    Monitor.Log($"Got {data.nodes.Count} ores from content pack {contentPack.Manifest.Name}", LogLevel.Debug);
                }
                catch
                {
                    SMonitor.Log($"custom_ore_nodes.json file not found in content pack {contentPack.Manifest.Name}", LogLevel.Debug);
                }
            }
            Monitor.Log($"Got {CustomOreNodes.Count} ores total", LogLevel.Debug);
            Helper.Content.InvalidateCache("Maps/springobjects");
        }
Пример #5
0
        private static void breakStone_Postfix(GameLocation __instance, ref bool __result, int indexOfStone, int x, int y, Farmer who, Random r)
        {
            SMonitor.Log($"Checking for custom ore in stone {indexOfStone}");
            int firstIndex = FirstIndex + (Config.SpriteSheetOffsetRows * SpringObjectsWidth / 16);

            if (indexOfStone - firstIndex < 0 || indexOfStone - firstIndex >= CustomOreNodes.Count)
            {
                return;
            }

            CustomOreNode node     = CustomOreNodes[indexOfStone - firstIndex];
            OreLevelRange gotRange = null;

            foreach (OreLevelRange range in node.oreLevelRanges)
            {
                if ((range.minLevel < 1 && !(__instance is MineShaft)) || (range.minLevel > 0 && __instance is MineShaft && ((__instance as MineShaft).mineLevel <= range.maxLevel)))
                {
                    gotRange = range;
                    break;
                }
            }
            if (gotRange == null)
            {
                return;
            }

            int addedOres = who.professions.Contains(18) ? 1 : 0;

            SMonitor.Log($"custom node has {node.dropItems.Count} potential items.");
            foreach (DropItem item in node.dropItems)
            {
                if (Game1.random.NextDouble() < item.dropChance * gotRange.dropChanceMult / 100)
                {
                    SMonitor.Log($"dropping item {item.itemIdOrName}");

                    if (!int.TryParse(item.itemIdOrName, out int itemId))
                    {
                        foreach (KeyValuePair <int, string> kvp in Game1.objectInformation)
                        {
                            if (kvp.Value.StartsWith(item.itemIdOrName + "/"))
                            {
                                itemId = kvp.Key;
                                break;
                            }
                        }
                    }

                    Game1.createMultipleObjectDebris(itemId, x, y, addedOres + (int)Math.Round(r.Next(item.minAmount, (Math.Max(item.minAmount + 1, item.maxAmount + 1)) + ((r.NextDouble() < (double)((float)who.LuckLevel / 100f)) ? item.luckyAmount : 0) + ((r.NextDouble() < (double)((float)who.MiningLevel / 100f)) ? item.minerAmount : 0)) * gotRange.dropMult), who.uniqueMultiplayerID, __instance);
                }
            }
            int experience = (int)Math.Round(node.exp * gotRange.expMult);

            who.gainExperience(3, experience);
            __result = experience > 0;
        }
Пример #6
0
        private static void chooseStoneType_Postfix(MineShaft __instance, ref Object __result, Vector2 tile)
        {
            if (__result == null || __result.parentSheetIndex == null)
            {
                return;
            }

            List <int> ores = new List <int>()
            {
                765, 764, 290, 751
            };

            if (!ores.Contains(__result.ParentSheetIndex))
            {
                float totalChance = 0;
                for (int i = 0; i < CustomOreNodes.Count; i++)
                {
                    CustomOreNode node = CustomOreNodes[i];
                    if (node.minLevel > -1 && __instance.mineLevel < node.minLevel || node.maxLevel > -1 && __instance.mineLevel > node.maxLevel)
                    {
                        continue;
                    }
                    totalChance += node.spawnChance;
                }
                double ourChance = Game1.random.NextDouble() * 100;
                if (ourChance < totalChance)
                {
                    // SMonitor.Log($"Chance of custom ore: {ourChance}%");
                    float cumulativeChance = 0f;
                    for (int i = 0; i < CustomOreNodes.Count; i++)
                    {
                        CustomOreNode node = CustomOreNodes[i];
                        if (node.minLevel > -1 && __instance.mineLevel < node.minLevel || node.maxLevel > -1 && __instance.mineLevel > node.maxLevel)
                        {
                            continue;
                        }
                        cumulativeChance += node.spawnChance;
                        if (ourChance < cumulativeChance)
                        {
                            SMonitor.Log($"Displaying custom ore \"{node.nodeDesc}\": {cumulativeChance}% / {ourChance}% (rolled)");

                            int index = (SpringObjectsHeight / 16 * SpringObjectsWidth / 16) + (Config.SpriteSheetOffsetRows * SpringObjectsWidth / 16) + i;
                            //SMonitor.Log($"Displaying stone at index {index}", LogLevel.Debug);
                            __result = new Object(tile, index, "Stone", true, false, false, false)
                            {
                                MinutesUntilReady = node.durability
                            };
                            //SMonitor.Log(__result.DisplayName);

                            return;
                        }
                    }
                }
            }
        }
Пример #7
0
        private static bool Object_draw_Prefix(Object __instance, SpriteBatch spriteBatch, int x, int y, float alpha = 1f)
        {
            CustomOreNode node = customOreNodesList.Find(n => n.parentSheetIndex == __instance.ParentSheetIndex);

            if (node == null)
            {
                return(true);
            }

            if (__instance.Fragility != 2)
            {
                spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, new Vector2(x * 64 + 32, y * 64 + 51 + 4)), new Rectangle?(Game1.shadowTexture.Bounds), Color.White * alpha, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), 4f, SpriteEffects.None, __instance.getBoundingBox(new Vector2(x, y)).Bottom / 15000f);
            }
            Vector2   position3        = Game1.GlobalToLocal(Game1.viewport, new Vector2(x * 64 + 32 + ((__instance.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0), y * 64 + 32 + ((__instance.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0)));
            Rectangle?sourceRectangle2 = new Rectangle(node.spriteX, node.spriteY, node.spriteW, node.spriteH);
            Color     color2           = Color.White * alpha;
            float     rotation2        = 0f;
            Vector2   origin2          = new Vector2(8f, 8f);
            Vector2   vector2          = __instance.scale;

            spriteBatch.Draw(node.texture, position3, sourceRectangle2, color2, rotation2, origin2, (__instance.scale.Y > 1f) ? __instance.getScale().Y : 4f, __instance.Flipped ? SpriteEffects.FlipHorizontally : SpriteEffects.None, (__instance.isPassable() ? __instance.getBoundingBox(new Vector2(x, y)).Top : __instance.getBoundingBox(new Vector2(x, y)).Bottom) / 10000f);
            return(false);
        }
Пример #8
0
        private static void chooseStoneType_Postfix(MineShaft __instance, ref Object __result, Vector2 tile)
        {
            if (__result == null || __result.parentSheetIndex == null)
            {
                return;
            }

            List <int> ores = new List <int>()
            {
                765, 764, 290, 751
            };

            if (!ores.Contains(__result.ParentSheetIndex))
            {
                for (int i = 0; i < CustomOreNodes.Count; i++)
                {
                    CustomOreNode node = CustomOreNodes[i];
                    if (node.minLevel > -1 && __instance.mineLevel < node.minLevel || node.maxLevel > -1 && __instance.mineLevel > node.maxLevel)
                    {
                        continue;
                    }
                    if (Game1.random.NextDouble() < node.spawnChance / 100f)
                    {
                        int index = (SpringObjectsHeight / 16 * SpringObjectsWidth / 16) + (Config.SpriteSheetOffsetRows * SpringObjectsWidth / 16) + i;
                        SMonitor.Log($"Displaying stone at index {index}", LogLevel.Debug);
                        __result = new Object(tile, index, "Stone", true, false, false, false)
                        {
                            MinutesUntilReady = node.durability
                        };

                        SMonitor.Log(__result.DisplayName);

                        return;
                    }
                }
            }
        }
Пример #9
0
 private static void Object_Prefix(ref int parentSheetIndex, ref string Givenname)
 {
     if (Environment.StackTrace.Contains("chooseStoneType"))
     {
         return;
     }
     if (Givenname == "Stone" || parentSheetIndex == 294 || parentSheetIndex == 295)
     {
         for (int i = 0; i < CustomOreNodes.Count; i++)
         {
             CustomOreNode node = CustomOreNodes[i];
             if (node.minLevel > 0)
             {
                 continue;
             }
             if (Game1.random.NextDouble() < node.spawnChance / 100f)
             {
                 int index = (SpringObjectsHeight / 16 * SpringObjectsWidth / 16) + (Config.SpriteSheetOffsetRows * SpringObjectsWidth / 16) + i;
                 parentSheetIndex = index;
                 break;
             }
         }
     }
 }
Пример #10
0
        private static void chooseStoneType_Postfix(MineShaft __instance, ref Object __result, Vector2 tile)
        {
            if (__result == null)
            {
                return;
            }

            int difficulty = __instance.mineLevel > 120 ? Game1.netWorldState.Value.SkullCavesDifficulty : Game1.netWorldState.Value.MinesDifficulty;

            List <int> ores = new List <int>()
            {
                765, 764, 290, 751
            };

            if (!ores.Contains(__result.ParentSheetIndex))
            {
                float totalChance = 0;
                for (int i = 0; i < customOreNodesList.Count; i++)
                {
                    CustomOreNode node = customOreNodesList[i];
                    foreach (OreLevelRange range in node.oreLevelRanges)
                    {
                        if ((range.minLevel < 1 || __instance.mineLevel >= range.minLevel) && (range.maxLevel < 1 || __instance.mineLevel <= range.maxLevel) && (range.minDifficulty <= difficulty) && (range.maxDifficulty < 0 || range.maxDifficulty >= difficulty))
                        {
                            totalChance += node.spawnChance * range.spawnChanceMult;
                            break;
                        }
                    }
                }
                double ourChance = Game1.random.NextDouble() * 100;
                if (ourChance < totalChance)
                {
                    // SMonitor.Log($"Chance of custom ore: {ourChance}%");
                    float cumulativeChance = 0f;
                    for (int i = 0; i < customOreNodesList.Count; i++)
                    {
                        CustomOreNode node     = customOreNodesList[i];
                        OreLevelRange gotRange = null;
                        foreach (OreLevelRange range in node.oreLevelRanges)
                        {
                            if (IsInRange(range, __instance, true))
                            {
                                gotRange = range;
                                break;
                            }
                        }
                        if (gotRange == null)
                        {
                            continue;
                        }
                        cumulativeChance += node.spawnChance * gotRange.spawnChanceMult;
                        if (ourChance < cumulativeChance)
                        {
                            SMonitor.Log($"Switching to custom ore \"{node.nodeDesc}\": {cumulativeChance}% / {ourChance}% (rolled)");

                            int index = node.parentSheetIndex;
                            //SMonitor.Log($"Displaying stone at index {index}", LogLevel.Debug);
                            __result = new Object(tile, index, "Stone", true, false, false, false)
                            {
                                MinutesUntilReady = node.durability
                            };

                            return;
                        }
                    }
                }
            }
        }
Пример #11
0
        private void ReloadOreData(bool first = false)
        {
            customOreNodesList.Clear();
            CustomOreData         data;
            int                   id           = 42424000;
            Dictionary <int, int> existingPSIs = new Dictionary <int, int>();
            CustomOreConfig       conf         = Helper.Data.ReadJsonFile <CustomOreConfig>("ore_config.json") ?? new CustomOreConfig();

            foreach (KeyValuePair <int, int> psi in conf.parentSheetIndexes)
            {
                existingPSIs[psi.Value] = psi.Key;
            }
            foreach (IContentPack contentPack in Helper.ContentPacks.GetOwned())
            {
                conf = contentPack.ReadJsonFile <CustomOreConfig>("ore_config.json") ?? new CustomOreConfig();
                foreach (KeyValuePair <int, int> psi in conf.parentSheetIndexes)
                {
                    existingPSIs[psi.Value] = psi.Key;
                }
            }
            try
            {
                if (File.Exists(Path.Combine(Helper.DirectoryPath, "custom_ore_nodes.json")))
                {
                    int add = 0;
                    try
                    {
                        data = Helper.Content.Load <CustomOreData>("custom_ore_nodes.json", ContentSource.ModFolder);
                    }
                    catch
                    {
                        var tempData = Helper.Content.Load <CustomOreDataOld>("custom_ore_nodes.json", ContentSource.ModFolder);
                        data = new CustomOreData();
                        for (int i = 0; i < tempData.nodes.Count; i++)
                        {
                            data.nodes.Add(new CustomOreNode(tempData.nodes[i]));
                        }
                        if (first)
                        {
                            Monitor.Log($"Rewriting custom_ore_nodes.json", LogLevel.Debug);
                            Helper.Data.WriteJsonFile("custom_ore_nodes.json", data);
                        }
                    }
                    conf = Helper.Data.ReadJsonFile <CustomOreConfig>("ore_config.json") ?? new CustomOreConfig();
                    foreach (object nodeObj in data.nodes)
                    {
                        CustomOreNode node = (CustomOreNode)nodeObj;

                        if (node.spriteType == "mod")
                        {
                            node.texture = Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.ModFolder);
                        }
                        else
                        {
                            node.texture = Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.GameContent);
                        }
                        if (conf.parentSheetIndexes.ContainsKey(add))
                        {
                            node.parentSheetIndex = conf.parentSheetIndexes[add];
                        }
                        else
                        {
                            while (existingPSIs.ContainsKey(id))
                            {
                                id++;
                            }
                            node.parentSheetIndex = id++;
                        }
                        conf.parentSheetIndexes[add] = node.parentSheetIndex;

                        customOreNodesList.Add(node);
                        add++;
                    }
                    if (first)
                    {
                        Monitor.Log($"Got {customOreNodesList.Count} ores from mod", LogLevel.Debug);
                        Helper.Data.WriteJsonFile("ore_config.json", conf);
                    }
                }
                else
                {
                    SMonitor.Log("No custom_ore_nodes.json in mod directory.");
                }
            }
            catch (Exception ex)
            {
                SMonitor.Log("Error processing custom_ore_nodes.json: " + ex, LogLevel.Error);
            }

            foreach (IContentPack contentPack in Helper.ContentPacks.GetOwned())
            {
                try
                {
                    int add = 0;
                    conf = contentPack.ReadJsonFile <CustomOreConfig>("ore_config.json") ?? new CustomOreConfig();
                    if (first)
                    {
                        Monitor.Log($"Reading content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}");
                    }

                    try
                    {
                        data = contentPack.ReadJsonFile <CustomOreData>("custom_ore_nodes.json");
                    }
                    catch (Exception ex)
                    {
                        Monitor.Log($"exception {ex}", LogLevel.Error);
                        var tempData = contentPack.ReadJsonFile <CustomOreDataOld>("custom_ore_nodes.json");
                        data = new CustomOreData();
                        for (int i = 0; i < tempData.nodes.Count; i++)
                        {
                            data.nodes.Add(new CustomOreNode(tempData.nodes[i]));
                        }
                        if (first)
                        {
                            Monitor.Log($"Rewriting custom_ore_nodes.json", LogLevel.Debug);
                            contentPack.WriteJsonFile("custom_ore_nodes.json", data);
                        }
                    }

                    foreach (CustomOreNode node in data.nodes)
                    {
                        if (node.spriteType == "mod")
                        {
                            node.texture = contentPack.LoadAsset <Texture2D>(node.spritePath);
                        }
                        else
                        {
                            node.texture = Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.GameContent);
                        }
                        if (conf.parentSheetIndexes.ContainsKey(add))
                        {
                            node.parentSheetIndex = conf.parentSheetIndexes[add];
                        }
                        else
                        {
                            while (existingPSIs.ContainsKey(id))
                            {
                                id++;
                            }
                            node.parentSheetIndex = id++;
                        }
                        conf.parentSheetIndexes[add] = node.parentSheetIndex;
                        customOreNodesList.Add(node);
                        add++;
                    }
                    if (first)
                    {
                        Monitor.Log($"Got {data.nodes.Count} ores from content pack {contentPack.Manifest.Name}", LogLevel.Debug);
                        contentPack.WriteJsonFile("ore_config.json", conf);
                    }
                }
                catch (Exception ex)
                {
                    SMonitor.Log($"Error processing custom_ore_nodes.json in content pack {contentPack.Manifest.Name} {ex}", LogLevel.Error);
                }
            }
            if (first)
            {
                Monitor.Log($"Got {customOreNodesList.Count} ores total", LogLevel.Debug);
            }
        }
Пример #12
0
        private void GameLoop_GameLaunched(object sender, StardewModdingAPI.Events.GameLaunchedEventArgs e)
        {
            CustomOreNodes.Clear();
            CustomOreData data;
            Dictionary <string, Texture2D> gameTextures = new Dictionary <string, Texture2D>();

            try
            {
                if (File.Exists(Path.Combine(Helper.DirectoryPath, "custom_ore_nodes.json")))
                {
                    Dictionary <string, Texture2D> modTextures = new Dictionary <string, Texture2D>();
                    data = Helper.Content.Load <CustomOreData>("custom_ore_nodes.json", ContentSource.ModFolder);
                    foreach (string nodeInfo in data.nodes)
                    {
                        try
                        {
                            CustomOreNode node = new CustomOreNode(nodeInfo);
                            if (node.spriteType == "mod")
                            {
                                if (!modTextures.ContainsKey(node.spritePath))
                                {
                                    modTextures.Add(node.spritePath, Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.ModFolder));
                                }
                                node.texture = modTextures[node.spritePath];
                            }
                            else
                            {
                                if (!gameTextures.ContainsKey(node.spritePath))
                                {
                                    gameTextures.Add(node.spritePath, Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.GameContent));
                                }
                                node.texture = gameTextures[node.spritePath];
                            }
                            CustomOreNodes.Add(node);
                        }
                        catch (Exception ex)
                        {
                            SMonitor.Log($"Error parsing node {nodeInfo}: {ex}", LogLevel.Error);
                        }
                    }
                    Monitor.Log($"Got {CustomOreNodes.Count} ores from mod", LogLevel.Debug);
                }
                else
                {
                    SMonitor.Log("No custom_ore_nodes.json in mod directory.");
                }
            }
            catch (Exception ex)
            {
                SMonitor.Log("Error processing custom_ore_nodes.json: " + ex, LogLevel.Error);
            }

            foreach (IContentPack contentPack in Helper.ContentPacks.GetOwned())
            {
                try
                {
                    Dictionary <string, Texture2D> modTextures = new Dictionary <string, Texture2D>();
                    Monitor.Log($"Reading content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}");
                    data = contentPack.ReadJsonFile <CustomOreData>("custom_ore_nodes.json");
                    foreach (string nodeInfo in data.nodes)
                    {
                        try
                        {
                            CustomOreNode node = new CustomOreNode(nodeInfo);
                            if (node.spriteType == "mod")
                            {
                                if (!modTextures.ContainsKey(node.spritePath))
                                {
                                    modTextures.Add(node.spritePath, contentPack.LoadAsset <Texture2D>(node.spritePath));
                                }
                                node.texture = modTextures[node.spritePath];
                            }
                            else
                            {
                                if (!gameTextures.ContainsKey(node.spritePath))
                                {
                                    gameTextures.Add(node.spritePath, Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.GameContent));
                                }
                                node.texture = gameTextures[node.spritePath];
                            }
                            CustomOreNodes.Add(node);
                        }
                        catch (Exception ex)
                        {
                            SMonitor.Log($"Error parsing node {nodeInfo}: {ex}", LogLevel.Error);
                        }
                    }
                    Monitor.Log($"Got {data.nodes.Count} ores from content pack {contentPack.Manifest.Name}", LogLevel.Debug);
                }
                catch (Exception ex)
                {
                    SMonitor.Log($"Error processing custom_ore_nodes.json in content pack {contentPack.Manifest.Name} {ex}", LogLevel.Error);
                }
            }
            Monitor.Log($"Got {CustomOreNodes.Count} ores total", LogLevel.Debug);
            Helper.Content.InvalidateCache("Maps/springobjects");
        }