Fixing Lepidopterist Trades

Porting and maintaining multiple versions of a mod can be a lot of work. Sometimes things slip through the cracks. One of those things were the Lepidopterist’s trade offers. I didn’t notice until after release that the Lepidopterist wasn’t offering all the trades they were supposed to.

So this bug has been around for a few versions. But today, I finally fixed it.

Finding the Problem


I first noticed the issue while playing on 1.21.4 in my own forever world. I came across a Lepidopterist selling only a Butterfly Net and nothing else.

That’s not right. Villagers are meant to have at least two trades at their starting level. I didn’t have time to look into it then, so I made a ticket and moved on.

Later, I revisited the issue in a test world. The problem was consistent: every Lepidopterist spawned with just the net for sale. After levelling them up I found that they offered no new trades at all. Clearly something was broken.

Digging into the Code


My mod registers new trades by responding to the VillagerTradesEvent. Normally, this works fine. But in 1.21.4, this event is triggered before the ServerAboutToStartEvent. At that point, the Butterfly Data isn’t loaded.

That’s a problem.

Without the Butterfly Data, the trade system has nothing to work with—no species, types, or rarities. But I’d solved a similar issue before when porting to 1.18.2, so I knew what to do: generate the required data ahead of time in code.

Code Generation


I already use the Python script to generate an array of Species in code, that can then be used without the Butterfly Data being loaded. All I had to do was extend that code generation function to include Butterfly Types and Rarities too.

Here’s a snippet of the updated Python code that generates the ButterflyType array:

        # Start of the array definition.
        output_file.write("""
    // A list of types of  butterflies.
    public static final ButterflyData.ButterflyType[] TYPES = {
""")

        # Iterate over all butterflies, moths, and specials
        for butterfly in all:

            folders = [BUTTERFLIES_FOLDER, MALE_BUTTERFLIES_FOLDER, MOTHS_FOLDER, MALE_MOTHS_FOLDER, SPECIAL_FOLDER]
            type = None
            i = 0

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

                    # Pull out the type if an exception wasn't thrown
                    type = json_data["type"]

                # If file not found, ignore the error and move on to the next folder
                except FileNotFoundError:
                    # doesn't exist
                    pass
                else:
                    # exists
                    pass

                i = i + 1

            # Write out the Butterfly Type
            output_file.write("""            ButterflyData.ButterflyType.""" + type.upper() + """,
""")

        # Finish defining the array
        output_file.write("""    };
""")

I do the same for Rarities as well. This means we now have access to the required data before any events are fired.

Updating the Event Handler


With the data generated up front, I updated the VillagerTradesEvent handler to use the static arrays instead of querying dynamic data:

            for (int i = 0; i < ButterflySpeciesList.SPECIES.length; ++i) {
                if (ButterflySpeciesList.TYPES[i] != ButterflyData.ButterflyType.SPECIAL) {
                    switch (ButterflySpeciesList.RARITIES[i]) {
                        case COMMON:
                            // Add trades here
                            break;

                        case UNCOMMON:
                            // Add trades here
                            break;

                        case RARE:
                            // Add trades here
                            break;
                    }
                }
            }

After implementing this, I loaded into the game to test. Sure enough, Lepidopterists now have trades again!

So, if you’re playing the mod in 1.21.4, you can finally get a collection of butterfly-related items from these villagers.

Next


There are still a few more bugs to squash before I get back to adding new features. Fixing bugs like this is worthwhile. Each one teaches you something new, and it makes future versions of the mod that much more robust.

Keep your foundations strong, and anything you build on top will be more stable.