How Many Butterflies is Too Many?

How many butterflies should there be in the world? Too few, and players will barely see them. Too many, and they’ll overrun everything. This has been a challenge since the start of this mod, and as one player recently pointed out, I may have gone too far in limiting them.

Player Feedback


This latest round of tweaks was prompted by player feedback, pointing out that butterflies had become frustratingly rare:

The default configuration of this mod sets butterfly spawn rates way too low. After running it for several minutes, I only managed to spot two or three butterflies, and the caterpillar spawn probability is even lower

user_woyiqx

They were right, of course. I’d had some serious problems with butterfly overpopulation in the past, so I had been careful to ensure they wouldn’t spawn too often. Even after I had stopped them breeding like rabbits, they still spawned too much.

Understanding Mob Spawning


Before I can explain what happened, I want to cover some of the basics of mob spawning. Mobs are sorted into categories in Minecraft, as follows:

  • Monster
    Hostile mobs like zombies, skeletons, endermen, etc.
  • Creature
    Normal animals like cows and sheep.
  • Ambient
    Creatures that only add to the atmosphere. Basically just bats.
  • Axolotls
    These guys get their own category.
  • Underground Water Creatures
    Self-descriptive. Similar to ambient this includes only one mob: Glow Squids.
  • Water Creatures
    Water animals, i.e. dolphins and squid.
  • Water Ambient
    Fish, including cod, salmon, and tropical fish.
  • Miscellaneous
    Entities that don’t spawn naturally, such as boats or armour stands.

Each category has its own limit on how many mobs can spawn, known as a Mob Cap. The cap is adjusted based on the number of chunks loaded in. In single player this means the Mob Cap is fixed, but on servers it can be higher.

Butterflies spawn under the Creature category, since they are normal animals like cows and sheep. Within each category, mobs are assigned Weights to determine how often they are picked from the pool. Whenever a spawn occurs, it uses these weights to choose a mob type. The odds of a mob type being selected is its weight divided by the total weight of all the mob types in its category.

For example, the weights for creatures in a Plains Biome are as follows. I copied this table from bithole, which proved to be a valuable reference. They go into more detail about Minecraft Mob Spawning than I have in this article so you should check it out:

Mob TypeWeightPack Size
Sheep124
Pig104
Chicken104
Cow84
Horse52–6
Donkey11–3

So the chances of a cow spawning is 8 out of 36, or around 22%.

The Overpopulation Problem


When I first set the spawn weights for butterflies, I set them way too high. Since each species adds four more rows to the above table, this meant that the chances of vanilla creatures spawning was close to zero. In modded worlds with Bok’s Banging Butterflies installed, it became almost impossible to find cows or sheep, meaning leather and wool was extremely hard to come by.

So I lowered the weights even more so that this wouldn’t happen. Now butterflies wouldn’t spawn too much, allowing animals like sheep, chicken, pigs, and so on to appear more often in the world. Unfortunately this also meant that butterflies barely spawned in the world anymore, leading to the comment above.

Finding the Right Balance


Clearly, I needed to do some real testing. My goal was to find spawn weights that kept butterflies visible while ensuring other animals remained accessible.

Using the mob spawning tables as a reference, I had a solid starting point for Spawn Weights. With these numbers in hand, I came up with a simple playtest plan:

  • Run around in survival mode and see if I can find at least three or four separate butterfly spawns within five minutes.
  • Ensure that vanilla animals are still present in reasonable numbers.

If both of these criteria were met, I’d consider the new spawn rates a success.

Putting it to the Test


I started altering spawn rates and testing things out in creative worlds. Eventually I found some values that seemed to work, and started testing it in survival worlds. Of course, I spawned in the middle of the ocean. Not a good start, since butterflies don’t spawn in ocean biomes…

Thankfully, I saw land nearby, and started swimming toward it.

As soon as I got to land I spotted some flying bugs. I was happy to see right away that butterflies were spawning.

Only to find out that they were bees. So the search continued.

Finally I came to a river and spotted some actual butterflies.

Nearby I found some moths as well. They’re a little tricky to see in this screenshot.

I ran around for a while longer and spotted several more spawns within a few minutes. I also spotted many other cows, sheep, pigs, and so on. The balance felt right, so I decided to release a new version with these spawn rates.

A Parity Problem


While working on the release and testing each version, I noticed something odd – eggs, caterpillars, and chrysalises weren’t spawning at all in 1.18.2. That’s because, unlike later versions, spawns aren’t data-driven in 1.18.2; they have to be hardcoded. I realised that when I ported the mod to that version, I didn’t actually implement the spawns very well.

