ProtocolLib

3M Downloads

Cannot modify merchant recipes in OPEN_WINDOW_MERCHANT packet

bo3tools opened this issue ยท 2 comments

commented

Describe the bug
Changes on List<MerchantRecipe> provided by PacketContainer.getMerchantRecipeLists().read() are not reflected in-game.

To Reproduce
Use minimal reproducible example:

ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();

PacketAdapter.AdapterParameteters params = PacketAdapter.params().plugin(this)
    .listenerPriority(ListenerPriority.NORMAL)
    .types(PacketType.Play.Server.OPEN_WINDOW_MERCHANT);

// Modify merchant recipes (normal priority)
protocolManager.addPacketListener(new PacketAdapter(params) {
    @Override
    public void onPacketSending(PacketEvent event) {
        PacketContainer packet = event.getPacket();

        // Set result of each trade to the coal item
        List<MerchantRecipe> merchantRecipes = packet.getMerchantRecipeLists().read(0);
        for (MerchantRecipe merchantRecipe: merchantRecipes) {
            merchantRecipe.getResult().setType(Material.COAL);
        }

        // Set merchant level to 3 and experience to 100
        packet.getIntegers().write(1, 3);
        packet.getIntegers().write(2, 100);
       
        event.setPacket(packet);
    }
});

// Log the changed packet (highest priority)
protocolManager.addPacketListener(new PacketAdapter(params.listenerPriority(ListenerPriority.HIGHEST)) {
    @Override
    public void onPacketSending(PacketEvent event) {
        PacketContainer packet = event.getPacket();

        int windowId = packet.getIntegers().read(0);
        int villagerLevel = packet.getIntegers().read(1);
        int villagerExperience = packet.getIntegers().read(2);
        boolean isRegularVillager = packet.getBooleans().read(0);
        boolean canRestock = packet.getBooleans().read(1);
        List<MerchantRecipe> merchantRecipes = packet.getMerchantRecipeLists().read(0);

        String tradeList = merchantRecipes.stream()
            .map((MerchantRecipe recipe) -> recipe.getIngredients().stream()
                .map((ItemStack itemStack) -> itemStack.getType().toString().toLowerCase())
                .collect(Collectors.joining(" + ")) + " => " + recipe.getResult().getType().toString().toLowerCase())
            .collect(Collectors.joining(", "));

        event.getPlayer().sendMessage("TradeList(Window=" + windowId +
            ", Lvl=" + villagerLevel + ", Exp=" + villagerExperience + ", CanRestock=" + canRestock +
            ", IsRegular=" + isRegularVillager + ", Trades=[" + tradeList + "]");
    }
});

Expected behavior
Merchant recipe to be modified.

Screenshots
Opening the merchant window. Merchant level and experience were changed, while trade results are unaffected.
image

Verifying the contents of the packet using a second packet listener with higher priority, result is indicated as coal.
image

Version Info
https://pastebin.com/xDcLAry6

Additional context
Add any other context about the problem here.

commented

You probably have to write the list back to the packet:

packet.getMerchantRecipeLists().write(0, list)

commented

You probably have to write the list back to the packet:

packet.getMerchantRecipeLists().write(0, list)

Writing the list back to the packet works, thanks!