This week I fixed a few bugs that had made it into Bok’s Banging Butterflies. Two have been present for a while, but I was unable to reproduce or fix them. The third was a bug introduced by my recent changes to texture generation.
Ugly Hummingbirds
With the addition of texture generation to the pipeline, I had a great way of generating all of my textures from four images per butterfly species. Unfortunately, there was still work left to do, as the hummingbird moths use a different model and texture, so this automation didn’t work for them. It left us with some ugly looking textures for any derived from them:
Fixing this was really just about doing a bit of extra work. I added a constant to the class, which was just an array containing the names of the three hummingbird moths in the mod already:
self.HUMMINGBIRD_MOTHS = [
'clearwing-hummingbird',
'hummingbird',
'white-lined-sphinx'
]
Then, to fix the butterfly scrolls GUI, I used this array to call a different method for hummingbird moths:
for texture in butterfly_entity_textures:
if any(moth in str(texture) for moth in self.HUMMINGBIRD_MOTHS):
self._generate_hummingbird_scroll_gui(scroll_image, nail_image, texture)
else:
self._generate_butterfly_scroll_gui(scroll_image, nail_image, texture)
I won’t go into detail on the _generate_hummingbird_scroll_gui() method as it is very similar to the code I showed last week, but you can see the it in my GitHub repository if you’re interested. With this new code, I now had Hummingbird Moth Scrolls that actually look nice:

For the other items I decided to generate a texture that is just the wings to be used by the other generation methods. I made sure to transform the image so it followed the same format as the default wings images used by other butterflies:
def _load_butterfly_entity_texture(self, f):
image = self._load_image(f)
# Is this a hummingbird moth?
if any(moth in str(f) for moth in self.HUMMINGBIRD_MOTHS):
# Get the wing texture
image = self._crop_image(image, (0, 9), (5, 6))
# Create a mirror image of the texture
reflected_image = image.transpose(Image.FLIP_LEFT_RIGHT)
# Create a new image with both wings
new_image = Image.new('RGBA', (image.width * 2, image.height))
new_image.paste(image, (0, 0))
new_image.paste(reflected_image, (image.width, 0))
# Rotate the image so it is facing the same way as other butterfly
# images
return self._rotate_image(new_image, -90)
else:
# Not a hummingbird, just extract the wings
return self._crop_image(image, (10, 0), (17, 20))
Then I just plug this method into the preloading of butterfly textures in the generate_textures() entry point for this class:
butterfly_entity_textures = [
[f, self._load_butterfly_entity_texture(f)]
for f in self.config.BUTTERFLY_ENTITY_TEXTURE_PATH.iterdir()
if f.suffix == ".png" and os.path.basename(f).startswith("butterfly_")
]
This gets passed into methods for generating item textures for spawn eggs, bottled butterflies, and butterfly scrolls. The item textures for hummingbird moths now also look good, and they fit in with the style of all the other textures.
Lost Bottled Moths
I’ve had a couple of comments saying that bottled butterflies don’t drop when destroyed over the last few months. I tried to reproduce the bug a few times, tested every version, and a server-client game, but to no avail. Without being able to reproduce the bug I had no idea what was wrong, or how to fix it.
Then I stumbled across it by accident while playing a modded game. I tried to break a bottle, and it didn’t drop. That’s when I realised the actual problem. Only some bottles don’t drop – when I tested the bug I just happened to select items that weren’t broken.
The problem was missing loot tables. And the reason for this was that I would filter out all loot tables in my data generation script:
src_files = [
p for p in cwd.rglob("*.json")
if base_entry in p.name and 'loot_table' not in str(p.parent)
]
This is because there are loot tables for some chysalises that will drop silk, and I don’t want them generated for other species. The problem is that this also means blocks (i.e. bottled butterflies) don’t get loot tables generated.
The fix is to ignore just entity loot tables, rather than all loot tables:
src_files = [
p for p in cwd.rglob("*.json")
if base_entry in p.name and 'loot_table\entities' not in str(p.parent)
]
Now the butterfly pipeline will generate loot tables for bottled butterflies, and will only ignore loot tables for chrysalises.
Butterfly Golem Anarchy
Another bug that was reported was that Butterfly Golems seemed to ignore spawn rules. They’re basically just reskinned Iron Golems so are supposed to behave exactly the same, but they were spawning in places Iron Golems normally can’t, which was breaking player’s iron farms.
I looked into this and discovered that I hadn’t registered any spawn rules for Iron Golems. This was a massive blunder on my part, so I quickly updated the event handler for spawn placement registration so that the Butterfly Golem would follow the same rules as the Iron Golem:
/**
* Register entity spawn placements here
* @param event The event information
*/
private void onSpawnPlacementRegister(SpawnPlacementRegisterEvent event) {
// <snip>
event.register(entityTypeRegistry.getButterflyGolem().get(),
SpawnPlacements.Type.ON_GROUND,
Heightmap.Types.MOTION_BLOCKING_NO_LEAVES,
Mob::checkMobSpawnRules,
SpawnPlacementRegisterEvent.Operation.AND);
}
I don’t know if this has fixed the bug, as I haven’t rigorously tested it. So I’ve kept the issue open in GitHub until I can investigate it properly and confirm that Butterfly Golems are spawning as expected.
Next Steps
Assuming no more bugs come in, next on my To-Do list are the following:
- Implement new variants for Peacock Pansy Butterflies and Common Grass Yellow Butterflies.
- Add a new effect to Butterflies when they are Mud Puddling.
I’m also considering designing a new way to summon Butterfly Golems, which would mean I could give them some unique abilities and wouldn’t have to worry about them interfering with iron farms any more. Unfortunately I can’t come up with any good ideas right now, but if you have any ideas or suggestions I’d love to hear about them, either in the comments below or in a new ticket.