There were 3 main problems with the code I had written:

  1. The spawn rates didn’t match other versions of the mod at all.
  2. The spawn rates didn’t take into account a butterfly’s rarity.
  3. Only butterflies were added to the list of spawns.

I decided that I need to rectify these problems to maintain parity between different versions of Minecraft. to start with, I deleted the spawn modifier JSON files, and removed the Python code that generated them. This serves us in removing unnecessary code, but also acts as a reminder that spawns work differently in this version.

To fix the parity issue, I needed a way to ensure butterfly rarity was handled consistently. The solution was extending the generate_code method to generate an enumeration for rarity in Java, similar to how I had previously handled Habitat in 1.18.2:

        output_file.write("""
    // A list of how rare each butterfly is.
    public static final ButterflyData.Rarity[] RARITIES = {
""")

        for butterfly in all:
            folders = [BUTTERFLIES_FOLDER, MALE_BUTTERFLIES_FOLDER, MOTHS_FOLDER, MALE_MOTHS_FOLDER, SPECIAL_FOLDER]
            rarity = None
            i = 0

            while rarity is None and i < len(folders):
                folder = folders[i]
                try:
                    with open(BUTTERFLY_DATA + folder + butterfly + ".json", 'r', encoding="utf8") as input_file:
                        json_data = json.load(input_file)

                    rarity = json_data["rarity"]
                except FileNotFoundError:
                    # doesn't exist
                    pass
                else:
                    # exists
                    pass

                i = i + 1

            output_file.write("""            ButterflyData.Rarity.""" + rarity.upper() + """,
""")

With this enumeration I could now rewrite my BiomeLoadingEvent handler to generate weights based on the rarity, the same as for all other versions of the mod. I also added spawns for eggs, caterpillars, and chrysalises, since I neglected to include them last time.

    /**
     * Add the spawns for each butterfly.
     * @param event The event we respond to in order to add the villages.
     */
    private void onBiomeLoading(BiomeLoadingEvent event)
    {
        List<RegistryObject<EntityType<ButterflyEgg>>> butterflyEggs = entityTypeRegistry.getButterflyEggs();
        List<RegistryObject<EntityType<Caterpillar>>> caterpillars = entityTypeRegistry.getCaterpillars();
        List<RegistryObject<EntityType<Chrysalis>>> chrysalises = entityTypeRegistry.getChrysalises();
        List<RegistryObject<EntityType<? extends Butterfly>>> butterflies = entityTypeRegistry.getButterflies();

        for (int i = 0; i < butterflies.size(); ++i) {

            // Set the weights based on rarity.
            int weight = 12;
            int maximum = 4;
            
            if (ButterflySpeciesList.RARITIES[i] == ButterflyData.Rarity.UNCOMMON) {
                weight = 8;
                maximum = 3;
            } else if (ButterflySpeciesList.RARITIES[i] == ButterflyData.Rarity.RARE) {
                weight = 4;
                maximum = 2;
            }

            // If the butterfly is in this habitat then add them to the spawn list.
            switch (ButterflySpeciesList.HABITATS[i]) {
                case FORESTS:
                    if (event.getCategory().equals(Biome.BiomeCategory.FOREST)){
                        event.getSpawns().addSpawn(MobCategory.CREATURE,
                                new MobSpawnSettings.SpawnerData(butterflyEggs.get(i).get(), weight, 1, maximum));
                        event.getSpawns().addSpawn(MobCategory.CREATURE,
                                new MobSpawnSettings.SpawnerData(caterpillars.get(i).get(), weight, 1, maximum));
                        event.getSpawns().addSpawn(MobCategory.CREATURE,
                                new MobSpawnSettings.SpawnerData(chrysalises.get(i).get(), weight, 1, maximum));
                        event.getSpawns().addSpawn(MobCategory.CREATURE,
                                new MobSpawnSettings.SpawnerData(butterflies.get(i).get(), weight, 1, maximum));
                    }

                    break;
    
                    // Cutting other habitats to keep things short.
            }
        }
    }

Now the 1.18.2 version of the mod will maintain parity with all other versions, meaning everyone playing with the mod should have the same experience.

Lesson of the Week


Not all bugs are crash bugs, or things not working as designed. Sometimes the design itself is bugged, as in this case. By attempting to limit how much the mod impacted other features, I’d made it so that the mod had barely any effect at all. Sometimes subtle can be effective, but you have to remember that people who install your mod want to be able to see your mod.

A well-balanced mod should feel like a natural part of the world—noticeable but not overwhelming. I think I’ve found a good balance this time, but as always, I’ll be keeping an eye out for feedback. After all, what’s game design without a little evolution?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.