From fdd2684432023644fee137cf69d95a9130cb96f6 Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Fri, 1 May 2026 14:34:05 +0200 Subject: [PATCH] feat: add Villager trading currently job selection is missing --- assets/villager_data.json | 1 + pumpkin-codegen/Cargo.lock | 1 + pumpkin-codegen/Cargo.toml | 2 +- pumpkin-codegen/src/main.rs | 2 + pumpkin-codegen/src/villager.rs | 328 ++ pumpkin-data/Cargo.toml | 2 + pumpkin-data/src/generated/villager.rs | 4676 +++++++++++++++++ pumpkin-data/src/lib.rs | 5 + .../src/brewing/brewing_screen_handler.rs | 4 + .../src/crafting/crafting_screen_handler.rs | 4 + .../furnace_like_screen_handler.rs | 4 + .../src/generic_container_screen_handler.rs | 4 + pumpkin-inventory/src/gui_builder.rs | 4 + pumpkin-inventory/src/lib.rs | 1 + .../src/merchant/merchant_screen_handler.rs | 222 + pumpkin-inventory/src/merchant/mod.rs | 1 + .../src/player/player_screen_handler.rs | 4 + pumpkin-inventory/src/screen_handler.rs | 3 + .../src/codec/item_stack_seralizer.rs | 1 + .../src/java/client/play/merchant_offers.rs | 52 + pumpkin-protocol/src/java/client/play/mod.rs | 2 + pumpkin-protocol/src/java/server/play/mod.rs | 2 + .../src/java/server/play/select_trade.rs | 11 + pumpkin-world/src/inventory/mod.rs | 2 + .../src/inventory/simple_inventory.rs | 73 + pumpkin/src/entity/passive/villager.rs | 55 - pumpkin/src/entity/passive/villager/data.rs | 48 + pumpkin/src/entity/passive/villager/mod.rs | 459 ++ pumpkin/src/net/java/mod.rs | 8 +- pumpkin/src/net/java/play.rs | 18 +- pumpkin/src/plugin/api/gui.rs | 4 + 31 files changed, 5943 insertions(+), 60 deletions(-) create mode 100644 assets/villager_data.json create mode 100644 pumpkin-codegen/src/villager.rs create mode 100644 pumpkin-data/src/generated/villager.rs create mode 100644 pumpkin-inventory/src/merchant/merchant_screen_handler.rs create mode 100644 pumpkin-inventory/src/merchant/mod.rs create mode 100644 pumpkin-protocol/src/java/client/play/merchant_offers.rs create mode 100644 pumpkin-protocol/src/java/server/play/select_trade.rs create mode 100644 pumpkin-world/src/inventory/simple_inventory.rs delete mode 100644 pumpkin/src/entity/passive/villager.rs create mode 100644 pumpkin/src/entity/passive/villager/data.rs create mode 100644 pumpkin/src/entity/passive/villager/mod.rs diff --git a/assets/villager_data.json b/assets/villager_data.json new file mode 100644 index 000000000..f09d26b20 --- /dev/null +++ b/assets/villager_data.json @@ -0,0 +1 @@ +{"professions":{"none":{"name":{"translate":"entity.minecraft.villager.none"},"requested_items":[],"secondary_poi":[],"trade_sets":{}},"armorer":{"name":{"translate":"entity.minecraft.villager.armorer"},"requested_items":[],"secondary_poi":[],"work_sound":"minecraft:entity.villager.work_armorer","trade_sets":{"1":"minecraft:armorer/level_1","2":"minecraft:armorer/level_2","3":"minecraft:armorer/level_3","4":"minecraft:armorer/level_4","5":"minecraft:armorer/level_5"}},"butcher":{"name":{"translate":"entity.minecraft.villager.butcher"},"requested_items":[],"secondary_poi":[],"work_sound":"minecraft:entity.villager.work_butcher","trade_sets":{"1":"minecraft:butcher/level_1","2":"minecraft:butcher/level_2","3":"minecraft:butcher/level_3","4":"minecraft:butcher/level_4","5":"minecraft:butcher/level_5"}},"cartographer":{"name":{"translate":"entity.minecraft.villager.cartographer"},"requested_items":[],"secondary_poi":[],"work_sound":"minecraft:entity.villager.work_cartographer","trade_sets":{"1":"minecraft:cartographer/level_1","2":"minecraft:cartographer/level_2","3":"minecraft:cartographer/level_3","4":"minecraft:cartographer/level_4","5":"minecraft:cartographer/level_5"}},"cleric":{"name":{"translate":"entity.minecraft.villager.cleric"},"requested_items":[],"secondary_poi":[],"work_sound":"minecraft:entity.villager.work_cleric","trade_sets":{"1":"minecraft:cleric/level_1","2":"minecraft:cleric/level_2","3":"minecraft:cleric/level_3","4":"minecraft:cleric/level_4","5":"minecraft:cleric/level_5"}},"farmer":{"name":{"translate":"entity.minecraft.villager.farmer"},"requested_items":["minecraft:wheat","minecraft:wheat_seeds","minecraft:beetroot_seeds","minecraft:bone_meal"],"secondary_poi":["minecraft:farmland"],"work_sound":"minecraft:entity.villager.work_farmer","trade_sets":{"1":"minecraft:farmer/level_1","2":"minecraft:farmer/level_2","3":"minecraft:farmer/level_3","4":"minecraft:farmer/level_4","5":"minecraft:farmer/level_5"}},"fisherman":{"name":{"translate":"entity.minecraft.villager.fisherman"},"requested_items":[],"secondary_poi":[],"work_sound":"minecraft:entity.villager.work_fisherman","trade_sets":{"1":"minecraft:fisherman/level_1","2":"minecraft:fisherman/level_2","3":"minecraft:fisherman/level_3","4":"minecraft:fisherman/level_4","5":"minecraft:fisherman/level_5"}},"fletcher":{"name":{"translate":"entity.minecraft.villager.fletcher"},"requested_items":[],"secondary_poi":[],"work_sound":"minecraft:entity.villager.work_fletcher","trade_sets":{"1":"minecraft:fletcher/level_1","2":"minecraft:fletcher/level_2","3":"minecraft:fletcher/level_3","4":"minecraft:fletcher/level_4","5":"minecraft:fletcher/level_5"}},"leatherworker":{"name":{"translate":"entity.minecraft.villager.leatherworker"},"requested_items":[],"secondary_poi":[],"work_sound":"minecraft:entity.villager.work_leatherworker","trade_sets":{"1":"minecraft:leatherworker/level_1","2":"minecraft:leatherworker/level_2","3":"minecraft:leatherworker/level_3","4":"minecraft:leatherworker/level_4","5":"minecraft:leatherworker/level_5"}},"librarian":{"name":{"translate":"entity.minecraft.villager.librarian"},"requested_items":[],"secondary_poi":[],"work_sound":"minecraft:entity.villager.work_librarian","trade_sets":{"1":"minecraft:librarian/level_1","2":"minecraft:librarian/level_2","3":"minecraft:librarian/level_3","4":"minecraft:librarian/level_4","5":"minecraft:librarian/level_5"}},"mason":{"name":{"translate":"entity.minecraft.villager.mason"},"requested_items":[],"secondary_poi":[],"work_sound":"minecraft:entity.villager.work_mason","trade_sets":{"1":"minecraft:mason/level_1","2":"minecraft:mason/level_2","3":"minecraft:mason/level_3","4":"minecraft:mason/level_4","5":"minecraft:mason/level_5"}},"nitwit":{"name":{"translate":"entity.minecraft.villager.nitwit"},"requested_items":[],"secondary_poi":[],"trade_sets":{}},"shepherd":{"name":{"translate":"entity.minecraft.villager.shepherd"},"requested_items":[],"secondary_poi":[],"work_sound":"minecraft:entity.villager.work_shepherd","trade_sets":{"1":"minecraft:shepherd/level_1","2":"minecraft:shepherd/level_2","3":"minecraft:shepherd/level_3","4":"minecraft:shepherd/level_4","5":"minecraft:shepherd/level_5"}},"toolsmith":{"name":{"translate":"entity.minecraft.villager.toolsmith"},"requested_items":[],"secondary_poi":[],"work_sound":"minecraft:entity.villager.work_toolsmith","trade_sets":{"1":"minecraft:toolsmith/level_1","2":"minecraft:toolsmith/level_2","3":"minecraft:toolsmith/level_3","4":"minecraft:toolsmith/level_4","5":"minecraft:toolsmith/level_5"}},"weaponsmith":{"name":{"translate":"entity.minecraft.villager.weaponsmith"},"requested_items":[],"secondary_poi":[],"work_sound":"minecraft:entity.villager.work_weaponsmith","trade_sets":{"1":"minecraft:weaponsmith/level_1","2":"minecraft:weaponsmith/level_2","3":"minecraft:weaponsmith/level_3","4":"minecraft:weaponsmith/level_4","5":"minecraft:weaponsmith/level_5"}}},"types":{"desert":"minecraft:desert","jungle":"minecraft:jungle","plains":"minecraft:plains","savanna":"minecraft:savanna","snow":"minecraft:snow","swamp":"minecraft:swamp","taiga":"minecraft:taiga"},"trade_sets":{"armorer/level_1":{"trades":"#minecraft:armorer/level_1","amount":2.0,"random_sequence":"minecraft:trade_set/armorer/level_1"},"armorer/level_2":{"trades":"#minecraft:armorer/level_2","amount":2.0,"random_sequence":"minecraft:trade_set/armorer/level_2"},"armorer/level_3":{"trades":"#minecraft:armorer/level_3","amount":2.0,"random_sequence":"minecraft:trade_set/armorer/level_3"},"armorer/level_4":{"trades":"#minecraft:armorer/level_4","amount":2.0,"random_sequence":"minecraft:trade_set/armorer/level_4"},"armorer/level_5":{"trades":"#minecraft:armorer/level_5","amount":2.0,"random_sequence":"minecraft:trade_set/armorer/level_5"},"butcher/level_1":{"trades":"#minecraft:butcher/level_1","amount":2.0,"random_sequence":"minecraft:trade_set/butcher/level_1"},"butcher/level_2":{"trades":"#minecraft:butcher/level_2","amount":2.0,"random_sequence":"minecraft:trade_set/butcher/level_2"},"butcher/level_3":{"trades":"#minecraft:butcher/level_3","amount":2.0,"random_sequence":"minecraft:trade_set/butcher/level_3"},"butcher/level_4":{"trades":"#minecraft:butcher/level_4","amount":2.0,"random_sequence":"minecraft:trade_set/butcher/level_4"},"butcher/level_5":{"trades":"#minecraft:butcher/level_5","amount":2.0,"random_sequence":"minecraft:trade_set/butcher/level_5"},"cartographer/level_1":{"trades":"#minecraft:cartographer/level_1","amount":2.0,"random_sequence":"minecraft:trade_set/cartographer/level_1"},"cartographer/level_2":{"trades":"#minecraft:cartographer/level_2","amount":2.0,"random_sequence":"minecraft:trade_set/cartographer/level_2"},"cartographer/level_3":{"trades":"#minecraft:cartographer/level_3","amount":2.0,"random_sequence":"minecraft:trade_set/cartographer/level_3"},"cartographer/level_4":{"trades":"#minecraft:cartographer/level_4","amount":2.0,"random_sequence":"minecraft:trade_set/cartographer/level_4"},"cartographer/level_5":{"trades":"#minecraft:cartographer/level_5","amount":2.0,"random_sequence":"minecraft:trade_set/cartographer/level_5"},"cleric/level_1":{"trades":"#minecraft:cleric/level_1","amount":2.0,"random_sequence":"minecraft:trade_set/cleric/level_1"},"cleric/level_2":{"trades":"#minecraft:cleric/level_2","amount":2.0,"random_sequence":"minecraft:trade_set/cleric/level_2"},"cleric/level_3":{"trades":"#minecraft:cleric/level_3","amount":2.0,"random_sequence":"minecraft:trade_set/cleric/level_3"},"cleric/level_4":{"trades":"#minecraft:cleric/level_4","amount":2.0,"random_sequence":"minecraft:trade_set/cleric/level_4"},"cleric/level_5":{"trades":"#minecraft:cleric/level_5","amount":2.0,"random_sequence":"minecraft:trade_set/cleric/level_5"},"farmer/level_1":{"trades":"#minecraft:farmer/level_1","amount":2.0,"random_sequence":"minecraft:trade_set/farmer/level_1"},"farmer/level_2":{"trades":"#minecraft:farmer/level_2","amount":2.0,"random_sequence":"minecraft:trade_set/farmer/level_2"},"farmer/level_3":{"trades":"#minecraft:farmer/level_3","amount":2.0,"random_sequence":"minecraft:trade_set/farmer/level_3"},"farmer/level_4":{"trades":"#minecraft:farmer/level_4","amount":2.0,"random_sequence":"minecraft:trade_set/farmer/level_4"},"farmer/level_5":{"trades":"#minecraft:farmer/level_5","amount":2.0,"random_sequence":"minecraft:trade_set/farmer/level_5"},"fisherman/level_1":{"trades":"#minecraft:fisherman/level_1","amount":2.0,"random_sequence":"minecraft:trade_set/fisherman/level_1"},"fisherman/level_2":{"trades":"#minecraft:fisherman/level_2","amount":2.0,"random_sequence":"minecraft:trade_set/fisherman/level_2"},"fisherman/level_3":{"trades":"#minecraft:fisherman/level_3","amount":2.0,"random_sequence":"minecraft:trade_set/fisherman/level_3"},"fisherman/level_4":{"trades":"#minecraft:fisherman/level_4","amount":2.0,"random_sequence":"minecraft:trade_set/fisherman/level_4"},"fisherman/level_5":{"trades":"#minecraft:fisherman/level_5","amount":2.0,"random_sequence":"minecraft:trade_set/fisherman/level_5"},"fletcher/level_1":{"trades":"#minecraft:fletcher/level_1","amount":2.0,"random_sequence":"minecraft:trade_set/fletcher/level_1"},"fletcher/level_2":{"trades":"#minecraft:fletcher/level_2","amount":2.0,"random_sequence":"minecraft:trade_set/fletcher/level_2"},"fletcher/level_3":{"trades":"#minecraft:fletcher/level_3","amount":2.0,"random_sequence":"minecraft:trade_set/fletcher/level_3"},"fletcher/level_4":{"trades":"#minecraft:fletcher/level_4","amount":2.0,"random_sequence":"minecraft:trade_set/fletcher/level_4"},"fletcher/level_5":{"trades":"#minecraft:fletcher/level_5","amount":2.0,"random_sequence":"minecraft:trade_set/fletcher/level_5"},"leatherworker/level_1":{"trades":"#minecraft:leatherworker/level_1","amount":2.0,"random_sequence":"minecraft:trade_set/leatherworker/level_1"},"leatherworker/level_2":{"trades":"#minecraft:leatherworker/level_2","amount":2.0,"random_sequence":"minecraft:trade_set/leatherworker/level_2"},"leatherworker/level_3":{"trades":"#minecraft:leatherworker/level_3","amount":2.0,"random_sequence":"minecraft:trade_set/leatherworker/level_3"},"leatherworker/level_4":{"trades":"#minecraft:leatherworker/level_4","amount":2.0,"random_sequence":"minecraft:trade_set/leatherworker/level_4"},"leatherworker/level_5":{"trades":"#minecraft:leatherworker/level_5","amount":2.0,"random_sequence":"minecraft:trade_set/leatherworker/level_5"},"librarian/level_1":{"trades":"#minecraft:librarian/level_1","amount":2.0,"random_sequence":"minecraft:trade_set/librarian/level_1"},"librarian/level_2":{"trades":"#minecraft:librarian/level_2","amount":2.0,"random_sequence":"minecraft:trade_set/librarian/level_2"},"librarian/level_3":{"trades":"#minecraft:librarian/level_3","amount":2.0,"random_sequence":"minecraft:trade_set/librarian/level_3"},"librarian/level_4":{"trades":"#minecraft:librarian/level_4","amount":2.0,"random_sequence":"minecraft:trade_set/librarian/level_4"},"librarian/level_5":{"trades":"#minecraft:librarian/level_5","amount":3.0,"random_sequence":"minecraft:trade_set/librarian/level_5"},"mason/level_1":{"trades":"#minecraft:mason/level_1","amount":2.0,"random_sequence":"minecraft:trade_set/mason/level_1"},"mason/level_2":{"trades":"#minecraft:mason/level_2","amount":2.0,"random_sequence":"minecraft:trade_set/mason/level_2"},"mason/level_3":{"trades":"#minecraft:mason/level_3","amount":2.0,"random_sequence":"minecraft:trade_set/mason/level_3"},"mason/level_4":{"trades":"#minecraft:mason/level_4","amount":2.0,"random_sequence":"minecraft:trade_set/mason/level_4"},"mason/level_5":{"trades":"#minecraft:mason/level_5","amount":2.0,"random_sequence":"minecraft:trade_set/mason/level_5"},"shepherd/level_1":{"trades":"#minecraft:shepherd/level_1","amount":2.0,"random_sequence":"minecraft:trade_set/shepherd/level_1"},"shepherd/level_2":{"trades":"#minecraft:shepherd/level_2","amount":2.0,"random_sequence":"minecraft:trade_set/shepherd/level_2"},"shepherd/level_3":{"trades":"#minecraft:shepherd/level_3","amount":2.0,"random_sequence":"minecraft:trade_set/shepherd/level_3"},"shepherd/level_4":{"trades":"#minecraft:shepherd/level_4","amount":2.0,"random_sequence":"minecraft:trade_set/shepherd/level_4"},"shepherd/level_5":{"trades":"#minecraft:shepherd/level_5","amount":2.0,"random_sequence":"minecraft:trade_set/shepherd/level_5"},"toolsmith/level_1":{"trades":"#minecraft:toolsmith/level_1","amount":2.0,"random_sequence":"minecraft:trade_set/toolsmith/level_1"},"toolsmith/level_2":{"trades":"#minecraft:toolsmith/level_2","amount":2.0,"random_sequence":"minecraft:trade_set/toolsmith/level_2"},"toolsmith/level_3":{"trades":"#minecraft:toolsmith/level_3","amount":2.0,"random_sequence":"minecraft:trade_set/toolsmith/level_3"},"toolsmith/level_4":{"trades":"#minecraft:toolsmith/level_4","amount":2.0,"random_sequence":"minecraft:trade_set/toolsmith/level_4"},"toolsmith/level_5":{"trades":"#minecraft:toolsmith/level_5","amount":2.0,"random_sequence":"minecraft:trade_set/toolsmith/level_5"},"wandering_trader/buying":{"trades":"#minecraft:wandering_trader/buying","amount":2.0,"random_sequence":"minecraft:trade_set/wandering_trader/buying"},"wandering_trader/common":{"trades":"#minecraft:wandering_trader/common","amount":5.0,"random_sequence":"minecraft:trade_set/wandering_trader/common"},"wandering_trader/uncommon":{"trades":"#minecraft:wandering_trader/uncommon","amount":2.0,"random_sequence":"minecraft:trade_set/wandering_trader/uncommon"},"weaponsmith/level_1":{"trades":"#minecraft:weaponsmith/level_1","amount":2.0,"random_sequence":"minecraft:trade_set/weaponsmith/level_1"},"weaponsmith/level_2":{"trades":"#minecraft:weaponsmith/level_2","amount":2.0,"random_sequence":"minecraft:trade_set/weaponsmith/level_2"},"weaponsmith/level_3":{"trades":"#minecraft:weaponsmith/level_3","amount":2.0,"random_sequence":"minecraft:trade_set/weaponsmith/level_3"},"weaponsmith/level_4":{"trades":"#minecraft:weaponsmith/level_4","amount":2.0,"random_sequence":"minecraft:trade_set/weaponsmith/level_4"},"weaponsmith/level_5":{"trades":"#minecraft:weaponsmith/level_5","amount":2.0,"random_sequence":"minecraft:trade_set/weaponsmith/level_5"}},"villager_trades":{"armorer/1/emerald_iron_boots":{"wants":{"id":"minecraft:emerald","count":4.0},"gives":{"id":"minecraft:iron_boots"},"max_uses":12.0,"reputation_discount":0.2},"armorer/1/emerald_iron_chestplate":{"wants":{"id":"minecraft:emerald","count":9.0},"gives":{"id":"minecraft:iron_chestplate"},"max_uses":12.0,"reputation_discount":0.2},"armorer/1/emerald_iron_helmet":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:iron_helmet"},"max_uses":12.0,"reputation_discount":0.2},"armorer/1/emerald_iron_leggings":{"wants":{"id":"minecraft:emerald","count":7.0},"gives":{"id":"minecraft:iron_leggings"},"max_uses":12.0,"reputation_discount":0.2},"armorer/2/emerald_chainmail_boots":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:chainmail_boots"},"max_uses":12.0,"reputation_discount":0.2,"xp":5.0},"armorer/2/emerald_chainmail_leggings":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:chainmail_leggings"},"max_uses":12.0,"reputation_discount":0.2,"xp":5.0},"armorer/3/diamond_emerald":{"wants":{"id":"minecraft:diamond"},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":20.0},"armorer/3/emerald_chainmail_chestplate":{"wants":{"id":"minecraft:emerald","count":4.0},"gives":{"id":"minecraft:chainmail_chestplate"},"max_uses":12.0,"reputation_discount":0.2,"xp":10.0},"armorer/3/emerald_chainmail_helmet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:chainmail_helmet"},"max_uses":12.0,"reputation_discount":0.2,"xp":10.0},"armorer/3/emerald_shield":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:shield"},"max_uses":12.0,"reputation_discount":0.2,"xp":10.0},"armorer/3/lava_bucket_emerald":{"wants":{"id":"minecraft:lava_bucket"},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":20.0},"armorer/4/emerald_enchanted_diamond_boots":{"wants":{"id":"minecraft:emerald","count":8.0},"gives":{"id":"minecraft:diamond_boots"},"max_uses":3.0,"reputation_discount":0.2,"xp":15.0,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:diamond_boots","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"armorer/4/emerald_enchanted_diamond_leggings":{"wants":{"id":"minecraft:emerald","count":14.0},"gives":{"id":"minecraft:diamond_leggings"},"max_uses":3.0,"reputation_discount":0.2,"xp":15.0,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:diamond_leggings","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"armorer/5/emerald_enchanted_diamond_chestplate":{"wants":{"id":"minecraft:emerald","count":16.0},"gives":{"id":"minecraft:diamond_chestplate"},"max_uses":3.0,"reputation_discount":0.2,"xp":30.0,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:diamond_chestplate","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"armorer/5/emerald_enchanted_diamond_helmet":{"wants":{"id":"minecraft:emerald","count":8.0},"gives":{"id":"minecraft:diamond_helmet"},"max_uses":3.0,"reputation_discount":0.2,"xp":30.0,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:diamond_helmet","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"butcher/1/chicken_emerald":{"wants":{"id":"minecraft:chicken","count":14.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"butcher/1/emerald_rabbit_stew":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:rabbit_stew"},"max_uses":12.0,"reputation_discount":0.05},"butcher/1/porkchop_emerald":{"wants":{"id":"minecraft:porkchop","count":7.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"butcher/1/rabbit_emerald":{"wants":{"id":"minecraft:rabbit","count":4.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"butcher/2/coal_emerald":{"wants":{"id":"minecraft:coal","count":15.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"butcher/2/emerald_cooked_chicken":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:cooked_chicken","count":8},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"butcher/2/emerald_cooked_porkchop":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:cooked_porkchop","count":5},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"butcher/3/beef_emerald":{"wants":{"id":"minecraft:beef","count":10.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":20.0},"butcher/3/mutton_emerald":{"wants":{"id":"minecraft:mutton","count":7.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":20.0},"butcher/4/dried_kelp_block_emerald":{"wants":{"id":"minecraft:dried_kelp_block","count":10.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"butcher/5/sweet_berries_emerald":{"wants":{"id":"minecraft:sweet_berries","count":10.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"cartographer/1/emerald_map":{"wants":{"id":"minecraft:emerald","count":7.0},"gives":{"id":"minecraft:map"},"max_uses":12.0,"reputation_discount":0.05},"cartographer/1/paper_emerald":{"wants":{"id":"minecraft:paper","count":24.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":2.0},"cartographer/2/emerald_and_compass_explorer_jungle_map":{"wants":{"id":"minecraft:emerald","count":8.0},"additional_wants":{"id":"minecraft:compass"},"gives":{"id":"minecraft:map"},"max_uses":12.0,"reputation_discount":0.2,"xp":5.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:swamp","minecraft:savanna","minecraft:desert"]}},"entity":"this","condition":"minecraft:entity_properties"},"given_item_modifiers":[{"destination":"minecraft:on_jungle_explorer_maps","decoration":"minecraft:jungle_temple","search_radius":100,"function":"minecraft:exploration_map"},{"name":{"translate":"filled_map.explorer_jungle"},"target":"item_name","function":"minecraft:set_name"},{"item_filter":{"items":"minecraft:filled_map","predicates":{"minecraft:map_id":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"cartographer/2/emerald_and_compass_explorer_swamp_map":{"wants":{"id":"minecraft:emerald","count":8.0},"additional_wants":{"id":"minecraft:compass"},"gives":{"id":"minecraft:map"},"max_uses":12.0,"reputation_discount":0.2,"xp":5.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:taiga","minecraft:snow","minecraft:jungle"]}},"entity":"this","condition":"minecraft:entity_properties"},"given_item_modifiers":[{"destination":"minecraft:on_swamp_explorer_maps","decoration":"minecraft:swamp_hut","search_radius":100,"function":"minecraft:exploration_map"},{"name":{"translate":"filled_map.explorer_swamp"},"target":"item_name","function":"minecraft:set_name"},{"item_filter":{"items":"minecraft:filled_map","predicates":{"minecraft:map_id":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"cartographer/2/emerald_and_compass_village_desert_map":{"wants":{"id":"minecraft:emerald","count":8.0},"additional_wants":{"id":"minecraft:compass"},"gives":{"id":"minecraft:map"},"max_uses":12.0,"reputation_discount":0.2,"xp":5.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:savanna","minecraft:jungle"]}},"entity":"this","condition":"minecraft:entity_properties"},"given_item_modifiers":[{"destination":"minecraft:on_desert_village_maps","decoration":"minecraft:village_desert","search_radius":100,"function":"minecraft:exploration_map"},{"name":{"translate":"filled_map.village_desert"},"target":"item_name","function":"minecraft:set_name"},{"item_filter":{"items":"minecraft:filled_map","predicates":{"minecraft:map_id":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"cartographer/2/emerald_and_compass_village_plains_map":{"wants":{"id":"minecraft:emerald","count":8.0},"additional_wants":{"id":"minecraft:compass"},"gives":{"id":"minecraft:map"},"max_uses":12.0,"reputation_discount":0.2,"xp":5.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:taiga","minecraft:snow","minecraft:savanna","minecraft:desert"]}},"entity":"this","condition":"minecraft:entity_properties"},"given_item_modifiers":[{"destination":"minecraft:on_plains_village_maps","decoration":"minecraft:village_plains","search_radius":100,"function":"minecraft:exploration_map"},{"name":{"translate":"filled_map.village_plains"},"target":"item_name","function":"minecraft:set_name"},{"item_filter":{"items":"minecraft:filled_map","predicates":{"minecraft:map_id":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"cartographer/2/emerald_and_compass_village_savanna_map":{"wants":{"id":"minecraft:emerald","count":8.0},"additional_wants":{"id":"minecraft:compass"},"gives":{"id":"minecraft:map"},"max_uses":12.0,"reputation_discount":0.2,"xp":5.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:plains","minecraft:jungle","minecraft:desert"]}},"entity":"this","condition":"minecraft:entity_properties"},"given_item_modifiers":[{"destination":"minecraft:on_savanna_village_maps","decoration":"minecraft:village_savanna","search_radius":100,"function":"minecraft:exploration_map"},{"name":{"translate":"filled_map.village_savanna"},"target":"item_name","function":"minecraft:set_name"},{"item_filter":{"items":"minecraft:filled_map","predicates":{"minecraft:map_id":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"cartographer/2/emerald_and_compass_village_snowy_map":{"wants":{"id":"minecraft:emerald","count":8.0},"additional_wants":{"id":"minecraft:compass"},"gives":{"id":"minecraft:map"},"max_uses":12.0,"reputation_discount":0.2,"xp":5.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:taiga","minecraft:swamp"]}},"entity":"this","condition":"minecraft:entity_properties"},"given_item_modifiers":[{"destination":"minecraft:on_snowy_village_maps","decoration":"minecraft:village_snowy","search_radius":100,"function":"minecraft:exploration_map"},{"name":{"translate":"filled_map.village_snowy"},"target":"item_name","function":"minecraft:set_name"},{"item_filter":{"items":"minecraft:filled_map","predicates":{"minecraft:map_id":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"cartographer/2/emerald_and_compass_village_taiga_map":{"wants":{"id":"minecraft:emerald","count":8.0},"additional_wants":{"id":"minecraft:compass"},"gives":{"id":"minecraft:map"},"max_uses":12.0,"reputation_discount":0.2,"xp":5.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:swamp","minecraft:snow","minecraft:plains"]}},"entity":"this","condition":"minecraft:entity_properties"},"given_item_modifiers":[{"destination":"minecraft:on_taiga_village_maps","decoration":"minecraft:village_taiga","search_radius":100,"function":"minecraft:exploration_map"},{"name":{"translate":"filled_map.village_taiga"},"target":"item_name","function":"minecraft:set_name"},{"item_filter":{"items":"minecraft:filled_map","predicates":{"minecraft:map_id":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"cartographer/2/glass_pane_emerald":{"wants":{"id":"minecraft:glass_pane","count":11.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"cartographer/3/compass_emerald":{"wants":{"id":"minecraft:compass"},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":20.0},"cartographer/3/emerald_and_compass_ocean_explorer_map":{"wants":{"id":"minecraft:emerald","count":13.0},"additional_wants":{"id":"minecraft:compass"},"gives":{"id":"minecraft:map"},"max_uses":12.0,"reputation_discount":0.2,"xp":10.0,"given_item_modifiers":[{"destination":"minecraft:on_ocean_explorer_maps","decoration":"minecraft:monument","search_radius":100,"function":"minecraft:exploration_map"},{"name":{"translate":"filled_map.monument"},"target":"item_name","function":"minecraft:set_name"},{"item_filter":{"items":"minecraft:filled_map","predicates":{"minecraft:map_id":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"cartographer/3/emerald_and_compass_trial_chamber_map":{"wants":{"id":"minecraft:emerald","count":12.0},"additional_wants":{"id":"minecraft:compass"},"gives":{"id":"minecraft:map"},"max_uses":12.0,"reputation_discount":0.2,"xp":10.0,"given_item_modifiers":[{"destination":"minecraft:on_trial_chambers_maps","decoration":"minecraft:trial_chambers","search_radius":100,"function":"minecraft:exploration_map"},{"name":{"translate":"filled_map.trial_chambers"},"target":"item_name","function":"minecraft:set_name"},{"item_filter":{"items":"minecraft:filled_map","predicates":{"minecraft:map_id":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"cartographer/4/emerald_black_banner":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:black_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":"minecraft:swamp"}},"entity":"this","condition":"minecraft:entity_properties"}},"cartographer/4/emerald_blue_banner":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:blue_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:snow","minecraft:taiga"]}},"entity":"this","condition":"minecraft:entity_properties"}},"cartographer/4/emerald_brown_banner":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:brown_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:plains","minecraft:jungle"]}},"entity":"this","condition":"minecraft:entity_properties"}},"cartographer/4/emerald_cyan_banner":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:cyan_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:desert","minecraft:snow"]}},"entity":"this","condition":"minecraft:entity_properties"}},"cartographer/4/emerald_gray_banner":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:gray_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":"minecraft:desert"}},"entity":"this","condition":"minecraft:entity_properties"}},"cartographer/4/emerald_green_banner":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:green_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:desert","minecraft:savanna","minecraft:jungle"]}},"entity":"this","condition":"minecraft:entity_properties"}},"cartographer/4/emerald_item_frame":{"wants":{"id":"minecraft:emerald","count":7.0},"gives":{"id":"minecraft:item_frame"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"cartographer/4/emerald_light_blue_banner":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:light_blue_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:snow","minecraft:swamp"]}},"entity":"this","condition":"minecraft:entity_properties"}},"cartographer/4/emerald_lime_banner":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:lime_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:desert","minecraft:taiga"]}},"entity":"this","condition":"minecraft:entity_properties"}},"cartographer/4/emerald_magenta_banner":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:magenta_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":"minecraft:savanna"}},"entity":"this","condition":"minecraft:entity_properties"}},"cartographer/4/emerald_orange_banner":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:orange_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:savanna","minecraft:desert"]}},"entity":"this","condition":"minecraft:entity_properties"}},"cartographer/4/emerald_pink_banner":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:pink_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:taiga","minecraft:plains"]}},"entity":"this","condition":"minecraft:entity_properties"}},"cartographer/4/emerald_purple_banner":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:purple_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:taiga","minecraft:swamp"]}},"entity":"this","condition":"minecraft:entity_properties"}},"cartographer/4/emerald_red_banner":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:red_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:snow","minecraft:savanna"]}},"entity":"this","condition":"minecraft:entity_properties"}},"cartographer/4/emerald_white_banner":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:white_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:snow","minecraft:plains"]}},"entity":"this","condition":"minecraft:entity_properties"}},"cartographer/4/emerald_yellow_banner":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:yellow_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:plains","minecraft:jungle"]}},"entity":"this","condition":"minecraft:entity_properties"}},"cartographer/5/emerald_and_compass_woodland_mansion_map":{"wants":{"id":"minecraft:emerald","count":14.0},"additional_wants":{"id":"minecraft:compass"},"gives":{"id":"minecraft:map"},"max_uses":12.0,"reputation_discount":0.2,"xp":30.0,"given_item_modifiers":[{"destination":"minecraft:on_woodland_explorer_maps","search_radius":100,"function":"minecraft:exploration_map"},{"name":{"translate":"filled_map.mansion"},"target":"item_name","function":"minecraft:set_name"},{"item_filter":{"items":"minecraft:filled_map","predicates":{"minecraft:map_id":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"cartographer/5/emerald_globe_banner_pattern":{"wants":{"id":"minecraft:emerald","count":8.0},"gives":{"id":"minecraft:globe_banner_pattern"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"cleric/1/emerald_redstone":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:redstone","count":2},"max_uses":12.0,"reputation_discount":0.05},"cleric/1/rotten_flesh_emerald":{"wants":{"id":"minecraft:rotten_flesh","count":32.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"cleric/2/emerald_lapis_lazuli":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:lapis_lazuli"},"max_uses":12.0,"reputation_discount":0.05,"xp":5.0},"cleric/2/gold_ingot_emerald":{"wants":{"id":"minecraft:gold_ingot","count":3.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"cleric/3/emerald_glowstone":{"wants":{"id":"minecraft:emerald","count":4.0},"gives":{"id":"minecraft:glowstone"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"cleric/3/rabbit_foot_emerald":{"wants":{"id":"minecraft:rabbit_foot","count":2.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":20.0},"cleric/4/emerald_ender_pearl":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:ender_pearl"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"cleric/4/glass_bottle_emerald":{"wants":{"id":"minecraft:glass_bottle","count":9.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"cleric/4/turtle_scute_emerald":{"wants":{"id":"minecraft:turtle_scute","count":4.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"cleric/5/emerald_experience_bottle":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:experience_bottle"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"cleric/5/nether_wart_emerald":{"wants":{"id":"minecraft:nether_wart","count":22.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"farmer/1/beetroot_emerald":{"wants":{"id":"minecraft:beetroot","count":15.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"farmer/1/carrot_emerald":{"wants":{"id":"minecraft:carrot","count":22.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"farmer/1/emerald_bread":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:bread","count":6},"max_uses":16.0,"reputation_discount":0.05},"farmer/1/potato_emerald":{"wants":{"id":"minecraft:potato","count":26.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"farmer/1/wheat_emerald":{"wants":{"id":"minecraft:wheat","count":20.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"farmer/2/emerald_apple":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:apple","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"farmer/2/emerald_pumpkin_pie":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:pumpkin_pie","count":4},"max_uses":12.0,"reputation_discount":0.05,"xp":5.0},"farmer/2/pumpkin_emerald":{"wants":{"id":"minecraft:pumpkin","count":6.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"farmer/3/emerald_cookie":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:cookie","count":18},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"farmer/3/melon_emerald":{"wants":{"id":"minecraft:melon","count":4.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":20.0},"farmer/4/emerald_cake":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:cake"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"farmer/4/emerald_suspicious_stew":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:suspicious_stew"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0,"given_item_modifiers":[{"effects":[{"type":"minecraft:night_vision","duration":5.0},{"type":"minecraft:jump_boost","duration":8.0},{"type":"minecraft:weakness","duration":7.0},{"type":"minecraft:blindness","duration":6.0},{"type":"minecraft:poison","duration":14.0},{"type":"minecraft:saturation","duration":7.0}],"function":"minecraft:set_stew_effect"}]},"farmer/5/emerald_glistening_melon_slice":{"wants":{"id":"minecraft:emerald","count":4.0},"gives":{"id":"minecraft:glistering_melon_slice","count":3},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"farmer/5/emerald_golden_carrot":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:golden_carrot","count":3},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"fisherman/1/coal_emerald":{"wants":{"id":"minecraft:coal","count":10.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"fisherman/1/emerald_cod_bucket":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:cod_bucket"},"max_uses":16.0,"reputation_discount":0.05},"fisherman/1/raw_cod_and_emerald_cooked_cod":{"wants":{"id":"minecraft:cod","count":6.0},"additional_wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:cooked_cod","count":6},"max_uses":16.0,"reputation_discount":0.05},"fisherman/1/string_emerald":{"wants":{"id":"minecraft:string","count":20.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"fisherman/2/cod_emerald":{"wants":{"id":"minecraft:cod","count":15.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":10.0},"fisherman/2/emerald_campfire":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:campfire"},"max_uses":12.0,"reputation_discount":0.05,"xp":5.0},"fisherman/2/salmon_and_emerald_cooked_salmon":{"wants":{"id":"minecraft:salmon","count":6.0},"additional_wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:cooked_salmon","count":6},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"fisherman/3/emerald_enchanted_fishing_rod":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:fishing_rod"},"max_uses":3.0,"reputation_discount":0.2,"xp":10.0,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:fishing_rod","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"fisherman/3/salmon_emerald":{"wants":{"id":"minecraft:salmon","count":13.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":20.0},"fisherman/4/tropical_fish_emerald":{"wants":{"id":"minecraft:tropical_fish","count":6.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"fisherman/5/acacia_boat_emerald":{"wants":{"id":"minecraft:acacia_boat"},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":"minecraft:savanna"}},"entity":"this","condition":"minecraft:entity_properties"}},"fisherman/5/dark_oak_boat_emerald":{"wants":{"id":"minecraft:dark_oak_boat"},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":"minecraft:swamp"}},"entity":"this","condition":"minecraft:entity_properties"}},"fisherman/5/jungle_boat_emerald":{"wants":{"id":"minecraft:jungle_boat"},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:desert","minecraft:jungle"]}},"entity":"this","condition":"minecraft:entity_properties"}},"fisherman/5/oak_boat_emerald":{"wants":{"id":"minecraft:oak_boat"},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":"minecraft:plains"}},"entity":"this","condition":"minecraft:entity_properties"}},"fisherman/5/pufferfish_emerald":{"wants":{"id":"minecraft:pufferfish","count":4.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"fisherman/5/spruce_boat_emerald":{"wants":{"id":"minecraft:spruce_boat"},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0,"merchant_predicate":{"predicate":{"predicates":{"minecraft:villager/variant":["minecraft:taiga","minecraft:snow"]}},"entity":"this","condition":"minecraft:entity_properties"}},"fletcher/1/emerald_arrow":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:arrow","count":16},"max_uses":12.0,"reputation_discount":0.05},"fletcher/1/gravel_and_emerald_flint":{"wants":{"id":"minecraft:gravel","count":10.0},"additional_wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:flint","count":10},"max_uses":12.0,"reputation_discount":0.05},"fletcher/1/stick_emerald":{"wants":{"id":"minecraft:stick","count":32.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"fletcher/2/emerald_bow":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:bow"},"max_uses":12.0,"reputation_discount":0.05,"xp":5.0},"fletcher/2/flint_emerald":{"wants":{"id":"minecraft:flint","count":26.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"fletcher/3/emerald_crossbow":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:crossbow"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"fletcher/3/string_emerald":{"wants":{"id":"minecraft:string","count":14.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":20.0},"fletcher/4/emerald_enchanted_bow":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:bow"},"max_uses":3.0,"reputation_discount":0.05,"xp":15.0,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:bow","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"fletcher/4/feather_emerald":{"wants":{"id":"minecraft:feather","count":24.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":30.0},"fletcher/5/arrow_and_emerald_tipped_arrow":{"wants":{"id":"minecraft:arrow","count":5.0},"additional_wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:tipped_arrow","count":5},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0,"given_item_modifiers":[{"options":"#minecraft:tradeable","function":"minecraft:set_random_potion"}]},"fletcher/5/emerald_enchanted_crossbow":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:crossbow"},"max_uses":3.0,"reputation_discount":0.05,"xp":15.0,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:crossbow","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"fletcher/5/tripwire_hook_emerald":{"wants":{"id":"minecraft:tripwire_hook","count":8.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"leatherworker/1/emerald_dyed_leather_chestplate":{"wants":{"id":"minecraft:emerald","count":7.0},"gives":{"id":"minecraft:leather_chestplate"},"max_uses":12.0,"reputation_discount":0.2,"given_item_modifiers":[{"number_of_dyes":{"summands":[1.0,{"n":2.0,"p":0.75,"type":"minecraft:binomial"}],"type":"minecraft:sum"},"function":"minecraft:set_random_dyes"},{"item_filter":{"items":"minecraft:leather_chestplate","predicates":{"minecraft:dyed_color":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"leatherworker/1/emerald_dyed_leather_leggings":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:leather_leggings"},"max_uses":12.0,"reputation_discount":0.2,"given_item_modifiers":[{"number_of_dyes":{"summands":[1.0,{"n":2.0,"p":0.75,"type":"minecraft:binomial"}],"type":"minecraft:sum"},"function":"minecraft:set_random_dyes"},{"item_filter":{"items":"minecraft:leather_leggings","predicates":{"minecraft:dyed_color":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"leatherworker/1/leather_emerald":{"wants":{"id":"minecraft:leather","count":6.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"leatherworker/2/emerald_dyed_leather_boots":{"wants":{"id":"minecraft:emerald","count":4.0},"gives":{"id":"minecraft:leather_boots"},"max_uses":12.0,"reputation_discount":0.2,"xp":5.0,"given_item_modifiers":[{"number_of_dyes":{"summands":[1.0,{"n":2.0,"p":0.75,"type":"minecraft:binomial"}],"type":"minecraft:sum"},"function":"minecraft:set_random_dyes"},{"item_filter":{"items":"minecraft:leather_boots","predicates":{"minecraft:dyed_color":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"leatherworker/2/emerald_dyed_leather_helmet":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:leather_helmet"},"max_uses":12.0,"reputation_discount":0.2,"xp":5.0,"given_item_modifiers":[{"number_of_dyes":{"summands":[1.0,{"n":2.0,"p":0.75,"type":"minecraft:binomial"}],"type":"minecraft:sum"},"function":"minecraft:set_random_dyes"},{"item_filter":{"items":"minecraft:leather_helmet","predicates":{"minecraft:dyed_color":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"leatherworker/2/flint_emerald":{"wants":{"id":"minecraft:flint","count":26.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"leatherworker/3/emerald_dyed_leather_chestplate":{"wants":{"id":"minecraft:emerald","count":7.0},"gives":{"id":"minecraft:leather_chestplate"},"max_uses":12.0,"reputation_discount":0.2,"given_item_modifiers":[{"number_of_dyes":{"summands":[1.0,{"n":2.0,"p":0.75,"type":"minecraft:binomial"}],"type":"minecraft:sum"},"function":"minecraft:set_random_dyes"},{"item_filter":{"items":"minecraft:leather_chestplate","predicates":{"minecraft:dyed_color":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"leatherworker/3/rabbit_hide_emerald":{"wants":{"id":"minecraft:rabbit_hide","count":9.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":20.0},"leatherworker/4/emerald_dyed_leather_horse_armor":{"wants":{"id":"minecraft:emerald","count":6.0},"gives":{"id":"minecraft:leather_horse_armor"},"max_uses":12.0,"reputation_discount":0.2,"xp":15.0,"given_item_modifiers":[{"number_of_dyes":{"summands":[1.0,{"n":2.0,"p":0.75,"type":"minecraft:binomial"}],"type":"minecraft:sum"},"function":"minecraft:set_random_dyes"},{"item_filter":{"items":"minecraft:leather_horse_armor","predicates":{"minecraft:dyed_color":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"leatherworker/4/turtle_scute_emerald":{"wants":{"id":"minecraft:turtle_scute","count":4.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"leatherworker/5/emerald_dyed_leather_helmet":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:leather_helmet"},"max_uses":12.0,"reputation_discount":0.2,"xp":5.0,"given_item_modifiers":[{"number_of_dyes":{"summands":[1.0,{"n":2.0,"p":0.75,"type":"minecraft:binomial"}],"type":"minecraft:sum"},"function":"minecraft:set_random_dyes"},{"item_filter":{"items":"minecraft:leather_helmet","predicates":{"minecraft:dyed_color":{}}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"leatherworker/5/emerald_saddle":{"wants":{"id":"minecraft:emerald","count":6.0},"gives":{"id":"minecraft:saddle"},"max_uses":12.0,"reputation_discount":0.2,"xp":30.0},"librarian/1/emerald_and_book_enchanted_book":{"wants":{"id":"minecraft:emerald","count":0.0},"additional_wants":{"id":"minecraft:book"},"gives":{"id":"minecraft:enchanted_book"},"max_uses":12.0,"reputation_discount":0.2,"given_item_modifiers":[{"options":"#minecraft:tradeable","only_compatible":false,"include_additional_cost_component":true,"function":"minecraft:enchant_randomly"},{"item_filter":{"items":"minecraft:enchanted_book","predicates":{"minecraft:stored_enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}],"double_trade_price_enchantments":"#minecraft:double_trade_price"},"librarian/1/emerald_bookshelf":{"wants":{"id":"minecraft:emerald","count":9.0},"gives":{"id":"minecraft:bookshelf"},"max_uses":12.0,"reputation_discount":0.05},"librarian/1/paper_emerald":{"wants":{"id":"minecraft:paper","count":24.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"librarian/2/book_emerald":{"wants":{"id":"minecraft:book","count":4.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"librarian/2/emerald_and_book_enchanted_book":{"wants":{"id":"minecraft:emerald","count":0.0},"additional_wants":{"id":"minecraft:book"},"gives":{"id":"minecraft:enchanted_book"},"max_uses":12.0,"reputation_discount":0.2,"xp":5.0,"given_item_modifiers":[{"options":"#minecraft:tradeable","only_compatible":false,"include_additional_cost_component":true,"function":"minecraft:enchant_randomly"},{"item_filter":{"items":"minecraft:enchanted_book","predicates":{"minecraft:stored_enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}],"double_trade_price_enchantments":"#minecraft:double_trade_price"},"librarian/2/emerald_lantern":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:lantern"},"max_uses":12.0,"reputation_discount":0.05,"xp":5.0},"librarian/3/emerald_and_book_enchanted_book":{"wants":{"id":"minecraft:emerald","count":0.0},"additional_wants":{"id":"minecraft:book"},"gives":{"id":"minecraft:enchanted_book"},"max_uses":12.0,"reputation_discount":0.2,"xp":10.0,"given_item_modifiers":[{"options":"#minecraft:tradeable","only_compatible":false,"include_additional_cost_component":true,"function":"minecraft:enchant_randomly"},{"item_filter":{"items":"minecraft:enchanted_book","predicates":{"minecraft:stored_enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}],"double_trade_price_enchantments":"#minecraft:double_trade_price"},"librarian/3/emerald_glass":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:glass","count":4},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"librarian/3/ink_sac_emerald":{"wants":{"id":"minecraft:ink_sac","count":5.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":20.0},"librarian/4/emerald_book_and_enchanted_book":{"wants":{"id":"minecraft:emerald","count":0.0},"additional_wants":{"id":"minecraft:book"},"gives":{"id":"minecraft:enchanted_book"},"max_uses":12.0,"reputation_discount":0.2,"xp":15.0,"given_item_modifiers":[{"options":"#minecraft:tradeable","only_compatible":false,"include_additional_cost_component":true,"function":"minecraft:enchant_randomly"},{"item_filter":{"items":"minecraft:enchanted_book","predicates":{"minecraft:stored_enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}],"double_trade_price_enchantments":"#minecraft:double_trade_price"},"librarian/4/emerald_clock":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:clock"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"librarian/4/emerald_compass":{"wants":{"id":"minecraft:emerald","count":4.0},"gives":{"id":"minecraft:compass"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"librarian/4/writable_book_emerald":{"wants":{"id":"minecraft:writable_book","count":2.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"librarian/5/emerald_red_candle":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:red_candle"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"librarian/5/emerald_yellow_candle":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:yellow_candle"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"mason/1/clay_ball_emerald":{"wants":{"id":"minecraft:clay_ball","count":10.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"mason/1/emerald_brick":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:brick","count":10},"max_uses":16.0,"reputation_discount":0.05},"mason/2/emerald_chiseled_stone_bricks":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:chiseled_stone_bricks","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"mason/2/stone_emerald":{"wants":{"id":"minecraft:stone","count":20.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":10.0},"mason/3/andesite_emerald":{"wants":{"id":"minecraft:andesite","count":16.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":20.0},"mason/3/diorite_emerald":{"wants":{"id":"minecraft:diorite","count":16.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":20.0},"mason/3/emerald_dripstone_block":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:dripstone_block","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":10.0},"mason/3/emerald_polished_andesite":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:polished_andesite","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":10.0},"mason/3/emerald_polished_diorite":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:polished_diorite","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":10.0},"mason/3/emerald_polished_granite":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:polished_granite","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":10.0},"mason/3/granite_emerald":{"wants":{"id":"minecraft:granite","count":16.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":20.0},"mason/4/emerald_black_glazed_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:black_glazed_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_black_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:black_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_blue_glazed_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:blue_glazed_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_blue_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:blue_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_brown_glazed_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:brown_glazed_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_brown_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:brown_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_cyan_glazed_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:cyan_glazed_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_cyan_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:cyan_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_gray_glazed_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:gray_glazed_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_gray_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:gray_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_green_glazed_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:green_glazed_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_green_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:green_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_light_blue_glazed_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:light_blue_glazed_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_light_blue_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:light_blue_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_light_gray_glazed_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:light_gray_glazed_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_light_gray_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:light_gray_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_lime_glazed_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:lime_glazed_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_lime_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:lime_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_magenta_glazed_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:magenta_glazed_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_magenta_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:magenta_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_orange_glazed_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:orange_glazed_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_orange_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:orange_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_pink_glazed_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:pink_glazed_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_pink_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:pink_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_purple_glazed_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:purple_glazed_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_purple_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:purple_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_red_glazed_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:red_glazed_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_red_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:red_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_white_glazed_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:white_glazed_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_white_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:white_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_yellow_glazed_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:yellow_glazed_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/emerald_yellow_terracotta":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:yellow_terracotta"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"mason/4/quartz_emerald":{"wants":{"id":"minecraft:quartz","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"mason/5/emerald_quartz_block":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:quartz_block"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"mason/5/emerald_quartz_pillar":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:quartz_pillar"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"shepherd/1/black_wool_emerald":{"wants":{"id":"minecraft:black_wool","count":18.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"shepherd/1/brown_wool_emerald":{"wants":{"id":"minecraft:brown_wool","count":18.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"shepherd/1/emerald_shears":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:shears"},"max_uses":12.0,"reputation_discount":0.05},"shepherd/1/gray_wool_emerald":{"wants":{"id":"minecraft:gray_wool","count":18.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"shepherd/1/white_wool_emerald":{"wants":{"id":"minecraft:white_wool","count":18.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"shepherd/2/black_dye_emerald":{"wants":{"id":"minecraft:black_dye","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":10.0},"shepherd/2/emerald_black_carpet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:black_carpet","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_black_wool":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:black_wool"},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_blue_carpet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:blue_carpet","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_blue_wool":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:blue_wool"},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_brown_carpet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:brown_carpet","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_brown_wool":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:brown_wool"},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_cyan_carpet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:cyan_carpet","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_cyan_wool":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:cyan_wool"},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_gray_carpet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:gray_carpet","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_gray_wool":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:gray_wool"},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_green_carpet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:green_carpet","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_green_wool":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:green_wool"},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_light_blue_carpet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:light_blue_carpet","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_light_blue_wool":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:light_blue_wool"},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_light_gray_carpet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:light_gray_carpet","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_light_gray_wool":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:light_gray_wool"},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_lime_carpet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:lime_carpet","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_lime_wool":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:lime_wool"},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_magenta_carpet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:magenta_carpet","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_magenta_wool":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:magenta_wool"},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_orange_carpet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:orange_carpet","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_orange_wool":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:orange_wool"},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_pink_carpet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:pink_carpet","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_pink_wool":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:pink_wool"},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_purple_carpet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:purple_carpet","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_purple_wool":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:purple_wool"},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_red_carpet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:red_carpet","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_red_wool":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:red_wool"},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_white_carpet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:white_carpet","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_white_wool":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:white_wool"},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_yellow_carpet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:yellow_carpet","count":4},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/emerald_yellow_wool":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:yellow_wool"},"max_uses":16.0,"reputation_discount":0.05,"xp":5.0},"shepherd/2/gray_dye_emerald":{"wants":{"id":"minecraft:gray_dye","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":10.0},"shepherd/2/light_blue_dye_emerald":{"wants":{"id":"minecraft:light_blue_dye","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":10.0},"shepherd/2/lime_dye_emerald":{"wants":{"id":"minecraft:lime_dye","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":10.0},"shepherd/2/white_dye_emerald":{"wants":{"id":"minecraft:white_dye","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/emerald_black_bed":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:black_bed"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/emerald_blue_bed":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:blue_bed"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/emerald_brown_bed":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:brown_bed"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/emerald_cyan_bed":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:cyan_bed"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/emerald_gray_bed":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:gray_bed"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/emerald_green_bed":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:green_bed"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/emerald_light_blue_bed":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:light_blue_bed"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/emerald_light_gray_bed":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:light_gray_bed"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/emerald_lime_bed":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:lime_bed"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/emerald_magenta_bed":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:magenta_bed"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/emerald_orange_bed":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:orange_bed"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/emerald_pink_bed":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:pink_bed"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/emerald_purple_bed":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:purple_bed"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/emerald_red_bed":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:red_bed"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/emerald_white_bed":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:white_bed"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/emerald_yellow_bed":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:yellow_bed"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"shepherd/3/light_gray_dye_emerald":{"wants":{"id":"minecraft:light_gray_dye","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":20.0},"shepherd/3/orange_dye_emerald":{"wants":{"id":"minecraft:orange_dye","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":20.0},"shepherd/3/pink_dye_emerald":{"wants":{"id":"minecraft:pink_dye","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":20.0},"shepherd/3/red_dye_emerald":{"wants":{"id":"minecraft:red_dye","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":20.0},"shepherd/3/yellow_dye_emerald":{"wants":{"id":"minecraft:yellow_dye","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":20.0},"shepherd/4/blue_dye_emerald":{"wants":{"id":"minecraft:blue_dye","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":30.0},"shepherd/4/brown_dye_emerald":{"wants":{"id":"minecraft:brown_dye","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":30.0},"shepherd/4/cyan_dye_emerald":{"wants":{"id":"minecraft:cyan_dye","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":30.0},"shepherd/4/emerald_black_banner":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:black_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"shepherd/4/emerald_blue_banner":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:blue_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"shepherd/4/emerald_brown_banner":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:brown_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"shepherd/4/emerald_cyan_banner":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:cyan_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"shepherd/4/emerald_gray_banner":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:gray_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"shepherd/4/emerald_green_banner":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:green_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"shepherd/4/emerald_light_blue_banner":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:light_blue_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"shepherd/4/emerald_light_gray_banner":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:light_gray_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"shepherd/4/emerald_lime_banner":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:lime_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"shepherd/4/emerald_magenta_banner":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:magenta_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"shepherd/4/emerald_orange_banner":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:orange_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"shepherd/4/emerald_pink_banner":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:pink_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"shepherd/4/emerald_purple_banner":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:purple_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"shepherd/4/emerald_red_banner":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:red_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"shepherd/4/emerald_white_banner":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:white_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"shepherd/4/emerald_yellow_banner":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:yellow_banner"},"max_uses":12.0,"reputation_discount":0.05,"xp":15.0},"shepherd/4/green_dye_emerald":{"wants":{"id":"minecraft:green_dye","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":30.0},"shepherd/4/magenta_dye_emerald":{"wants":{"id":"minecraft:magenta_dye","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":30.0},"shepherd/4/purple_dye_emerald":{"wants":{"id":"minecraft:purple_dye","count":12.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":30.0},"shepherd/5/emerald_painting":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:painting","count":3},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"smith/1/coal_emerald":{"wants":{"id":"minecraft:coal","count":15.0},"gives":{"id":"minecraft:emerald"},"max_uses":16.0,"reputation_discount":0.05,"xp":2.0},"smith/2/emerald_bell":{"wants":{"id":"minecraft:emerald","count":36.0},"gives":{"id":"minecraft:bell"},"max_uses":12.0,"reputation_discount":0.2,"xp":5.0},"smith/2/iron_ingot_emerald":{"wants":{"id":"minecraft:iron_ingot","count":4.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":10.0},"toolsmith/1/emerald_stone_axe":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:stone_axe"},"max_uses":12.0,"reputation_discount":0.2},"toolsmith/1/emerald_stone_hoe":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:stone_hoe"},"max_uses":12.0,"reputation_discount":0.2},"toolsmith/1/emerald_stone_pickaxe":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:stone_pickaxe"},"max_uses":12.0,"reputation_discount":0.2},"toolsmith/1/emerald_stone_shovel":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:stone_shovel"},"max_uses":12.0,"reputation_discount":0.2},"toolsmith/3/emerald_diamond_hoe":{"wants":{"id":"minecraft:emerald","count":4.0},"gives":{"id":"minecraft:diamond_hoe"},"max_uses":3.0,"reputation_discount":0.2,"xp":10.0},"toolsmith/3/emerald_enchanted_iron_axe":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:iron_axe"},"max_uses":3.0,"reputation_discount":0.2,"xp":10.0,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:iron_axe","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"toolsmith/3/emerald_enchanted_iron_pickaxe":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:iron_pickaxe"},"max_uses":3.0,"reputation_discount":0.2,"xp":10.0,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:iron_pickaxe","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"toolsmith/3/emerald_enchanted_iron_shovel":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:iron_shovel"},"max_uses":3.0,"reputation_discount":0.2,"xp":10.0,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:iron_shovel","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"toolsmith/3/flint_emerald":{"wants":{"id":"minecraft:flint","count":30.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":20.0},"toolsmith/4/diamond_emerald":{"wants":{"id":"minecraft:diamond"},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"toolsmith/4/emerald_enchanted_diamond_axe":{"wants":{"id":"minecraft:emerald","count":12.0},"gives":{"id":"minecraft:diamond_axe"},"max_uses":3.0,"reputation_discount":0.2,"xp":15.0,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:diamond_axe","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"toolsmith/4/emerald_enchanted_diamond_shovel":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:diamond_shovel"},"max_uses":3.0,"reputation_discount":0.2,"xp":15.0,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:diamond_shovel","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"toolsmith/5/emerald_enchanted_diamond_pickaxe":{"wants":{"id":"minecraft:emerald","count":13.0},"gives":{"id":"minecraft:diamond_pickaxe"},"max_uses":3.0,"reputation_discount":0.2,"xp":30.0,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:diamond_pickaxe","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"wandering_trader/baked_potato_emerald":{"wants":{"id":"minecraft:baked_potato","count":4.0},"gives":{"id":"minecraft:emerald"},"max_uses":2.0,"reputation_discount":0.05},"wandering_trader/emerald_acacia_log":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:acacia_log","count":8},"reputation_discount":0.05},"wandering_trader/emerald_acacia_sapling":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:acacia_sapling"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_allium":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:allium"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_azure_bluet":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:azure_bluet"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_beetroot_seeds":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:beetroot_seeds"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_birch_log":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:birch_log","count":8},"reputation_discount":0.05},"wandering_trader/emerald_birch_sapling":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:birch_sapling"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_black_dye":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:black_dye","count":3},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_blue_dye":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:blue_dye","count":3},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_blue_ice":{"wants":{"id":"minecraft:emerald","count":6.0},"gives":{"id":"minecraft:blue_ice"},"max_uses":6.0,"reputation_discount":0.05},"wandering_trader/emerald_blue_orchid":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:blue_orchid"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_brain_coral_block":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:brain_coral_block"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_brown_dye":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:brown_dye","count":3},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_brown_mushroom":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:brown_mushroom","count":3},"reputation_discount":0.05},"wandering_trader/emerald_bubble_coral_block":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:bubble_coral_block"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_cactus":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:cactus"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_cherry_log":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:cherry_log","count":8},"reputation_discount":0.05},"wandering_trader/emerald_cherry_sapling":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:cherry_sapling"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_cornflower":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:cornflower"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_cyan_dye":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:cyan_dye","count":3},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_dandelion":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:dandelion"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_dark_oak_log":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:dark_oak_log","count":8},"reputation_discount":0.05},"wandering_trader/emerald_dark_oak_sapling":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:dark_oak_sapling"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_dry_tall_grass":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:tall_dry_grass"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_enchanted_iron_pickaxe":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:iron_pickaxe"},"max_uses":1.0,"reputation_discount":0.2,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:iron_pickaxe","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"wandering_trader/emerald_fern":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:fern"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_fire_coral_block":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:fire_coral_block"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_firefly_bush":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:firefly_bush"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_fish_bucket":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:tropical_fish_bucket"},"reputation_discount":0.05},"wandering_trader/emerald_glowstone":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:glowstone"},"max_uses":5.0,"reputation_discount":0.05},"wandering_trader/emerald_golden_dandelion":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:golden_dandelion"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_gray_dye":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:gray_dye","count":3},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_green_dye":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:green_dye","count":3},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_gunpowder":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:gunpowder","count":4},"max_uses":2.0,"reputation_discount":0.05},"wandering_trader/emerald_horn_coral_block":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:horn_coral_block"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_jungle_log":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:jungle_log","count":8},"reputation_discount":0.05},"wandering_trader/emerald_jungle_sapling":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:jungle_sapling"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_kelp":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:kelp"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_light_blue_dye":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:light_blue_dye","count":3},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_light_gray_dye":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:light_gray_dye","count":3},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_lily_of_the_valley":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:lily_of_the_valley"},"max_uses":7.0,"reputation_discount":0.05},"wandering_trader/emerald_lily_pad":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:lily_pad","count":5},"max_uses":2.0,"reputation_discount":0.05},"wandering_trader/emerald_lime_dye":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:lime_dye","count":3},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_long_invisibility_potion":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:potion"},"max_uses":1.0,"reputation_discount":0.05,"given_item_modifiers":[{"id":"minecraft:long_invisibility","function":"minecraft:set_potion"}]},"wandering_trader/emerald_magenta_dye":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:magenta_dye","count":3},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_mangrove_log":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:mangrove_log","count":8},"reputation_discount":0.05},"wandering_trader/emerald_mangrove_propagule":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:mangrove_propagule"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_melon_seeds":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:melon_seeds"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_moss_block":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:moss_block","count":2},"max_uses":5.0,"reputation_discount":0.05},"wandering_trader/emerald_name_tag":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:name_tag"},"max_uses":5.0,"reputation_discount":0.05},"wandering_trader/emerald_nautilus_shell":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:nautilus_shell"},"max_uses":5.0,"reputation_discount":0.05},"wandering_trader/emerald_oak_log":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:oak_log","count":8},"reputation_discount":0.05},"wandering_trader/emerald_oak_sapling":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:oak_sapling"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_open_eyeblossom":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:open_eyeblossom"},"max_uses":7.0,"reputation_discount":0.05},"wandering_trader/emerald_orange_dye":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:orange_dye","count":3},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_orange_tulip":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:orange_tulip"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_oxeye_daisy":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:oxeye_daisy"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_packed_ice":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:packed_ice"},"max_uses":6.0,"reputation_discount":0.05},"wandering_trader/emerald_pale_hanging_moss":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:pale_hanging_moss","count":3},"reputation_discount":0.05},"wandering_trader/emerald_pale_moss_block":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:pale_moss_block","count":2},"max_uses":5.0,"reputation_discount":0.05},"wandering_trader/emerald_pale_oak_log":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:pale_oak_log","count":8},"reputation_discount":0.05},"wandering_trader/emerald_pale_oak_sapling":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:pale_oak_sapling"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_pink_dye":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:pink_dye","count":3},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_pink_tulip":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:pink_tulip"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_podzol":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:podzol","count":3},"max_uses":6.0,"reputation_discount":0.05},"wandering_trader/emerald_pointed_dripstone":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:pointed_dripstone","count":2},"max_uses":5.0,"reputation_discount":0.05},"wandering_trader/emerald_poppy":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:poppy"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_pufferfish_bucket":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:pufferfish_bucket"},"reputation_discount":0.05},"wandering_trader/emerald_pumpkin":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:pumpkin"},"reputation_discount":0.05},"wandering_trader/emerald_pumpkin_seeds":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:pumpkin_seeds"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_purple_dye":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:purple_dye","count":3},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_red_dye":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:red_dye","count":3},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_red_mushroom":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:red_mushroom","count":3},"reputation_discount":0.05},"wandering_trader/emerald_red_sand":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:red_sand","count":4},"max_uses":6.0,"reputation_discount":0.05},"wandering_trader/emerald_red_tulip":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:red_tulip"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_rooted_dirt":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:rooted_dirt","count":2},"max_uses":5.0,"reputation_discount":0.05},"wandering_trader/emerald_sand":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:sand","count":8},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_sea_pickle":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:sea_pickle"},"max_uses":5.0,"reputation_discount":0.05},"wandering_trader/emerald_slime_ball":{"wants":{"id":"minecraft:emerald","count":4.0},"gives":{"id":"minecraft:slime_ball"},"max_uses":5.0,"reputation_discount":0.05},"wandering_trader/emerald_small_dripleaf":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:small_dripleaf","count":2},"max_uses":5.0,"reputation_discount":0.05},"wandering_trader/emerald_spruce_log":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:spruce_log","count":8},"reputation_discount":0.05},"wandering_trader/emerald_spruce_sapling":{"wants":{"id":"minecraft:emerald","count":5.0},"gives":{"id":"minecraft:spruce_sapling"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_sugar_cane":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:sugar_cane"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_tube_coral_block":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:tube_coral_block"},"max_uses":8.0,"reputation_discount":0.05},"wandering_trader/emerald_vine":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:vine","count":3},"reputation_discount":0.05},"wandering_trader/emerald_wheat_seeds":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:wheat_seeds"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_white_dye":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:white_dye","count":3},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_white_tulip":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:white_tulip"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_wildflowers":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:wildflowers"},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/emerald_yellow_dye":{"wants":{"id":"minecraft:emerald"},"gives":{"id":"minecraft:yellow_dye","count":3},"max_uses":12.0,"reputation_discount":0.05},"wandering_trader/fermented_spider_eye_emerald":{"wants":{"id":"minecraft:fermented_spider_eye"},"gives":{"id":"minecraft:emerald","count":3},"max_uses":2.0,"reputation_discount":0.05},"wandering_trader/hay_block_emerald":{"wants":{"id":"minecraft:hay_block"},"gives":{"id":"minecraft:emerald"},"max_uses":2.0,"reputation_discount":0.05},"wandering_trader/milk_bucket_emerald":{"wants":{"id":"minecraft:milk_bucket"},"gives":{"id":"minecraft:emerald","count":2},"max_uses":2.0,"reputation_discount":0.05},"wandering_trader/water_bottle_emerald":{"wants":{"id":"minecraft:potion","components":{"minecraft:potion_contents":{"potion":"minecraft:water"}}},"gives":{"id":"minecraft:emerald"},"max_uses":2.0,"reputation_discount":0.05},"wandering_trader/water_bucket_emerald":{"wants":{"id":"minecraft:water_bucket"},"gives":{"id":"minecraft:emerald","count":2},"max_uses":2.0,"reputation_discount":0.05},"weaponsmith/1/emerald_enchanted_iron_sword":{"wants":{"id":"minecraft:emerald","count":2.0},"gives":{"id":"minecraft:iron_sword"},"max_uses":12.0,"reputation_discount":0.2,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:iron_sword","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"weaponsmith/1/emerald_iron_axe":{"wants":{"id":"minecraft:emerald","count":3.0},"gives":{"id":"minecraft:iron_axe"},"max_uses":12.0,"reputation_discount":0.2},"weaponsmith/3/flint_emerald":{"wants":{"id":"minecraft:flint","count":24.0},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":20.0},"weaponsmith/4/diamond_emerald":{"wants":{"id":"minecraft:diamond"},"gives":{"id":"minecraft:emerald"},"max_uses":12.0,"reputation_discount":0.05,"xp":30.0},"weaponsmith/4/emerald_enchanted_diamond_axe":{"wants":{"id":"minecraft:emerald","count":12.0},"gives":{"id":"minecraft:diamond_axe"},"max_uses":3.0,"reputation_discount":0.2,"xp":15.0,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:diamond_axe","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]},"weaponsmith/5/emerald_enchanted_diamond_sword":{"wants":{"id":"minecraft:emerald","count":8.0},"gives":{"id":"minecraft:diamond_sword"},"max_uses":3.0,"reputation_discount":0.2,"xp":30.0,"given_item_modifiers":[{"levels":{"min":5.0,"max":19.0,"type":"minecraft:uniform"},"options":"#minecraft:on_traded_equipment","include_additional_cost_component":true,"function":"minecraft:enchant_with_levels"},{"item_filter":{"items":"minecraft:diamond_sword","predicates":{"minecraft:enchantments":[{}]}},"on_fail":{"function":"minecraft:discard"},"function":"minecraft:filtered"}]}}} \ No newline at end of file diff --git a/pumpkin-codegen/Cargo.lock b/pumpkin-codegen/Cargo.lock index 7eba9bac0..33136ec9c 100644 --- a/pumpkin-codegen/Cargo.lock +++ b/pumpkin-codegen/Cargo.lock @@ -1015,6 +1015,7 @@ version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ + "indexmap", "itoa", "memchr", "serde", diff --git a/pumpkin-codegen/Cargo.toml b/pumpkin-codegen/Cargo.toml index 3381f83b7..38d3ff70b 100644 --- a/pumpkin-codegen/Cargo.toml +++ b/pumpkin-codegen/Cargo.toml @@ -12,7 +12,7 @@ heck = "0.5" md5 = "0.8" serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" +serde_json = { version = "1.0", features = ["preserve_order"] } serde_json5 = "0.2" rayon = "1.11.0" diff --git a/pumpkin-codegen/src/main.rs b/pumpkin-codegen/src/main.rs index 2f835bbae..8c2fc5f13 100644 --- a/pumpkin-codegen/src/main.rs +++ b/pumpkin-codegen/src/main.rs @@ -57,6 +57,7 @@ mod tag; mod tracked_data; mod translations; mod version; +mod villager; mod world_event; /// Output directory where all generated Rust source files are written. @@ -101,6 +102,7 @@ pub fn main() { (entity_status::build, "entity_status.rs"), (tag::build, "tag.rs"), (noise_router::build, "noise_router.rs"), + (villager::build, "villager.rs"), ( flower_pot_transformations::build, "flower_pot_transformations.rs", diff --git a/pumpkin-codegen/src/villager.rs b/pumpkin-codegen/src/villager.rs new file mode 100644 index 000000000..8ec8590c6 --- /dev/null +++ b/pumpkin-codegen/src/villager.rs @@ -0,0 +1,328 @@ +use heck::{ToPascalCase, ToShoutySnakeCase}; +use indexmap::IndexMap; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; +use serde::Deserialize; +use std::fs; + +#[derive(Deserialize)] +struct VillagerDataJson { + professions: IndexMap, + types: IndexMap, + trade_sets: IndexMap, + villager_trades: IndexMap, +} + +#[derive(Deserialize)] +struct ProfessionJson { + name: NameJson, + requested_items: Vec, + work_sound: Option, + trade_sets: IndexMap, +} + +#[derive(Deserialize)] +struct NameJson { + translate: String, +} + +#[derive(Deserialize)] +struct TradeSetJson { + trades: String, // Tag like "#minecraft:armorer/level_1" + amount: f32, +} + +#[derive(Deserialize)] +struct TradeJson { + wants: TradeItemJson, + wants_b: Option, + gives: TradeItemJson, + max_uses: Option, + xp: Option, + price_multiplier: Option, +} + +#[derive(Deserialize)] +struct TradeItemJson { + id: String, + count: Option, +} + +pub fn build() -> TokenStream { + let data: VillagerDataJson = + serde_json::from_str(&fs::read_to_string("../assets/villager_data.json").unwrap()) + .expect("Failed to parse villager_data.json"); + + let mut profession_variants = Vec::new(); + let mut type_variants = Vec::new(); + + let mut work_sounds = Vec::new(); + let mut requested_items = Vec::new(); + let mut profession_names = Vec::new(); + + let mut profession_from_i32 = Vec::new(); + let mut type_from_i32 = Vec::new(); + + let mut trade_set_data = Vec::new(); + let mut generated_trade_sets = IndexMap::new(); + + // Helper to format a trade into TokenStream + let format_trade = |trade: &TradeJson| { + let wants_item = format_ident!( + "{}", + trade.wants.id.strip_prefix("minecraft:").unwrap_or(&trade.wants.id).to_shouty_snake_case() + ); + let wants_count = trade.wants.count.unwrap_or(1.0) as i32; + let wants = quote! { VillagerTradeItem { item: &crate::item::Item::#wants_item, count: #wants_count } }; + + let wants_b = if let Some(b) = &trade.wants_b { + let item = format_ident!( + "{}", + b.id.strip_prefix("minecraft:").unwrap_or(&b.id).to_shouty_snake_case() + ); + let count = b.count.unwrap_or(1.0) as i32; + quote! { Some(VillagerTradeItem { item: &crate::item::Item::#item, count: #count }) } + } else { + quote! { None } + }; + + let gives_item = format_ident!( + "{}", + trade.gives.id.strip_prefix("minecraft:").unwrap_or(&trade.gives.id).to_shouty_snake_case() + ); + let gives_count = trade.gives.count.unwrap_or(1.0) as i32; + let gives = quote! { VillagerTradeItem { item: &crate::item::Item::#gives_item, count: #gives_count } }; + + let max_uses = trade.max_uses.unwrap_or(16.0) as i32; + let xp = trade.xp.unwrap_or(2.0) as i32; + let price_multiplier = trade.price_multiplier.unwrap_or(0.05); + + quote! { + VillagerTrade { + wants: #wants, + wants_b: #wants_b, + gives: #gives, + max_uses: #max_uses, + xp: #xp, + price_multiplier: #price_multiplier, + } + } + }; + + // Pre-process all trade sets mentioned in trade_sets map + for (set_key, set_data) in &data.trade_sets { + let tag = &set_data.trades; + if !tag.starts_with("#minecraft:") { + continue; + } + let tag_content = tag.strip_prefix("#minecraft:").unwrap(); + let parts: Vec<&str> = tag_content.split('/').collect(); + if parts.len() < 2 { + continue; + } + let prof = parts[0]; + let level_str = parts[1].strip_prefix("level_").unwrap_or(parts[1]); + + let mut matching_trades = Vec::new(); + let prefix = format!("{prof}/{level_str}/"); + for (key, trade) in &data.villager_trades { + if key.starts_with(&prefix) { + matching_trades.push(format_trade(trade)); + } + } + + // Fallback for smiths + if matching_trades.is_empty() && (prof == "armorer" || prof == "toolsmith" || prof == "weaponsmith") { + let smith_prefix = format!("smith/{level_str}/"); + for (key, trade) in &data.villager_trades { + if key.starts_with(&smith_prefix) { + matching_trades.push(format_trade(trade)); + } + } + } + + if !matching_trades.is_empty() { + let ident_name = tag_content.replace('/', "_").to_shouty_snake_case(); + let ident = format_ident!("TRADES_{}", ident_name); + trade_set_data.push(quote! { + pub const #ident: &[VillagerTrade] = &[ + #(#matching_trades),* + ]; + }); + generated_trade_sets.insert(tag.clone(), ident); + } + } + + let mut profession_trade_sets = Vec::new(); + + for (i, (name, prof_data)) in data.professions.iter().enumerate() { + let ident = format_ident!("{}", name.to_pascal_case()); + profession_variants.push(quote! { #ident }); + + let sound = if let Some(sound) = &prof_data.work_sound { + let sound_ident = format_ident!( + "{}", + sound + .strip_prefix("minecraft:") + .unwrap_or(sound) + .replace('.', "_") + .to_pascal_case() + ); + quote! { Some(crate::sound::Sound::#sound_ident) } + } else { + quote! { None } + }; + work_sounds.push(quote! { Self::#ident => #sound }); + + let items: Vec<_> = prof_data + .requested_items + .iter() + .map(|i| { + let item_ident = format_ident!( + "{}", + i.strip_prefix("minecraft:") + .unwrap_or(i) + .to_shouty_snake_case() + ); + quote! { &crate::item::Item::#item_ident } + }) + .collect(); + requested_items.push(quote! { Self::#ident => &[#(#items),*] }); + + let translate = &prof_data.name.translate; + profession_names.push(quote! { Self::#ident => #translate }); + + let i = i as i32; + profession_from_i32.push(quote! { #i => Some(Self::#ident) }); + + let mut level_matches = Vec::new(); + for (level_str, set_key) in &prof_data.trade_sets { + let level = level_str.parse::().unwrap(); + let set_key_clean = set_key.strip_prefix("minecraft:").unwrap_or(set_key); + if let Some(set) = data.trade_sets.get(set_key_clean) { + if let Some(trades_ident) = generated_trade_sets.get(&set.trades) { + let amount = set.amount as i32; + level_matches.push(quote! { #level => Some(VillagerTradeSet { trades: #trades_ident, amount: #amount }) }); + } + } + } + profession_trade_sets.push(quote! { + Self::#ident => match level { + #(#level_matches,)* + _ => None, + } + }); + } + + for (i, name) in data.types.keys().enumerate() { + let ident = format_ident!("{}", name.to_pascal_case()); + type_variants.push(quote! { #ident }); + + let i = i as i32; + type_from_i32.push(quote! { #i => Some(Self::#ident) }); + } + + quote! { + use serde::Serialize; + + #[derive(Clone, Copy, PartialEq)] + pub struct VillagerTradeItem { + pub item: &'static crate::item::Item, + pub count: i32, + } + + #[derive(Clone, Copy, PartialEq)] + pub struct VillagerTrade { + pub wants: VillagerTradeItem, + pub wants_b: Option, + pub gives: VillagerTradeItem, + pub max_uses: i32, + pub xp: i32, + pub price_multiplier: f32, + } + + #[derive(Clone, Copy, PartialEq)] + pub struct VillagerTradeSet { + pub trades: &'static [VillagerTrade], + pub amount: i32, + } + + #(#trade_set_data)* + + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)] + #[repr(i32)] + pub enum VillagerProfession { + #(#profession_variants),* + } + + impl VillagerProfession { + #[must_use] + pub fn from_i32(id: i32) -> Option { + match id { + #(#profession_from_i32,)* + _ => None, + } + } + + #[must_use] + pub fn work_sound(&self) -> Option { + match self { + #(#work_sounds),* + } + } + + #[must_use] + pub fn requested_items(&self) -> &'static [&'static crate::item::Item] { + match self { + #(#requested_items),* + } + } + + #[must_use] + pub fn translation_key(&self) -> &'static str { + match self { + #(#profession_names),* + } + } + + #[must_use] + pub fn trade_set(&self, level: i32) -> Option { + match self { + #(#profession_trade_sets,)* + } + } + } + + impl TryFrom for VillagerProfession { + type Error = (); + + fn try_from(value: i32) -> Result { + Self::from_i32(value).ok_or(()) + } + } + + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)] + #[repr(i32)] + pub enum VillagerType { + #(#type_variants),* + } + + impl VillagerType { + #[must_use] + pub fn from_i32(id: i32) -> Option { + match id { + #(#type_from_i32,)* + _ => None, + } + } + } + + impl TryFrom for VillagerType { + type Error = (); + + fn try_from(value: i32) -> Result { + Self::from_i32(value).ok_or(()) + } + } + } +} diff --git a/pumpkin-data/Cargo.toml b/pumpkin-data/Cargo.toml index 4442392fb..b1fd65c0b 100644 --- a/pumpkin-data/Cargo.toml +++ b/pumpkin-data/Cargo.toml @@ -42,6 +42,7 @@ default = [ "recipe_remainder", "chunk_gen_settings", "carver", + "villager", ] item = [] @@ -78,6 +79,7 @@ potion = ["potion_brewing"] recipe_remainder = [] chunk_gen_settings = [] carver = [] +villager = ["item", "sound"] noise_parameter = [] biome = [] diff --git a/pumpkin-data/src/generated/villager.rs b/pumpkin-data/src/generated/villager.rs new file mode 100644 index 000000000..14831fba3 --- /dev/null +++ b/pumpkin-data/src/generated/villager.rs @@ -0,0 +1,4676 @@ +/* This file is generated. Do not edit manually. */ +use serde::Serialize; +#[derive(Clone, Copy, PartialEq)] +pub struct VillagerTradeItem { + pub item: &'static crate::item::Item, + pub count: i32, +} +#[derive(Clone, Copy, PartialEq)] +pub struct VillagerTrade { + pub wants: VillagerTradeItem, + pub wants_b: Option, + pub gives: VillagerTradeItem, + pub max_uses: i32, + pub xp: i32, + pub price_multiplier: f32, +} +#[derive(Clone, Copy, PartialEq)] +pub struct VillagerTradeSet { + pub trades: &'static [VillagerTrade], + pub amount: i32, +} +pub const TRADES_ARMORER_LEVEL_1: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 4i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::IRON_BOOTS, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 9i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::IRON_CHESTPLATE, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 5i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::IRON_HELMET, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 7i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::IRON_LEGGINGS, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_ARMORER_LEVEL_2: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CHAINMAIL_BOOTS, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CHAINMAIL_LEGGINGS, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_ARMORER_LEVEL_3: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::DIAMOND, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 4i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CHAINMAIL_CHESTPLATE, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CHAINMAIL_HELMET, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 5i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::SHIELD, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::LAVA_BUCKET, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_ARMORER_LEVEL_4: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 8i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::DIAMOND_BOOTS, + count: 1i32, + }, + max_uses: 3i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 14i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::DIAMOND_LEGGINGS, + count: 1i32, + }, + max_uses: 3i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_ARMORER_LEVEL_5: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 16i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::DIAMOND_CHESTPLATE, + count: 1i32, + }, + max_uses: 3i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 8i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::DIAMOND_HELMET, + count: 1i32, + }, + max_uses: 3i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_BUTCHER_LEVEL_1: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::CHICKEN, + count: 14i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::RABBIT_STEW, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::PORKCHOP, + count: 7i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::RABBIT, + count: 4i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_BUTCHER_LEVEL_2: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::COAL, + count: 15i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::COOKED_CHICKEN, + count: 8i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::COOKED_PORKCHOP, + count: 5i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_BUTCHER_LEVEL_3: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::BEEF, + count: 10i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::MUTTON, + count: 7i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_BUTCHER_LEVEL_4: &[VillagerTrade] = &[VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::DRIED_KELP_BLOCK, + count: 10i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, +}]; +pub const TRADES_BUTCHER_LEVEL_5: &[VillagerTrade] = &[VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::SWEET_BERRIES, + count: 10i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, +}]; +pub const TRADES_CARTOGRAPHER_LEVEL_1: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 7i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAP, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::PAPER, + count: 24i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_CARTOGRAPHER_LEVEL_2: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 8i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAP, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 8i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAP, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 8i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAP, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 8i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAP, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 8i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAP, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 8i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAP, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 8i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAP, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::GLASS_PANE, + count: 11i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_CARTOGRAPHER_LEVEL_3: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::COMPASS, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 13i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAP, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAP, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_CARTOGRAPHER_LEVEL_4: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BLACK_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BLUE_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BROWN_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CYAN_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GRAY_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GREEN_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 7i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::ITEM_FRAME, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIGHT_BLUE_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIME_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAGENTA_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::ORANGE_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::PINK_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::PURPLE_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::RED_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::WHITE_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::YELLOW_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_CARTOGRAPHER_LEVEL_5: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 14i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAP, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 8i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GLOBE_BANNER_PATTERN, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_CLERIC_LEVEL_1: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::REDSTONE, + count: 2i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::ROTTEN_FLESH, + count: 32i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_CLERIC_LEVEL_2: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LAPIS_LAZULI, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::GOLD_INGOT, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_CLERIC_LEVEL_3: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 4i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GLOWSTONE, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::RABBIT_FOOT, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_CLERIC_LEVEL_4: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 5i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::ENDER_PEARL, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::GLASS_BOTTLE, + count: 9i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::TURTLE_SCUTE, + count: 4i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_CLERIC_LEVEL_5: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EXPERIENCE_BOTTLE, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::NETHER_WART, + count: 22i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_FARMER_LEVEL_1: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::BEETROOT, + count: 15i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::CARROT, + count: 22i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BREAD, + count: 6i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::POTATO, + count: 26i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::WHEAT, + count: 20i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_FARMER_LEVEL_2: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::APPLE, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::PUMPKIN_PIE, + count: 4i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::PUMPKIN, + count: 6i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_FARMER_LEVEL_3: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::COOKIE, + count: 18i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::MELON, + count: 4i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_FARMER_LEVEL_4: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CAKE, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::SUSPICIOUS_STEW, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_FARMER_LEVEL_5: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 4i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GLISTERING_MELON_SLICE, + count: 3i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GOLDEN_CARROT, + count: 3i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_FISHERMAN_LEVEL_1: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::COAL, + count: 10i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::COD_BUCKET, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::COD, + count: 6i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::COOKED_COD, + count: 6i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::STRING, + count: 20i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_FISHERMAN_LEVEL_2: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::COD, + count: 15i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CAMPFIRE, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::SALMON, + count: 6i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::COOKED_SALMON, + count: 6i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_FISHERMAN_LEVEL_3: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::FISHING_ROD, + count: 1i32, + }, + max_uses: 3i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::SALMON, + count: 13i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_FISHERMAN_LEVEL_4: &[VillagerTrade] = &[VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::TROPICAL_FISH, + count: 6i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, +}]; +pub const TRADES_FISHERMAN_LEVEL_5: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::ACACIA_BOAT, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::DARK_OAK_BOAT, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::JUNGLE_BOAT, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::OAK_BOAT, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::PUFFERFISH, + count: 4i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::SPRUCE_BOAT, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_FLETCHER_LEVEL_1: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::ARROW, + count: 16i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::GRAVEL, + count: 10i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::FLINT, + count: 10i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::STICK, + count: 32i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_FLETCHER_LEVEL_2: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BOW, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::FLINT, + count: 26i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_FLETCHER_LEVEL_3: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CROSSBOW, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::STRING, + count: 14i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_FLETCHER_LEVEL_4: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BOW, + count: 1i32, + }, + max_uses: 3i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::FEATHER, + count: 24i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_FLETCHER_LEVEL_5: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::ARROW, + count: 5i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::TIPPED_ARROW, + count: 5i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CROSSBOW, + count: 1i32, + }, + max_uses: 3i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::TRIPWIRE_HOOK, + count: 8i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_LEATHERWORKER_LEVEL_1: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 7i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LEATHER_CHESTPLATE, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LEATHER_LEGGINGS, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::LEATHER, + count: 6i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_LEATHERWORKER_LEVEL_2: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 4i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LEATHER_BOOTS, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 5i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LEATHER_HELMET, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::FLINT, + count: 26i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_LEATHERWORKER_LEVEL_3: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 7i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LEATHER_CHESTPLATE, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::RABBIT_HIDE, + count: 9i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_LEATHERWORKER_LEVEL_4: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 6i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LEATHER_HORSE_ARMOR, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::TURTLE_SCUTE, + count: 4i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_LEATHERWORKER_LEVEL_5: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 5i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LEATHER_HELMET, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 6i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::SADDLE, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_LIBRARIAN_LEVEL_1: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 0i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::ENCHANTED_BOOK, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 9i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BOOKSHELF, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::PAPER, + count: 24i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_LIBRARIAN_LEVEL_2: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::BOOK, + count: 4i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 0i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::ENCHANTED_BOOK, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LANTERN, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_LIBRARIAN_LEVEL_3: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 0i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::ENCHANTED_BOOK, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GLASS, + count: 4i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::INK_SAC, + count: 5i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_LIBRARIAN_LEVEL_4: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 0i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::ENCHANTED_BOOK, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 5i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CLOCK, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 4i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::COMPASS, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::WRITABLE_BOOK, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_LIBRARIAN_LEVEL_5: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::RED_CANDLE, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::YELLOW_CANDLE, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_MASON_LEVEL_1: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::CLAY_BALL, + count: 10i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BRICK, + count: 10i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_MASON_LEVEL_2: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CHISELED_STONE_BRICKS, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::STONE, + count: 20i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_MASON_LEVEL_3: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::ANDESITE, + count: 16i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::DIORITE, + count: 16i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::DRIPSTONE_BLOCK, + count: 4i32, + }, + max_uses: 16i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::POLISHED_ANDESITE, + count: 4i32, + }, + max_uses: 16i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::POLISHED_DIORITE, + count: 4i32, + }, + max_uses: 16i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::POLISHED_GRANITE, + count: 4i32, + }, + max_uses: 16i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::GRANITE, + count: 16i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_MASON_LEVEL_4: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BLACK_GLAZED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BLACK_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BLUE_GLAZED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BLUE_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BROWN_GLAZED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BROWN_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CYAN_GLAZED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CYAN_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GRAY_GLAZED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GRAY_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GREEN_GLAZED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GREEN_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIGHT_BLUE_GLAZED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIGHT_BLUE_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIGHT_GRAY_GLAZED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIGHT_GRAY_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIME_GLAZED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIME_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAGENTA_GLAZED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAGENTA_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::ORANGE_GLAZED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::ORANGE_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::PINK_GLAZED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::PINK_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::PURPLE_GLAZED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::PURPLE_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::RED_GLAZED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::RED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::WHITE_GLAZED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::WHITE_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::YELLOW_GLAZED_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::YELLOW_TERRACOTTA, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::QUARTZ, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_MASON_LEVEL_5: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::QUARTZ_BLOCK, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::QUARTZ_PILLAR, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_SHEPHERD_LEVEL_1: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::BLACK_WOOL, + count: 18i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::BROWN_WOOL, + count: 18i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::SHEARS, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::GRAY_WOOL, + count: 18i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::WHITE_WOOL, + count: 18i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_SHEPHERD_LEVEL_2: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::BLACK_DYE, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BLACK_CARPET, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BLACK_WOOL, + count: 1i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BLUE_CARPET, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BLUE_WOOL, + count: 1i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BROWN_CARPET, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BROWN_WOOL, + count: 1i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CYAN_CARPET, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CYAN_WOOL, + count: 1i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GRAY_CARPET, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GRAY_WOOL, + count: 1i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GREEN_CARPET, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GREEN_WOOL, + count: 1i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIGHT_BLUE_CARPET, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIGHT_BLUE_WOOL, + count: 1i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIGHT_GRAY_CARPET, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIGHT_GRAY_WOOL, + count: 1i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIME_CARPET, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIME_WOOL, + count: 1i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAGENTA_CARPET, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAGENTA_WOOL, + count: 1i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::ORANGE_CARPET, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::ORANGE_WOOL, + count: 1i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::PINK_CARPET, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::PINK_WOOL, + count: 1i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::PURPLE_CARPET, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::PURPLE_WOOL, + count: 1i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::RED_CARPET, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::RED_WOOL, + count: 1i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::WHITE_CARPET, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::WHITE_WOOL, + count: 1i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::YELLOW_CARPET, + count: 4i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::YELLOW_WOOL, + count: 1i32, + }, + max_uses: 16i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::GRAY_DYE, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::LIGHT_BLUE_DYE, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::LIME_DYE, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::WHITE_DYE, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_SHEPHERD_LEVEL_3: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BLACK_BED, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BLUE_BED, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BROWN_BED, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CYAN_BED, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GRAY_BED, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GREEN_BED, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIGHT_BLUE_BED, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIGHT_GRAY_BED, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIME_BED, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAGENTA_BED, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::ORANGE_BED, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::PINK_BED, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::PURPLE_BED, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::RED_BED, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::WHITE_BED, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::YELLOW_BED, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::LIGHT_GRAY_DYE, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::ORANGE_DYE, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::PINK_DYE, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::RED_DYE, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::YELLOW_DYE, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_SHEPHERD_LEVEL_4: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::BLUE_DYE, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::BROWN_DYE, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::CYAN_DYE, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BLACK_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BLUE_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BROWN_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::CYAN_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GRAY_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::GREEN_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIGHT_BLUE_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIGHT_GRAY_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::LIME_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::MAGENTA_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::ORANGE_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::PINK_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::PURPLE_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::RED_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::WHITE_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::YELLOW_BANNER, + count: 1i32, + }, + max_uses: 12i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::GREEN_DYE, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::MAGENTA_DYE, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::PURPLE_DYE, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 16i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_SHEPHERD_LEVEL_5: &[VillagerTrade] = &[VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::PAINTING, + count: 3i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, +}]; +pub const TRADES_TOOLSMITH_LEVEL_1: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::STONE_AXE, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::STONE_HOE, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::STONE_PICKAXE, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::STONE_SHOVEL, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_TOOLSMITH_LEVEL_2: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 36i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BELL, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::IRON_INGOT, + count: 4i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_TOOLSMITH_LEVEL_3: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 4i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::DIAMOND_HOE, + count: 1i32, + }, + max_uses: 3i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::IRON_AXE, + count: 1i32, + }, + max_uses: 3i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::IRON_PICKAXE, + count: 1i32, + }, + max_uses: 3i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::IRON_SHOVEL, + count: 1i32, + }, + max_uses: 3i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::FLINT, + count: 30i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 20i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_TOOLSMITH_LEVEL_4: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::DIAMOND, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::DIAMOND_AXE, + count: 1i32, + }, + max_uses: 3i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 5i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::DIAMOND_SHOVEL, + count: 1i32, + }, + max_uses: 3i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_TOOLSMITH_LEVEL_5: &[VillagerTrade] = &[VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 13i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::DIAMOND_PICKAXE, + count: 1i32, + }, + max_uses: 3i32, + xp: 30i32, + price_multiplier: 0.05f32, +}]; +pub const TRADES_WEAPONSMITH_LEVEL_1: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 2i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::IRON_SWORD, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 3i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::IRON_AXE, + count: 1i32, + }, + max_uses: 12i32, + xp: 2i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_WEAPONSMITH_LEVEL_2: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 36i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::BELL, + count: 1i32, + }, + max_uses: 12i32, + xp: 5i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::IRON_INGOT, + count: 4i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 10i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_WEAPONSMITH_LEVEL_3: &[VillagerTrade] = &[VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::FLINT, + count: 24i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 20i32, + price_multiplier: 0.05f32, +}]; +pub const TRADES_WEAPONSMITH_LEVEL_4: &[VillagerTrade] = &[ + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::DIAMOND, + count: 1i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 1i32, + }, + max_uses: 12i32, + xp: 30i32, + price_multiplier: 0.05f32, + }, + VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 12i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::DIAMOND_AXE, + count: 1i32, + }, + max_uses: 3i32, + xp: 15i32, + price_multiplier: 0.05f32, + }, +]; +pub const TRADES_WEAPONSMITH_LEVEL_5: &[VillagerTrade] = &[VillagerTrade { + wants: VillagerTradeItem { + item: &crate::item::Item::EMERALD, + count: 8i32, + }, + wants_b: None, + gives: VillagerTradeItem { + item: &crate::item::Item::DIAMOND_SWORD, + count: 1i32, + }, + max_uses: 3i32, + xp: 30i32, + price_multiplier: 0.05f32, +}]; +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)] +#[repr(i32)] +pub enum VillagerProfession { + None, + Armorer, + Butcher, + Cartographer, + Cleric, + Farmer, + Fisherman, + Fletcher, + Leatherworker, + Librarian, + Mason, + Nitwit, + Shepherd, + Toolsmith, + Weaponsmith, +} +impl VillagerProfession { + #[must_use] + pub fn from_i32(id: i32) -> Option { + match id { + 0i32 => Some(Self::None), + 1i32 => Some(Self::Armorer), + 2i32 => Some(Self::Butcher), + 3i32 => Some(Self::Cartographer), + 4i32 => Some(Self::Cleric), + 5i32 => Some(Self::Farmer), + 6i32 => Some(Self::Fisherman), + 7i32 => Some(Self::Fletcher), + 8i32 => Some(Self::Leatherworker), + 9i32 => Some(Self::Librarian), + 10i32 => Some(Self::Mason), + 11i32 => Some(Self::Nitwit), + 12i32 => Some(Self::Shepherd), + 13i32 => Some(Self::Toolsmith), + 14i32 => Some(Self::Weaponsmith), + _ => None, + } + } + #[must_use] + pub fn work_sound(&self) -> Option { + match self { + Self::None => None, + Self::Armorer => Some(crate::sound::Sound::EntityVillagerWorkArmorer), + Self::Butcher => Some(crate::sound::Sound::EntityVillagerWorkButcher), + Self::Cartographer => Some(crate::sound::Sound::EntityVillagerWorkCartographer), + Self::Cleric => Some(crate::sound::Sound::EntityVillagerWorkCleric), + Self::Farmer => Some(crate::sound::Sound::EntityVillagerWorkFarmer), + Self::Fisherman => Some(crate::sound::Sound::EntityVillagerWorkFisherman), + Self::Fletcher => Some(crate::sound::Sound::EntityVillagerWorkFletcher), + Self::Leatherworker => Some(crate::sound::Sound::EntityVillagerWorkLeatherworker), + Self::Librarian => Some(crate::sound::Sound::EntityVillagerWorkLibrarian), + Self::Mason => Some(crate::sound::Sound::EntityVillagerWorkMason), + Self::Nitwit => None, + Self::Shepherd => Some(crate::sound::Sound::EntityVillagerWorkShepherd), + Self::Toolsmith => Some(crate::sound::Sound::EntityVillagerWorkToolsmith), + Self::Weaponsmith => Some(crate::sound::Sound::EntityVillagerWorkWeaponsmith), + } + } + #[must_use] + pub fn requested_items(&self) -> &'static [&'static crate::item::Item] { + match self { + Self::None => &[], + Self::Armorer => &[], + Self::Butcher => &[], + Self::Cartographer => &[], + Self::Cleric => &[], + Self::Farmer => &[ + &crate::item::Item::WHEAT, + &crate::item::Item::WHEAT_SEEDS, + &crate::item::Item::BEETROOT_SEEDS, + &crate::item::Item::BONE_MEAL, + ], + Self::Fisherman => &[], + Self::Fletcher => &[], + Self::Leatherworker => &[], + Self::Librarian => &[], + Self::Mason => &[], + Self::Nitwit => &[], + Self::Shepherd => &[], + Self::Toolsmith => &[], + Self::Weaponsmith => &[], + } + } + #[must_use] + pub fn translation_key(&self) -> &'static str { + match self { + Self::None => "entity.minecraft.villager.none", + Self::Armorer => "entity.minecraft.villager.armorer", + Self::Butcher => "entity.minecraft.villager.butcher", + Self::Cartographer => "entity.minecraft.villager.cartographer", + Self::Cleric => "entity.minecraft.villager.cleric", + Self::Farmer => "entity.minecraft.villager.farmer", + Self::Fisherman => "entity.minecraft.villager.fisherman", + Self::Fletcher => "entity.minecraft.villager.fletcher", + Self::Leatherworker => "entity.minecraft.villager.leatherworker", + Self::Librarian => "entity.minecraft.villager.librarian", + Self::Mason => "entity.minecraft.villager.mason", + Self::Nitwit => "entity.minecraft.villager.nitwit", + Self::Shepherd => "entity.minecraft.villager.shepherd", + Self::Toolsmith => "entity.minecraft.villager.toolsmith", + Self::Weaponsmith => "entity.minecraft.villager.weaponsmith", + } + } + #[must_use] + pub fn trade_set(&self, level: i32) -> Option { + match self { + Self::None => None, + Self::Armorer => match level { + 1i32 => Some(VillagerTradeSet { + trades: TRADES_ARMORER_LEVEL_1, + amount: 2i32, + }), + 2i32 => Some(VillagerTradeSet { + trades: TRADES_ARMORER_LEVEL_2, + amount: 2i32, + }), + 3i32 => Some(VillagerTradeSet { + trades: TRADES_ARMORER_LEVEL_3, + amount: 2i32, + }), + 4i32 => Some(VillagerTradeSet { + trades: TRADES_ARMORER_LEVEL_4, + amount: 2i32, + }), + 5i32 => Some(VillagerTradeSet { + trades: TRADES_ARMORER_LEVEL_5, + amount: 2i32, + }), + _ => None, + }, + Self::Butcher => match level { + 1i32 => Some(VillagerTradeSet { + trades: TRADES_BUTCHER_LEVEL_1, + amount: 2i32, + }), + 2i32 => Some(VillagerTradeSet { + trades: TRADES_BUTCHER_LEVEL_2, + amount: 2i32, + }), + 3i32 => Some(VillagerTradeSet { + trades: TRADES_BUTCHER_LEVEL_3, + amount: 2i32, + }), + 4i32 => Some(VillagerTradeSet { + trades: TRADES_BUTCHER_LEVEL_4, + amount: 2i32, + }), + 5i32 => Some(VillagerTradeSet { + trades: TRADES_BUTCHER_LEVEL_5, + amount: 2i32, + }), + _ => None, + }, + Self::Cartographer => match level { + 1i32 => Some(VillagerTradeSet { + trades: TRADES_CARTOGRAPHER_LEVEL_1, + amount: 2i32, + }), + 2i32 => Some(VillagerTradeSet { + trades: TRADES_CARTOGRAPHER_LEVEL_2, + amount: 2i32, + }), + 3i32 => Some(VillagerTradeSet { + trades: TRADES_CARTOGRAPHER_LEVEL_3, + amount: 2i32, + }), + 4i32 => Some(VillagerTradeSet { + trades: TRADES_CARTOGRAPHER_LEVEL_4, + amount: 2i32, + }), + 5i32 => Some(VillagerTradeSet { + trades: TRADES_CARTOGRAPHER_LEVEL_5, + amount: 2i32, + }), + _ => None, + }, + Self::Cleric => match level { + 1i32 => Some(VillagerTradeSet { + trades: TRADES_CLERIC_LEVEL_1, + amount: 2i32, + }), + 2i32 => Some(VillagerTradeSet { + trades: TRADES_CLERIC_LEVEL_2, + amount: 2i32, + }), + 3i32 => Some(VillagerTradeSet { + trades: TRADES_CLERIC_LEVEL_3, + amount: 2i32, + }), + 4i32 => Some(VillagerTradeSet { + trades: TRADES_CLERIC_LEVEL_4, + amount: 2i32, + }), + 5i32 => Some(VillagerTradeSet { + trades: TRADES_CLERIC_LEVEL_5, + amount: 2i32, + }), + _ => None, + }, + Self::Farmer => match level { + 1i32 => Some(VillagerTradeSet { + trades: TRADES_FARMER_LEVEL_1, + amount: 2i32, + }), + 2i32 => Some(VillagerTradeSet { + trades: TRADES_FARMER_LEVEL_2, + amount: 2i32, + }), + 3i32 => Some(VillagerTradeSet { + trades: TRADES_FARMER_LEVEL_3, + amount: 2i32, + }), + 4i32 => Some(VillagerTradeSet { + trades: TRADES_FARMER_LEVEL_4, + amount: 2i32, + }), + 5i32 => Some(VillagerTradeSet { + trades: TRADES_FARMER_LEVEL_5, + amount: 2i32, + }), + _ => None, + }, + Self::Fisherman => match level { + 1i32 => Some(VillagerTradeSet { + trades: TRADES_FISHERMAN_LEVEL_1, + amount: 2i32, + }), + 2i32 => Some(VillagerTradeSet { + trades: TRADES_FISHERMAN_LEVEL_2, + amount: 2i32, + }), + 3i32 => Some(VillagerTradeSet { + trades: TRADES_FISHERMAN_LEVEL_3, + amount: 2i32, + }), + 4i32 => Some(VillagerTradeSet { + trades: TRADES_FISHERMAN_LEVEL_4, + amount: 2i32, + }), + 5i32 => Some(VillagerTradeSet { + trades: TRADES_FISHERMAN_LEVEL_5, + amount: 2i32, + }), + _ => None, + }, + Self::Fletcher => match level { + 1i32 => Some(VillagerTradeSet { + trades: TRADES_FLETCHER_LEVEL_1, + amount: 2i32, + }), + 2i32 => Some(VillagerTradeSet { + trades: TRADES_FLETCHER_LEVEL_2, + amount: 2i32, + }), + 3i32 => Some(VillagerTradeSet { + trades: TRADES_FLETCHER_LEVEL_3, + amount: 2i32, + }), + 4i32 => Some(VillagerTradeSet { + trades: TRADES_FLETCHER_LEVEL_4, + amount: 2i32, + }), + 5i32 => Some(VillagerTradeSet { + trades: TRADES_FLETCHER_LEVEL_5, + amount: 2i32, + }), + _ => None, + }, + Self::Leatherworker => match level { + 1i32 => Some(VillagerTradeSet { + trades: TRADES_LEATHERWORKER_LEVEL_1, + amount: 2i32, + }), + 2i32 => Some(VillagerTradeSet { + trades: TRADES_LEATHERWORKER_LEVEL_2, + amount: 2i32, + }), + 3i32 => Some(VillagerTradeSet { + trades: TRADES_LEATHERWORKER_LEVEL_3, + amount: 2i32, + }), + 4i32 => Some(VillagerTradeSet { + trades: TRADES_LEATHERWORKER_LEVEL_4, + amount: 2i32, + }), + 5i32 => Some(VillagerTradeSet { + trades: TRADES_LEATHERWORKER_LEVEL_5, + amount: 2i32, + }), + _ => None, + }, + Self::Librarian => match level { + 1i32 => Some(VillagerTradeSet { + trades: TRADES_LIBRARIAN_LEVEL_1, + amount: 2i32, + }), + 2i32 => Some(VillagerTradeSet { + trades: TRADES_LIBRARIAN_LEVEL_2, + amount: 2i32, + }), + 3i32 => Some(VillagerTradeSet { + trades: TRADES_LIBRARIAN_LEVEL_3, + amount: 2i32, + }), + 4i32 => Some(VillagerTradeSet { + trades: TRADES_LIBRARIAN_LEVEL_4, + amount: 2i32, + }), + 5i32 => Some(VillagerTradeSet { + trades: TRADES_LIBRARIAN_LEVEL_5, + amount: 3i32, + }), + _ => None, + }, + Self::Mason => match level { + 1i32 => Some(VillagerTradeSet { + trades: TRADES_MASON_LEVEL_1, + amount: 2i32, + }), + 2i32 => Some(VillagerTradeSet { + trades: TRADES_MASON_LEVEL_2, + amount: 2i32, + }), + 3i32 => Some(VillagerTradeSet { + trades: TRADES_MASON_LEVEL_3, + amount: 2i32, + }), + 4i32 => Some(VillagerTradeSet { + trades: TRADES_MASON_LEVEL_4, + amount: 2i32, + }), + 5i32 => Some(VillagerTradeSet { + trades: TRADES_MASON_LEVEL_5, + amount: 2i32, + }), + _ => None, + }, + Self::Nitwit => None, + Self::Shepherd => match level { + 1i32 => Some(VillagerTradeSet { + trades: TRADES_SHEPHERD_LEVEL_1, + amount: 2i32, + }), + 2i32 => Some(VillagerTradeSet { + trades: TRADES_SHEPHERD_LEVEL_2, + amount: 2i32, + }), + 3i32 => Some(VillagerTradeSet { + trades: TRADES_SHEPHERD_LEVEL_3, + amount: 2i32, + }), + 4i32 => Some(VillagerTradeSet { + trades: TRADES_SHEPHERD_LEVEL_4, + amount: 2i32, + }), + 5i32 => Some(VillagerTradeSet { + trades: TRADES_SHEPHERD_LEVEL_5, + amount: 2i32, + }), + _ => None, + }, + Self::Toolsmith => match level { + 1i32 => Some(VillagerTradeSet { + trades: TRADES_TOOLSMITH_LEVEL_1, + amount: 2i32, + }), + 2i32 => Some(VillagerTradeSet { + trades: TRADES_TOOLSMITH_LEVEL_2, + amount: 2i32, + }), + 3i32 => Some(VillagerTradeSet { + trades: TRADES_TOOLSMITH_LEVEL_3, + amount: 2i32, + }), + 4i32 => Some(VillagerTradeSet { + trades: TRADES_TOOLSMITH_LEVEL_4, + amount: 2i32, + }), + 5i32 => Some(VillagerTradeSet { + trades: TRADES_TOOLSMITH_LEVEL_5, + amount: 2i32, + }), + _ => None, + }, + Self::Weaponsmith => match level { + 1i32 => Some(VillagerTradeSet { + trades: TRADES_WEAPONSMITH_LEVEL_1, + amount: 2i32, + }), + 2i32 => Some(VillagerTradeSet { + trades: TRADES_WEAPONSMITH_LEVEL_2, + amount: 2i32, + }), + 3i32 => Some(VillagerTradeSet { + trades: TRADES_WEAPONSMITH_LEVEL_3, + amount: 2i32, + }), + 4i32 => Some(VillagerTradeSet { + trades: TRADES_WEAPONSMITH_LEVEL_4, + amount: 2i32, + }), + 5i32 => Some(VillagerTradeSet { + trades: TRADES_WEAPONSMITH_LEVEL_5, + amount: 2i32, + }), + _ => None, + }, + } + } +} +impl TryFrom for VillagerProfession { + type Error = (); + fn try_from(value: i32) -> Result { + Self::from_i32(value).ok_or(()) + } +} +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)] +#[repr(i32)] +pub enum VillagerType { + Desert, + Jungle, + Plains, + Savanna, + Snow, + Swamp, + Taiga, +} +impl VillagerType { + #[must_use] + pub fn from_i32(id: i32) -> Option { + match id { + 0i32 => Some(Self::Desert), + 1i32 => Some(Self::Jungle), + 2i32 => Some(Self::Plains), + 3i32 => Some(Self::Savanna), + 4i32 => Some(Self::Snow), + 5i32 => Some(Self::Swamp), + 6i32 => Some(Self::Taiga), + _ => None, + } + } +} +impl TryFrom for VillagerType { + type Error = (); + fn try_from(value: i32) -> Result { + Self::from_i32(value).ok_or(()) + } +} diff --git a/pumpkin-data/src/lib.rs b/pumpkin-data/src/lib.rs index f7174aec8..b83e61af8 100644 --- a/pumpkin-data/src/lib.rs +++ b/pumpkin-data/src/lib.rs @@ -294,3 +294,8 @@ pub mod chunk_gen_settings; #[rustfmt::skip] #[path = "generated/carver.rs"] pub mod carver; + +#[cfg(feature = "villager")] +#[rustfmt::skip] +#[path = "generated/villager.rs"] +pub mod villager; diff --git a/pumpkin-inventory/src/brewing/brewing_screen_handler.rs b/pumpkin-inventory/src/brewing/brewing_screen_handler.rs index 24bc282c7..f346f69b3 100644 --- a/pumpkin-inventory/src/brewing/brewing_screen_handler.rs +++ b/pumpkin-inventory/src/brewing/brewing_screen_handler.rs @@ -103,6 +103,10 @@ impl ScreenHandler for BrewingScreenHandler { self } + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + fn get_behaviour(&self) -> &ScreenHandlerBehaviour { &self.behaviour } diff --git a/pumpkin-inventory/src/crafting/crafting_screen_handler.rs b/pumpkin-inventory/src/crafting/crafting_screen_handler.rs index b569a7f8e..420b75bb8 100644 --- a/pumpkin-inventory/src/crafting/crafting_screen_handler.rs +++ b/pumpkin-inventory/src/crafting/crafting_screen_handler.rs @@ -568,6 +568,10 @@ impl ScreenHandler for CraftingTableScreenHandler { self } + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + fn get_behaviour(&self) -> &ScreenHandlerBehaviour { &self.behaviour } diff --git a/pumpkin-inventory/src/furnace_like/furnace_like_screen_handler.rs b/pumpkin-inventory/src/furnace_like/furnace_like_screen_handler.rs index 88b70b854..10174d1d6 100644 --- a/pumpkin-inventory/src/furnace_like/furnace_like_screen_handler.rs +++ b/pumpkin-inventory/src/furnace_like/furnace_like_screen_handler.rs @@ -136,6 +136,10 @@ impl ScreenHandler for FurnaceLikeScreenHandler { self } + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + fn get_behaviour(&self) -> &ScreenHandlerBehaviour { &self.behaviour } diff --git a/pumpkin-inventory/src/generic_container_screen_handler.rs b/pumpkin-inventory/src/generic_container_screen_handler.rs index 74c59dc0b..905080b4d 100644 --- a/pumpkin-inventory/src/generic_container_screen_handler.rs +++ b/pumpkin-inventory/src/generic_container_screen_handler.rs @@ -167,6 +167,10 @@ impl ScreenHandler for GenericContainerScreenHandler { self } + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + fn get_behaviour(&self) -> &ScreenHandlerBehaviour { &self.behaviour } diff --git a/pumpkin-inventory/src/gui_builder.rs b/pumpkin-inventory/src/gui_builder.rs index 0589c3a65..39e01bf65 100644 --- a/pumpkin-inventory/src/gui_builder.rs +++ b/pumpkin-inventory/src/gui_builder.rs @@ -111,6 +111,10 @@ impl ScreenHandler for GUIScreenHandler { self } + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + fn get_behaviour(&self) -> &ScreenHandlerBehaviour { &self.behaviour } diff --git a/pumpkin-inventory/src/lib.rs b/pumpkin-inventory/src/lib.rs index 4e43e9179..378cd6964 100644 --- a/pumpkin-inventory/src/lib.rs +++ b/pumpkin-inventory/src/lib.rs @@ -40,6 +40,7 @@ mod error; pub mod furnace_like; pub mod generic_container_screen_handler; pub mod gui_builder; +pub mod merchant; pub mod player; pub mod screen_handler; pub mod slot; diff --git a/pumpkin-inventory/src/merchant/merchant_screen_handler.rs b/pumpkin-inventory/src/merchant/merchant_screen_handler.rs new file mode 100644 index 000000000..652879314 --- /dev/null +++ b/pumpkin-inventory/src/merchant/merchant_screen_handler.rs @@ -0,0 +1,222 @@ +use std::any::Any; +use std::sync::Arc; + +use pumpkin_data::{item_stack::ItemStack, screen::WindowType}; +use pumpkin_world::inventory::Inventory; + +use crate::{ + player::player_inventory::PlayerInventory, + screen_handler::{ + InventoryPlayer, ItemStackFuture, ScreenHandler, ScreenHandlerBehaviour, + ScreenHandlerFuture, + }, + slot::NormalSlot, +}; + +pub struct MerchantScreenHandler { + pub inventory: Arc, + behaviour: ScreenHandlerBehaviour, + selected_offer: usize, + pub offers: Vec, +} + +impl MerchantScreenHandler { + pub async fn new( + sync_id: u8, + player_inventory: &Arc, + inventory: Arc, + offers: Vec, + ) -> Self { + let mut handler = Self { + inventory: inventory.clone(), + behaviour: ScreenHandlerBehaviour::new(sync_id, Some(WindowType::Merchant)), + selected_offer: 0, + offers, + }; + + inventory.on_open().await; + + // Merchant specific slots: 2 input, 1 output + for i in 0..3 { + handler.add_slot(Arc::new(NormalSlot::new(inventory.clone(), i))); + } + + let player_inventory: Arc = player_inventory.clone(); + handler.add_player_slots(&player_inventory); + + handler + } + + pub async fn set_selected_offer(&mut self, index: usize) { + self.selected_offer = index; + self.update_result_slot().await; + self.send_content_updates().await; + } + + pub async fn update_result_slot(&mut self) { + if self.selected_offer >= self.offers.len() { + self.inventory.set_stack(2, ItemStack::EMPTY.clone()).await; + return; + } + + let offer = &self.offers[self.selected_offer]; + let input_a = self.inventory.get_stack(0).await; + let input_a = input_a.lock().await; + let input_b = self.inventory.get_stack(1).await; + let input_b = input_b.lock().await; + + let match_a = input_a.are_items_and_components_equal(&offer.base_cost_a.0) + && input_a.item_count >= offer.base_cost_a.0.item_count; + + let match_b = offer.cost_b.as_ref().map_or_else( + || input_b.is_empty(), + |cost_b| { + input_b.are_items_and_components_equal(&cost_b.0) + && input_b.item_count >= cost_b.0.item_count + }, + ); + + if match_a && match_b { + self.inventory.set_stack(2, (*offer.output.0).clone()).await; + } else { + self.inventory.set_stack(2, ItemStack::EMPTY.clone()).await; + } + } +} + +impl ScreenHandler for MerchantScreenHandler { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + + fn get_behaviour(&self) -> &ScreenHandlerBehaviour { + &self.behaviour + } + + fn get_behaviour_mut(&mut self) -> &mut ScreenHandlerBehaviour { + &mut self.behaviour + } + + fn on_closed<'a>(&'a mut self, player: &'a dyn InventoryPlayer) -> ScreenHandlerFuture<'a, ()> { + Box::pin(async move { + self.default_on_closed(player).await; + self.inventory.on_close().await; + // Vanilla drops items from merchant container on close + for i in 0..2 { + // Drop inputs only, output is virtual/ghost in some sense or just cleared + let stack = self.inventory.remove_stack(i).await; + if !stack.is_empty() { + player.drop_item(stack, false).await; + } + } + // Clear output slot + self.inventory.set_stack(2, ItemStack::EMPTY.clone()).await; + }) + } + + fn quick_move<'a>( + &'a mut self, + _player: &'a dyn InventoryPlayer, + slot_index: i32, + ) -> ItemStackFuture<'a> { + Box::pin(async move { + let mut stack_left = ItemStack::EMPTY.clone(); + let slot = self.get_behaviour().slots[slot_index as usize].clone(); + + if slot.has_stack().await { + let slot_stack_lock = slot.get_stack().await; + let slot_stack_guard = slot_stack_lock.lock().await; + stack_left = slot_stack_guard.clone(); + drop(slot_stack_guard); + + let mut slot_stack_mut = slot_stack_lock.lock().await; + + if slot_index < 3 { + // From merchant slots to player inventory + if !self + .insert_item( + &mut slot_stack_mut, + 3, + self.get_behaviour().slots.len() as i32, + true, + ) + .await + { + return ItemStack::EMPTY.clone(); + } + } else { + // From player inventory to merchant inputs (0 and 1) + if !self.insert_item(&mut slot_stack_mut, 0, 2, false).await { + return ItemStack::EMPTY.clone(); + } + } + + if slot_stack_mut.is_empty() { + drop(slot_stack_mut); + slot.set_stack(ItemStack::EMPTY.clone()).await; + } else { + drop(slot_stack_mut); + slot.mark_dirty().await; + } + } + + stack_left + }) + } + + fn on_slot_click<'a>( + &'a mut self, + slot_index: i32, + button: i32, + action_type: pumpkin_protocol::java::server::play::SlotActionType, + player: &'a dyn InventoryPlayer, + ) -> ScreenHandlerFuture<'a, ()> { + Box::pin(async move { + if slot_index == 2 { + // Special handling for taking from output slot + let result_slot = self.get_behaviour().slots[2].clone(); + if result_slot.has_stack().await { + let result_stack = result_slot.get_cloned_stack().await; + if !result_stack.is_empty() { + // Consume inputs + let offer = &self.offers[self.selected_offer]; + + let input_a = self.inventory.get_stack(0).await; + let mut input_a = input_a.lock().await; + input_a.decrement(offer.base_cost_a.0.item_count); + if input_a.is_empty() { + *input_a = ItemStack::EMPTY.clone(); + } + drop(input_a); + self.get_behaviour().slots[0].mark_dirty().await; + + if let Some(cost_b) = &offer.cost_b { + let input_b = self.inventory.get_stack(1).await; + let mut input_b = input_b.lock().await; + input_b.decrement(cost_b.0.item_count); + if input_b.is_empty() { + *input_b = ItemStack::EMPTY.clone(); + } + drop(input_b); + self.get_behaviour().slots[1].mark_dirty().await; + } + + // Award XP + player.award_experience(offer.xp).await; + } + } + } + + self.internal_on_slot_click(slot_index, button, action_type, player) + .await; + if slot_index == 0 || slot_index == 1 || slot_index == 2 { + self.update_result_slot().await; + self.send_content_updates().await; + } + }) + } +} diff --git a/pumpkin-inventory/src/merchant/mod.rs b/pumpkin-inventory/src/merchant/mod.rs new file mode 100644 index 000000000..c1a11084f --- /dev/null +++ b/pumpkin-inventory/src/merchant/mod.rs @@ -0,0 +1 @@ +pub mod merchant_screen_handler; diff --git a/pumpkin-inventory/src/player/player_screen_handler.rs b/pumpkin-inventory/src/player/player_screen_handler.rs index ba0c80ed9..0e34cbc22 100644 --- a/pumpkin-inventory/src/player/player_screen_handler.rs +++ b/pumpkin-inventory/src/player/player_screen_handler.rs @@ -121,6 +121,10 @@ impl ScreenHandler for PlayerScreenHandler { self } + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + fn get_behaviour(&self) -> &ScreenHandlerBehaviour { &self.behaviour } diff --git a/pumpkin-inventory/src/screen_handler.rs b/pumpkin-inventory/src/screen_handler.rs index f3243543d..504553570 100644 --- a/pumpkin-inventory/src/screen_handler.rs +++ b/pumpkin-inventory/src/screen_handler.rs @@ -223,6 +223,9 @@ pub trait ScreenHandler: Send + Sync { /// Returns this screen handler as an Any reference. fn as_any(&self) -> &dyn Any; + /// Returns this screen handler as a mutable Any reference. + fn as_any_mut(&mut self) -> &mut dyn Any; + /// Gets the sync ID for this screen handler. fn sync_id(&self) -> u8 { self.get_behaviour().sync_id diff --git a/pumpkin-protocol/src/codec/item_stack_seralizer.rs b/pumpkin-protocol/src/codec/item_stack_seralizer.rs index f5cc31697..80e04dc6c 100644 --- a/pumpkin-protocol/src/codec/item_stack_seralizer.rs +++ b/pumpkin-protocol/src/codec/item_stack_seralizer.rs @@ -13,6 +13,7 @@ use serde::{ }; use std::borrow::Cow; +#[derive(Clone)] pub struct ItemStackSerializer<'a>(pub Cow<'a, ItemStack>); fn item_component_counts(stack: &ItemStack) -> (u8, u8) { diff --git a/pumpkin-protocol/src/java/client/play/merchant_offers.rs b/pumpkin-protocol/src/java/client/play/merchant_offers.rs new file mode 100644 index 000000000..6447afe13 --- /dev/null +++ b/pumpkin-protocol/src/java/client/play/merchant_offers.rs @@ -0,0 +1,52 @@ +use pumpkin_data::packet::clientbound::PLAY_MERCHANT_OFFERS; +use pumpkin_macros::java_packet; +use serde::{Deserialize, Serialize}; + +use crate::VarInt; +use crate::codec::item_stack_seralizer::ItemStackSerializer; + +#[derive(Serialize, Deserialize, Clone)] +pub struct MerchantOffer { + pub base_cost_a: ItemStackSerializer<'static>, + pub output: ItemStackSerializer<'static>, + pub cost_b: Option>, + pub is_disabled: bool, + pub uses: i32, + pub max_uses: i32, + pub xp: i32, + pub special_price: i32, + pub price_multiplier: f32, + pub demand: i32, +} + +#[derive(Serialize)] +#[java_packet(PLAY_MERCHANT_OFFERS)] +pub struct CMerchantOffers { + pub window_id: VarInt, + pub offers: Vec, + pub villager_level: VarInt, + pub experience: VarInt, + pub is_regular_villager: bool, + pub can_restock: bool, +} + +impl CMerchantOffers { + #[must_use] + pub const fn new( + window_id: VarInt, + offers: Vec, + villager_level: VarInt, + experience: VarInt, + is_regular_villager: bool, + can_restock: bool, + ) -> Self { + Self { + window_id, + offers, + villager_level, + experience, + is_regular_villager, + can_restock, + } + } +} diff --git a/pumpkin-protocol/src/java/client/play/mod.rs b/pumpkin-protocol/src/java/client/play/mod.rs index d3f831065..feff59037 100644 --- a/pumpkin-protocol/src/java/client/play/mod.rs +++ b/pumpkin-protocol/src/java/client/play/mod.rs @@ -37,6 +37,7 @@ mod keep_alive; mod level_event; mod light_update; mod login; +mod merchant_offers; mod multi_block_update; mod open_screen; mod open_sign_editor; @@ -136,6 +137,7 @@ pub use keep_alive::*; pub use level_event::*; pub use light_update::*; pub use login::*; +pub use merchant_offers::*; pub use multi_block_update::*; pub use open_screen::*; pub use open_sign_editor::*; diff --git a/pumpkin-protocol/src/java/server/play/mod.rs b/pumpkin-protocol/src/java/server/play/mod.rs index 6175247ea..4b2e89dc5 100644 --- a/pumpkin-protocol/src/java/server/play/mod.rs +++ b/pumpkin-protocol/src/java/server/play/mod.rs @@ -31,6 +31,7 @@ mod player_rotation; mod player_session; mod recipe_book_change_settings; mod recipe_book_seen_recipe; +mod select_trade; mod set_command_block; mod set_creative_slot; mod set_held_item; @@ -72,6 +73,7 @@ pub use player_rotation::*; pub use player_session::*; pub use recipe_book_change_settings::*; pub use recipe_book_seen_recipe::*; +pub use select_trade::*; pub use set_command_block::*; pub use set_creative_slot::*; pub use set_held_item::*; diff --git a/pumpkin-protocol/src/java/server/play/select_trade.rs b/pumpkin-protocol/src/java/server/play/select_trade.rs new file mode 100644 index 000000000..d500f54db --- /dev/null +++ b/pumpkin-protocol/src/java/server/play/select_trade.rs @@ -0,0 +1,11 @@ +use pumpkin_data::packet::serverbound::PLAY_SELECT_TRADE; +use pumpkin_macros::java_packet; +use serde::Deserialize; + +use crate::VarInt; + +#[derive(Deserialize)] +#[java_packet(PLAY_SELECT_TRADE)] +pub struct SSelectTrade { + pub selected_slot: VarInt, +} diff --git a/pumpkin-world/src/inventory/mod.rs b/pumpkin-world/src/inventory/mod.rs index f80cf305b..5b5186667 100644 --- a/pumpkin-world/src/inventory/mod.rs +++ b/pumpkin-world/src/inventory/mod.rs @@ -6,8 +6,10 @@ use pumpkin_data::item_stack::ItemStack; #[expect(clippy::module_inception)] mod inventory; +mod simple_inventory; pub use inventory::*; +pub use simple_inventory::*; // These are some utility functions found in Inventories.java pub async fn split_stack(stacks: &[Arc>], slot: usize, amount: u8) -> ItemStack { diff --git a/pumpkin-world/src/inventory/simple_inventory.rs b/pumpkin-world/src/inventory/simple_inventory.rs new file mode 100644 index 000000000..3292d0746 --- /dev/null +++ b/pumpkin-world/src/inventory/simple_inventory.rs @@ -0,0 +1,73 @@ +use crate::inventory::{Clearable, Inventory, InventoryFuture, split_stack}; +use pumpkin_data::item_stack::ItemStack; +use std::any::Any; +use std::sync::Arc; +use tokio::sync::Mutex; + +pub struct SimpleInventory { + pub stacks: Vec>>, +} + +impl SimpleInventory { + pub fn new(size: usize) -> Self { + Self { + stacks: (0..size) + .map(|_| Arc::new(Mutex::new(ItemStack::EMPTY.clone()))) + .collect(), + } + } +} + +impl Clearable for SimpleInventory { + fn clear(&self) -> InventoryFuture<'_, ()> { + Box::pin(async move { + for stack in &self.stacks { + *stack.lock().await = ItemStack::EMPTY.clone(); + } + }) + } +} + +impl Inventory for SimpleInventory { + fn size(&self) -> usize { + self.stacks.len() + } + + fn is_empty(&self) -> InventoryFuture<'_, bool> { + Box::pin(async move { + for stack in &self.stacks { + if !stack.lock().await.is_empty() { + return false; + } + } + true + }) + } + + fn get_stack(&self, slot: usize) -> InventoryFuture<'_, Arc>> { + Box::pin(async move { self.stacks[slot].clone() }) + } + + fn remove_stack(&self, slot: usize) -> InventoryFuture<'_, ItemStack> { + Box::pin(async move { + let mut stack = self.stacks[slot].lock().await; + let result = stack.clone(); + *stack = ItemStack::EMPTY.clone(); + result + }) + } + + fn remove_stack_specific(&self, slot: usize, amount: u8) -> InventoryFuture<'_, ItemStack> { + Box::pin(async move { split_stack(&self.stacks, slot, amount).await }) + } + + fn set_stack(&self, slot: usize, stack: ItemStack) -> InventoryFuture<'_, ()> { + Box::pin(async move { + *self.stacks[slot].lock().await = stack; + }) + } + + fn as_any(&self) -> &dyn Any { + self + } +} diff --git a/pumpkin/src/entity/passive/villager.rs b/pumpkin/src/entity/passive/villager.rs deleted file mode 100644 index a3e5836ce..000000000 --- a/pumpkin/src/entity/passive/villager.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::sync::{Arc, Weak}; - -use pumpkin_data::entity::EntityType; - -use crate::entity::{ - Entity, NBTStorage, - ai::goal::{ - look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, - wander_around::WanderAroundGoal, - }, - mob::{Mob, MobEntity}, -}; - -pub struct VillagerEntity { - pub mob_entity: MobEntity, -} - -impl VillagerEntity { - pub async fn new(entity: Entity) -> Arc { - let mob_entity = MobEntity::new(entity); - let villager = Self { mob_entity }; - let mob_arc = Arc::new(villager); - let mob_weak: Weak = { - let mob_arc: Arc = mob_arc.clone(); - Arc::downgrade(&mob_arc) - }; - - { - let mut goal_selector = mob_arc.mob_entity.goals_selector.lock().await; - - goal_selector.add_goal(0, Box::new(SwimGoal::default())); - // Villagers have complex AI, but for now we give them basic movement - goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(0.6))); - goal_selector.add_goal( - 2, - LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), - ); - goal_selector.add_goal( - 3, - LookAtEntityGoal::with_default(mob_weak, &EntityType::VILLAGER, 8.0), - ); - goal_selector.add_goal(4, Box::new(RandomLookAroundGoal::default())); - }; - - mob_arc - } -} - -impl NBTStorage for VillagerEntity {} - -impl Mob for VillagerEntity { - fn get_mob_entity(&self) -> &MobEntity { - &self.mob_entity - } -} diff --git a/pumpkin/src/entity/passive/villager/data.rs b/pumpkin/src/entity/passive/villager/data.rs new file mode 100644 index 000000000..957f6bc17 --- /dev/null +++ b/pumpkin/src/entity/passive/villager/data.rs @@ -0,0 +1,48 @@ +use pumpkin_data::item::Item; +pub use pumpkin_data::villager::{VillagerProfession, VillagerType}; +use pumpkin_protocol::codec::var_int::VarInt; +use serde::Serialize; + +pub const BREEDING_FOOD_THRESHOLD: i32 = 12; + +#[must_use] +pub const fn get_food_points(item: &Item) -> i32 { + match item.id { + id if id == Item::BREAD.id => 4, + id if id == Item::POTATO.id => 1, + id if id == Item::CARROT.id => 1, + id if id == Item::BEETROOT.id => 1, + _ => 0, + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] +#[repr(i32)] +pub enum GossipType { + MajorNegative = 0, + MinorNegative = 1, + MajorPositive = 2, + MinorPositive = 3, + Trading = 4, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct VillagerData { + pub r#type: VillagerType, + pub profession: VillagerProfession, + pub level: i32, +} + +impl Serialize for VillagerData { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut state = serializer.serialize_struct("VillagerData", 3)?; + state.serialize_field("type", &VarInt(self.r#type as i32))?; + state.serialize_field("profession", &VarInt(self.profession as i32))?; + state.serialize_field("level", &VarInt(self.level))?; + state.end() + } +} diff --git a/pumpkin/src/entity/passive/villager/mod.rs b/pumpkin/src/entity/passive/villager/mod.rs new file mode 100644 index 000000000..2f71d7eff --- /dev/null +++ b/pumpkin/src/entity/passive/villager/mod.rs @@ -0,0 +1,459 @@ +use std::collections::HashMap; +use std::sync::atomic::{AtomicI32, AtomicI64, Ordering}; +use std::sync::{Arc, Weak}; +use uuid::Uuid; + +use pumpkin_data::entity::EntityType; +use pumpkin_data::item_stack::ItemStack; +use pumpkin_data::meta_data_type::MetaDataType; +use pumpkin_data::tracked_data::TrackedData; +use pumpkin_inventory::merchant::merchant_screen_handler::MerchantScreenHandler; +use pumpkin_inventory::screen_handler::{ + BoxFuture, InventoryPlayer, ScreenHandlerFactory, SharedScreenHandler, +}; +use pumpkin_protocol::codec::var_int::VarInt; +use pumpkin_protocol::java::client::play::{CMerchantOffers, Metadata}; +use pumpkin_util::text::TextComponent; +use pumpkin_world::inventory::SimpleInventory; +use tokio::sync::Mutex; + +use crate::entity::player::Player; +use crate::entity::{ + Entity, EntityBase, NBTStorage, + ai::goal::{ + avoid_entity::AvoidEntityGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, swim::SwimGoal, wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub mod data; +pub use data::{ + BREEDING_FOOD_THRESHOLD, GossipType, VillagerData, VillagerProfession, VillagerType, + get_food_points, +}; + +pub struct VillagerEntity { + pub mob_entity: MobEntity, + pub villager_data: Mutex, + pub food_level: AtomicI32, + pub xp: AtomicI32, + pub last_restock_time: AtomicI64, + pub restocks_today: AtomicI32, + pub gossips: Mutex>>, + pub inventory: Arc>>>>, + pub merchant_inventory: Arc, + pub offers: Mutex>, + pub self_arc: Mutex>>, +} + +impl VillagerEntity { + #[expect(clippy::too_many_lines)] + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let villager_data = VillagerData { + r#type: VillagerType::Plains, + profession: VillagerProfession::None, + level: 1, + }; + let inventory = Arc::new(Mutex::new( + (0..8) + .map(|_| Arc::new(Mutex::new(ItemStack::EMPTY.clone()))) + .collect(), + )); + + let villager = Self { + mob_entity, + villager_data: Mutex::new(villager_data), + food_level: AtomicI32::new(0), + xp: AtomicI32::new(0), + last_restock_time: AtomicI64::new(0), + restocks_today: AtomicI32::new(0), + gossips: Mutex::new(HashMap::new()), + inventory, + merchant_inventory: Arc::new(SimpleInventory::new(3)), + offers: Mutex::new(Vec::new()), + self_arc: Mutex::new(None), + }; + let mob_arc = Arc::new(villager); + *mob_arc.self_arc.lock().await = Some(Arc::downgrade(&mob_arc)); + let mob_weak: Weak = { + let mob_arc: Arc = mob_arc.clone(); + Arc::downgrade(&mob_arc) + }; + + { + let mut goal_selector = mob_arc.mob_entity.goals_selector.lock().await; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + // Villagers avoid threats + goal_selector.add_goal( + 1, + Box::new(AvoidEntityGoal::new(&EntityType::ZOMBIE, 8.0, 0.5, 0.5)), + ); + goal_selector.add_goal( + 1, + Box::new(AvoidEntityGoal::new( + &EntityType::ZOMBIE_VILLAGER, + 8.0, + 0.5, + 0.5, + )), + ); + goal_selector.add_goal( + 1, + Box::new(AvoidEntityGoal::new(&EntityType::HUSK, 8.0, 0.5, 0.5)), + ); + goal_selector.add_goal( + 1, + Box::new(AvoidEntityGoal::new(&EntityType::DROWNED, 8.0, 0.5, 0.5)), + ); + goal_selector.add_goal( + 1, + Box::new(AvoidEntityGoal::new(&EntityType::PILLAGER, 12.0, 0.5, 0.5)), + ); + goal_selector.add_goal( + 1, + Box::new(AvoidEntityGoal::new( + &EntityType::VINDICATOR, + 12.0, + 0.5, + 0.5, + )), + ); + goal_selector.add_goal( + 1, + Box::new(AvoidEntityGoal::new(&EntityType::EVOKER, 12.0, 0.5, 0.5)), + ); + goal_selector.add_goal( + 1, + Box::new(AvoidEntityGoal::new(&EntityType::RAVAGER, 12.0, 0.5, 0.5)), + ); + goal_selector.add_goal( + 1, + Box::new(AvoidEntityGoal::new(&EntityType::VEX, 12.0, 0.5, 0.5)), + ); + + // Basic movement and looking (Vanilla uses 0.5 speed) + goal_selector.add_goal(2, Box::new(WanderAroundGoal::new(0.5))); + goal_selector.add_goal( + 3, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal( + 4, + LookAtEntityGoal::with_default(mob_weak, &EntityType::VILLAGER, 8.0), + ); + goal_selector.add_goal(5, Box::new(RandomLookAroundGoal::default())); + }; + + // Send initial metadata + mob_arc + .get_entity() + .send_meta_data(&[Metadata::new( + TrackedData::VILLAGER_DATA, + MetaDataType::VILLAGER_DATA, + villager_data, + )]) + .await; + + mob_arc + } + + pub async fn count_food_points_in_inventory(&self) -> i32 { + let inventory = self.inventory.lock().await; + let mut total = 0; + for stack_mutex in inventory.iter() { + let stack = stack_mutex.lock().await; + if !stack.is_empty() { + total += get_food_points(stack.get_item()) * stack.item_count as i32; + } + } + total + } + + pub async fn eat_until_full(&self) { + if self.food_level.load(Ordering::Relaxed) >= BREEDING_FOOD_THRESHOLD { + return; + } + let inventory = self.inventory.lock().await; + for stack_mutex in inventory.iter() { + let mut stack = stack_mutex.lock().await; + if !stack.is_empty() { + let points = get_food_points(stack.get_item()); + if points > 0 { + while stack.item_count > 0 + && self.food_level.load(Ordering::Relaxed) < BREEDING_FOOD_THRESHOLD + { + self.food_level.fetch_add(points, Ordering::Relaxed); + stack.item_count -= 1; + } + if stack.item_count == 0 { + *stack = ItemStack::EMPTY.clone(); + } + if self.food_level.load(Ordering::Relaxed) >= BREEDING_FOOD_THRESHOLD { + break; + } + } + } + } + } + + pub async fn set_villager_data(&self, data: VillagerData) { + let mut villager_data = self.villager_data.lock().await; + let old_profession = villager_data.profession; + *villager_data = data; + self.get_entity() + .send_meta_data(&[Metadata::new( + TrackedData::VILLAGER_DATA, + MetaDataType::VILLAGER_DATA, + data, + )]) + .await; + + if old_profession != data.profession { + self.generate_trades(data.profession, data.level).await; + if let Some(sound) = data.profession.work_sound() { + self.get_entity().play_sound(sound).await; + } + } + } + + pub async fn generate_trades(&self, profession: VillagerProfession, level: i32) { + use pumpkin_protocol::codec::item_stack_seralizer::ItemStackSerializer; + use rand::seq::IndexedRandom; + use std::borrow::Cow; + + let mut offers = self.offers.lock().await; + offers.clear(); + + if let Some(trade_set) = profession.trade_set(level) { + let mut rng = rand::rng(); + let chosen_trades = trade_set.trades.sample(&mut rng, trade_set.amount as usize); + + for trade in chosen_trades { + offers.push(pumpkin_protocol::java::client::play::MerchantOffer { + base_cost_a: ItemStackSerializer(Cow::Owned(ItemStack::new( + trade.wants.count as u8, + trade.wants.item, + ))), + output: ItemStackSerializer(Cow::Owned(ItemStack::new( + trade.gives.count as u8, + trade.gives.item, + ))), + cost_b: trade.wants_b.as_ref().map(|b| { + ItemStackSerializer(Cow::Owned(ItemStack::new(b.count as u8, b.item))) + }), + is_disabled: false, + uses: 0, + max_uses: trade.max_uses, + xp: trade.xp, + special_price: 0, + price_multiplier: trade.price_multiplier, + demand: 0, + }); + } + } + } + + pub async fn set_unhappy(&self) { + let entity = self.get_entity(); + entity + .world + .load() + .send_entity_status(entity, pumpkin_data::entity::EntityStatus::VillagerAngry) + .await; + entity + .play_sound(pumpkin_data::sound::Sound::EntityVillagerNo) + .await; + } + + pub async fn open_trading_screen(&self, player: &Player) { + let self_weak = self.self_arc.lock().await; + if let Some(self_arc) = self_weak.as_ref().and_then(std::sync::Weak::upgrade) { + player.open_handled_screen(&*self_arc, None).await; + + let offers = self.offers.lock().await; + let villager_data = self.villager_data.lock().await; + + player + .client + .enqueue_packet(&CMerchantOffers::new( + player.screen_handler_sync_id.load(Ordering::Relaxed).into(), + offers.clone(), + VarInt(villager_data.level), + VarInt(self.xp.load(Ordering::Relaxed)), + true, + true, + )) + .await; + } + } +} + +impl ScreenHandlerFactory for VillagerEntity { + fn create_screen_handler<'a>( + &'a self, + sync_id: u8, + player_inventory: &'a Arc, + _player: &'a dyn InventoryPlayer, + ) -> BoxFuture<'a, Option> { + Box::pin(async move { + let offers = self.offers.lock().await; + let handler = MerchantScreenHandler::new( + sync_id, + player_inventory, + self.merchant_inventory.clone(), + offers.clone(), + ) + .await; + Some(Arc::new(Mutex::new(handler)) as SharedScreenHandler) + }) + } + + fn get_display_name(&self) -> TextComponent { + // TODO: Localized name based on profession + TextComponent::text("Villager") + } +} + +impl NBTStorage for VillagerEntity { + fn write_nbt<'a>( + &'a self, + nbt: &'a mut pumpkin_nbt::pnbt::PNbtCompound, + ) -> crate::entity::NbtFuture<'a, ()> { + Box::pin(async move { + self.mob_entity.living_entity.write_nbt(nbt).await; + let data = self.villager_data.lock().await; + nbt.put_int(data.r#type as i32); + nbt.put_int(data.profession as i32); + nbt.put_int(data.level); + + nbt.put_int(self.food_level.load(Ordering::Relaxed)); + nbt.put_int(self.xp.load(Ordering::Relaxed)); + nbt.put_long(self.last_restock_time.load(Ordering::Relaxed)); + nbt.put_int(self.restocks_today.load(Ordering::Relaxed)); + + // Inventory + let inventory = self.inventory.lock().await; + nbt.put_int(inventory.len() as i32); + for stack_mutex in inventory.iter() { + let stack = stack_mutex.lock().await; + stack.write_item_stack_pnbt(nbt); + } + + // Gossips (Simplified: just save counts per UUID and type) + let gossips = self.gossips.lock().await; + nbt.put_int(gossips.len() as i32); + for (uuid, types) in gossips.iter() { + nbt.put_uuid(uuid); + nbt.put_int(types.len() as i32); + for (gtype, value) in types { + nbt.put_int(*gtype as i32); + nbt.put_int(*value); + } + } + }) + } + + fn read_nbt_non_mut<'a>( + &'a self, + nbt: &'a mut pumpkin_nbt::pnbt::PNbtCompound, + ) -> crate::entity::NbtFuture<'a, ()> { + Box::pin(async move { + self.mob_entity.living_entity.read_nbt_non_mut(nbt).await; + let mut data = self.villager_data.lock().await; + if let Ok(t) = nbt.get_int() { + data.r#type = VillagerType::try_from(t).unwrap_or(VillagerType::Plains); + } + if let Ok(p) = nbt.get_int() { + data.profession = + VillagerProfession::try_from(p).unwrap_or(VillagerProfession::None); + } + if let Ok(l) = nbt.get_int() { + data.level = l; + } + + if let Ok(food) = nbt.get_int() { + self.food_level.store(food, Ordering::Relaxed); + } + if let Ok(xp) = nbt.get_int() { + self.xp.store(xp, Ordering::Relaxed); + } + if let Ok(restock) = nbt.get_long() { + self.last_restock_time.store(restock, Ordering::Relaxed); + } + if let Ok(today) = nbt.get_int() { + self.restocks_today.store(today, Ordering::Relaxed); + } + + // Inventory + if let Ok(inv_len) = nbt.get_int() { + let mut inventory = self.inventory.lock().await; + inventory.clear(); + for _ in 0..inv_len { + let stack = + ItemStack::read_item_stack_pnbt(nbt).unwrap_or(ItemStack::EMPTY.clone()); + inventory.push(Arc::new(Mutex::new(stack))); + } + } + + // Gossips + if let Ok(gossip_len) = nbt.get_int() { + let mut gossips = self.gossips.lock().await; + gossips.clear(); + for _ in 0..gossip_len { + if let Ok(uuid) = nbt.get_uuid() + && let Ok(types_len) = nbt.get_int() + { + let mut types = HashMap::new(); + for _ in 0..types_len { + if let (Ok(gtype), Ok(val)) = (nbt.get_int(), nbt.get_int()) { + let gossip_type = match gtype { + 0 => GossipType::MajorNegative, + 1 => GossipType::MinorNegative, + 2 => GossipType::MajorPositive, + 3 => GossipType::MinorPositive, + 4 => GossipType::Trading, + _ => continue, + }; + types.insert(gossip_type, val); + } + } + gossips.insert(uuid, types); + } + } + } + }) + } +} + +impl Mob for VillagerEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } + + fn mob_interact<'a>( + &'a self, + player: &'a crate::entity::player::Player, + _item_stack: &'a mut pumpkin_data::item_stack::ItemStack, + ) -> crate::entity::EntityBaseFuture<'a, bool> { + Box::pin(async move { + if self.get_entity().age.load(Ordering::Relaxed) < 0 { + self.set_unhappy().await; + return true; + } + + let offers = self.offers.lock().await; + if offers.is_empty() { + self.set_unhappy().await; + return true; + } + drop(offers); + + self.open_trading_screen(player).await; + + true + }) + } +} diff --git a/pumpkin/src/net/java/mod.rs b/pumpkin/src/net/java/mod.rs index cbc8b1ae6..b8f0960d8 100644 --- a/pumpkin/src/net/java/mod.rs +++ b/pumpkin/src/net/java/mod.rs @@ -12,8 +12,8 @@ use pumpkin_protocol::java::server::play::{ SPaddleBoat, SPickItemFromBlock, SPlaceRecipe, SPlayPingRequest, SPlayerAbilities, SPlayerAction, SPlayerCommand, SPlayerInput, SPlayerLoaded, SPlayerPosition, SPlayerPositionRotation, SPlayerRotation, SPlayerSession, SRecipeBookChangeSettings, - SRecipeBookSeenRecipe, SSetCommandBlock, SSetCreativeSlot, SSetHeldItem, SSetPlayerGround, - SSwingArm, SUpdateSign, SUseItem, SUseItemOn, + SRecipeBookSeenRecipe, SSelectTrade, SSetCommandBlock, SSetCreativeSlot, SSetHeldItem, + SSetPlayerGround, SSwingArm, SUpdateSign, SUseItem, SUseItemOn, }; use pumpkin_protocol::packet::MultiVersionJavaPacket; use pumpkin_protocol::{ @@ -891,6 +891,10 @@ impl JavaClient { self.handle_place_recipe(player, SPlaceRecipe::read(payload, &version)?) .await; } + id if id == SSelectTrade::to_id(version) => { + self.handle_select_trade(player, SSelectTrade::read(payload, &version)?) + .await; + } _ => { warn!("Failed to handle player packet id {}", packet.id); } diff --git a/pumpkin/src/net/java/play.rs b/pumpkin/src/net/java/play.rs index da9b6ccc8..d7606d754 100644 --- a/pumpkin/src/net/java/play.rs +++ b/pumpkin/src/net/java/play.rs @@ -46,6 +46,7 @@ use pumpkin_data::item_stack::ItemStack; use pumpkin_data::sound::{Sound, SoundCategory}; use pumpkin_data::{Block, BlockDirection, BlockState, translation}; use pumpkin_inventory::InventoryError; +use pumpkin_inventory::merchant::merchant_screen_handler::MerchantScreenHandler; use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_inventory::screen_handler::{InventoryPlayer, ScreenHandler}; use pumpkin_macros::send_cancellable; @@ -62,8 +63,8 @@ use pumpkin_protocol::java::server::play::{ SKeepAlive, SMoveVehicle, SPaddleBoat, SPickItemFromBlock, SPlaceRecipe, SPlayPingRequest, SPlayerAbilities, SPlayerAction, SPlayerCommand, SPlayerInput, SPlayerPosition, SPlayerPositionRotation, SPlayerRotation, SPlayerSession, SRecipeBookChangeSettings, - SRecipeBookSeenRecipe, SSetCommandBlock, SSetCreativeSlot, SSetHeldItem, SSetPlayerGround, - SSwingArm, SUpdateSign, SUseItem, SUseItemOn, Status, + SRecipeBookSeenRecipe, SSelectTrade, SSetCommandBlock, SSetCreativeSlot, SSetHeldItem, + SSetPlayerGround, SSwingArm, SUpdateSign, SUseItem, SUseItemOn, Status, }; use pumpkin_util::math::boundingbox::BoundingBox; use pumpkin_util::math::vector3::Vector3; @@ -2765,4 +2766,17 @@ impl JavaClient { self.enqueue_packet(&COpenSignEditor::new(block_position, is_front_text)) .await; } + + pub async fn handle_select_trade(&self, player: &Arc, packet: SSelectTrade) { + let screen_handler = player.current_screen_handler.lock().await; + let mut screen_handler = screen_handler.lock().await; + if let Some(merchant) = screen_handler + .as_any_mut() + .downcast_mut::() + { + merchant + .set_selected_offer(packet.selected_slot.0 as usize) + .await; + } + } } diff --git a/pumpkin/src/plugin/api/gui.rs b/pumpkin/src/plugin/api/gui.rs index 5e9ad85ee..70eb02613 100644 --- a/pumpkin/src/plugin/api/gui.rs +++ b/pumpkin/src/plugin/api/gui.rs @@ -140,6 +140,10 @@ impl ScreenHandler for PluginScreenHandler { self } + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + fn get_behaviour(&self) -> &ScreenHandlerBehaviour { &self.behaviour }