Improving Quality of Life

This week I add a lot of quality of life improvements to the mod, as well as a bug fix. There aren’t really any major new features, but the mod is now a little easier to use, and is now compatible with mods that add custom biomes to Minecraft.

Spawning in Your Mod


The way I created the spawn rules for the butterflies originally was wrong. I didn’t quite understand how biome tags work, so I just used the biome names. But biome tags are a useful tool, especially if you want your new entities to be able to spawn in custom biomes.

When I originally created my biome modifiers, I based them around each entity, adding the biomes they can spawn in to a list. The right approach is to base them around the biome (or group of biomes) and add the entities you want to spawn in that list of tags.

Minecraft, Forge, and Fabric each have their own set of biome tags we can use that group biomes together. For example, is_plains will include all biomes that could be classified as a type of plain. Mods can add their own biomes to these tags, which means that by using these tags we can allow butterflies to spawn in biomes from other mods.

As an example, we can set up all the butterflies spawning in mushroom-based biomes using the following biome modifier.

{
  "type": "forge:add_spawns",
  "biomes": "#forge:is_mushroom",
  "spawners": [
    {
      "type": "butterflies:buckeye",
      "weight": 10,
      "minCount": 3,
      "maxCount": 5
    },
    {
      "type": "butterflies:buckeye_caterpillar",
      "weight": 10,
      "minCount": 3,
      "maxCount": 5
    },
    {
      "type": "butterflies:buckeye_chrysalis",
      "weight": 10,
      "minCount": 3,
      "maxCount": 5
    },
    {
      "type": "butterflies:buckeye_egg",
      "weight": 10,
      "minCount": 3,
      "maxCount": 5
    },
    {
      "type": "butterflies:cabbage",
      "weight": 10,
      "minCount": 3,
      "maxCount": 5
    },
    {
      "type": "butterflies:cabbage_caterpillar",
      "weight": 10,
      "minCount": 3,
      "maxCount": 5
    },
    {
      "type": "butterflies:cabbage_chrysalis",
      "weight": 10,
      "minCount": 3,
      "maxCount": 5
    },
    {
      "type": "butterflies:cabbage_egg",
      "weight": 10,
      "minCount": 3,
      "maxCount": 5
    },
    {
      "type": "butterflies:rainbow",
      "weight": 5,
      "minCount": 2,
      "maxCount": 4
    },
    {
      "type": "butterflies:rainbow_caterpillar",
      "weight": 5,
      "minCount": 2,
      "maxCount": 4
    },
    {
      "type": "butterflies:rainbow_chrysalis",
      "weight": 5,
      "minCount": 2,
      "maxCount": 4
    },
    {
      "type": "butterflies:rainbow_egg",
      "weight": 5,
      "minCount": 2,
      "maxCount": 4
    }
  ]
}

I redesigned the spawn rules for each butterfly slightly so I could take advantage of the tags. In order to take advantage tags, I had to account for butterflies to spawn in slightly different biomes, but in general they are the same. I didn’t use tags for cherry groves or for river biomes, since I really didn’t want butterflies spawning in other biomes they were tagged in.

Shout out to Rat for clocking me on to biome tags.

Bottle Crash

I woke up one morning to a bug report from EclipseLB: breaking bottled butterflies would cause their server to crash. Thanks to them including a call stack I was able to see exactly which line of code was causing the crash, and after a short amount of research I figured out the problem.

The server-side of Forge doesn’t include apache.commons, a library I was using to create new lists. In modern day Java, we don’t need to use it anymore, so the fix was simple. Instead of using:

            List<ItemStack> result = Lists.newArrayList();

We can use type inference to write a line that is just as simple:

List<ItemStack> result = new ArrayList<>();

This removes our dependency on apache.commons and now servers will not crash if a player decides they want to move a bottled butterfly.

Butterfly Love

I wanted to add a bit of visual feedback for butterfly breeding so that players could see if their attempts to breed butterflies were working. So, like other animals and villagers, I wanted a heart effect to show when they become fertile.

After spending a while trying to figure out how to code the particle effect, I realised that they were Animals. This meant I could just call setInLove() and Minecraft’s base code would handle it for us.

                    for (Butterfly i : nearbyButterflies) {
                        if (i.getType() == this.getType()) {
                            setIsFertile(true);
                            setInLove(null);
                            break;
                        }
                    }

While I was digging through the code, I also noticed that by default all animals could be fed wheat to set them in love mode. This is not something I want butterflies to do, so I added an override to all butterfly entities to prevent this.

    /**
     * Butterflies can't be fed by players.
     * @param stack The item stack the player tried to feed the butterfly.
     * @return FALSE, indicating it isn't food.
     */
    @Override
    public boolean isFood(@NotNull ItemStack stack) {
        return false;
    }

This isn’t game breaking so I haven’t made a release for this one yet, so you can try feeding butterflies wheat before version 3.3.1 if you want to see something fun.

Here’s a Hint

Another idea I had that I have finally gotten around to implementing is to add some hints on how to use the items in the mod. I had someone ask me how to catch butterflies with the net, so it would be nice if the mod could tell them how to use items without players having to find a readme or figure it out another way.

To do this, I first added a few new strings to my en_us.json:

  "tooltip.butterflies.butterfly_net": "Swing (left-click) at a butterfly to catch it",
  "tooltip.butterflies.release_butterfly": "Right click to release the butterfly",
  "tooltip.butterflies.release_caterpillar": "Right click to release the caterpillar",
  "tooltip.butterflies.place_caterpillar": "Right-click on leaves to place the caterpillar",
  "tooltip.butterflies.place_egg": "Right-click on leaves to place the butterfly egg",
  "tooltip.butterflies.scroll": "Right-click to read or to place on a block"

After that I just needed to modify each item’s appendHoverText() method to include the new text. For example, the bottled butterfly now gives a hint on how to release butterflies:

    /**
     * Adds some helper text.
     * @param stack The item stack.
     * @param level The current level.
     * @param components The current text components.
     * @param tooltipFlag Is this a tooltip?
     */
    @Override
    public void appendHoverText(@NotNull ItemStack stack,
                                @Nullable Level level,
                                @NotNull List<Component> components,
                                @NotNull TooltipFlag tooltipFlag) {
        appendButterflyNameToHoverText(stack, components);

        MutableComponent newComponent = Component.translatable("tooltip.butterflies.release_butterfly");
        Style style = newComponent.getStyle().withColor(TextColor.fromLegacyFormat(ChatFormatting.GRAY))
                .withItalic(true);
        newComponent.setStyle(style);
        components.add(newComponent);

        super.appendHoverText(stack, level, components, tooltipFlag);
    }

Hopefully this makes the mod easier to use for newcomers. It’s a pattern I’ll keep using for any future items I add to the mod as well, since it’s nice if people can just pick up and play without any required reading beforehand.

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.