← Назад к ресурсам

VillagersTradingPlus

Add, replace or delete the trades of any villager, change the currency, gate trades behind conditions and reprice them, all from a datapack.

Modrinth economy utility

Описание

VillagerTradingPlus allows you to fully customize villager trading for your world. Add, replace or delete the trades of any villager, change the currency, gate trades behind conditions and reprice them, all from a datapack. Versions: 1.20.1, 1.21.1, 1.21.8 Loader: Fabric, Neoforge, Forge Support my work on *** ## What this is VillagerTradingPlus is a **library**. On its own it adds no villagers, blocks or items: it replaces the machinery behind villager trading so that mods and datapacks can define trades in JSON. Install it if a mod asks for it, or if you want to rewrite villager trading in your own pack. [**VillagersPlus**](https://modrinth.com/mod/villagersplus) is the reference mod built on top of it. ## What you can do with it * **Add, delete or overwrite** trades for every villager profession, the vanilla ones included. * **Change the currency** from emeralds to any item you like. * Set the **amount, max usages, villager experience** and price behaviour of each trade. * **Gate trades behind conditions**: biome, dimension, weather, time of day, moon phase, gamerule, job site block or a config flag. * Fourteen **trade types**, from a plain item sale to weighted pools, structure maps and enchanted books drawn from a weighted list you define. * **Merge multiple datapacks** that modify the same villager, instead of letting the last one win. * Customize the **wandering trader** the same way, with its own common and rare tiers. *** ## Configuration `config/villagertradingplus/villagertradingplus-1.0-config.json5` These apply to every trade the library builds, no matter which mod or datapack defined it. ### Trades | Option | Default | What it does | | --- | --- | --- | | `trade_offers_per_level` | 2 | Max new trades a villager gains per level. | | `trade_offers_wandering_trader` | 5 | Max trades the wandering trader offers. | | `trade_price_multiplier_scale` | 1.0 | Scales how strongly prices swing from demand and reputation. `0.0` freezes both. Does **not** change a trade's starting price. | | `trade_cost_scale` | 1.0 | Multiplies the base cost of every trade (first input slot only). `2.0` doubles all prices. Result is clamped to 1 .. one stack. | | `enable_conditional_trades` | true | Whether condition-gated trades are actually checked. `false` makes every trade always appear. | | `enable_time_of_day_pricing` | false | Randomly nudges a trade's cost based on the in-game time it is unlocked. The price is locked in at unlock and does not keep changing. | | `time_of_day_price_variance` | 0.15 | How far that nudge can go, as a fraction of the cost. Only used when the option above is on. | ### Trading screen controls All three are **off by default**. When on, **any** player can use them, so they are meant for creative building and testing rather than survival servers. | Option | Default | What it does | | --- | --- | --- | | `allow_trade_reroll` | false | Buttons to re-roll a villager's or wandering trader's trades, all at once or one level at a time. | | `allow_set_villager_level` | false | A control to set a villager's level (1-5) and regenerate its trades. Wandering traders have no levels and ignore it. | | `allow_view_all_trades` | false | A button that opens a read-only catalog panel listing every trade a villager could roll at a chosen level, with weights, chances and conditions. | *** ## Making a datapack Trade files go into a datapack under **your own namespace**. Three folders are read: | Folder | What it does | | --- | --- | | `data//default_villager_trades/.json` | Replaces a profession's trades outright. | | `data//villager_trades/.json` | Adds to a profession's trades. | | `data//wandering_trader_trades/.json` | Wandering trader trades. | A profession file names the profession and holds five tier arrays: ```json { "profession": "minecraft:butcher", "trades": { "novice": [], "apprentice": [], "journeyman": [], "expert": [], "master": [] } } ``` Every snippet below is a single trade object that goes inside one of those five arrays. _Notice: the vanilla trades aren't in JSON form yet, so replacing those means writing out the tiers you want to keep._ *** ## Fields every trade type accepts These are left out of the examples below to keep them short: | Field | Meaning | | --- | --- | | `max_uses` | How often the trade can be used before it locks. | | `villager_experience` | Experience the villager gains per use. | | `price_multiplier` | How strongly reputation and Hero of the Village move this trade's price. | | `demand` | Seeds vanilla's demand pricing: the cost climbs with use and decays over time. | | `conditions` / `logic` | See **Conditions** further down. | Trade types are namespaced `villagertradingplus:`. The old `villagersplus:` namespace is still accepted for datapacks written before the split, but it logs a deprecation warning on load, so write new files against the new one. *** ## Trade types ### sell_item The villager sells an item for a price. ```json { "type": "villagertradingplus:sell_item", "sell": { "item": "minecraft:oxeye_daisy", "count": 1 }, "priceIn": { "item": "minecraft:emerald", "count": 2 } } ``` ### buy_item The villager buys an item and pays you. ```json { "type": "villagertradingplus:buy_item", "buy": { "item": "minecraft:wheat_seeds", "count": 4 }, "reward": { "item": "minecraft:emerald", "count": 1 } } ``` ### sell_tagged_item Sells **one random member** of an item tag. The member is chosen when the offer is generated, so two villagers with this trade will usually sell different things. Vanilla trades match a concrete item, so this is not an "any of" match at the counter. ```json { "type": "villagertradingplus:sell_tagged_item", "sell": { "tag": "minecraft:saplings", "count": 1 }, "priceIn": { "item": "minecraft:emerald", "count": 3 } } ``` ### buy_tagged_item The same idea for buying. ```json { "type": "villagertradingplus:buy_tagged_item", "buy": { "tag": "minecraft:flowers", "count": 8 }, "reward": { "item": "minecraft:emerald", "count": 1 } } ``` ### process_item Takes `convertible` plus `priceIn` and returns `sell`, the classic "bring me raw material" trade. ```json { "type": "villagertradingplus:process_item", "convertible": { "item": "minecraft:dead_tube_coral", "count": 1 }, "priceIn": { "item": "minecraft:emerald", "count": 5 }, "sell": { "item": "minecraft:tube_coral", "count": 1 } } ``` ### multi_input Two inputs, one output. Vanilla has exactly two buy slots, so one of the two inputs **is** the currency. ```json { "type": "villagertradingplus:multi_input", "input_a": { "item": "minecraft:emerald", "count": 5 }, "input_b": { "item": "minecraft:book", "count": 1 }, "sell": { "item": "minecraft:enchanted_book", "enchantments": [ { "id": "minecraft:mending", "lvl": 1 } ] } } ``` ### weighted_pool Picks one of several trades by weight when the offer is generated. Below, the daisy is ten times as likely as the wither rose. ```json { "type": "villagertradingplus:weighted_pool", "pool": [ { "weight": 10, "trade": { "type": "villagertradingplus:sell_item", "sell": { "item": "minecraft:oxeye_daisy", "count": 1 }, "priceIn": { "item": "minecraft:emerald", "count": 1 } } }, { "weight": 1, "trade": { "type": "villagertradingplus:sell_item", "sell": { "item": "minecraft:wither_rose", "count": 1 }, "priceIn": { "item": "minecraft:emerald", "count": 8 } } } ] } ``` ### sell_potion Takes `convertible` plus `priceIn` and returns `sell`, for potion-shaped trades. ```json { "type": "villagertradingplus:sell_potion", "convertible": { "item": "minecraft:potion", "count": 3 }, "priceIn": { "item": "minecraft:emerald", "count": 5 }, "sell": { "item": "minecraft:splash_potion", "count": 7 } } ``` ### sell_map Sells a filled map pointing at a structure. `structure_id` is a structure tag. ```json { "type": "villagertradingplus:sell_map", "structure_id": "minecraft:on_woodland_explorer_maps", "name": "filled_map", "buy": { "item": "minecraft:compass", "count": 1 }, "priceIn": { "item": "minecraft:emerald", "count": 2 }, "price_multiplier": 0.2 } ``` ### sell_enchanted_tool Sells a tool with a **random** enchantment, vanilla-style. The price scales with what was rolled. ```json { "type": "villagertradingplus:sell_enchanted_tool", "sell": { "item": "minecraft:diamond_pickaxe", "count": 1 }, "basePriceIn": { "item": "minecraft:emerald", "count": 2 } } ``` ### sell_specific_enchanted_tool Sells a tool with a **fixed** enchantment at a fixed level, a guaranteed result rather than a roll. `enchantment` defaults to `minecraft:fortune`, `level` to 1. ```json { "type": "villagertradingplus:sell_specific_enchanted_tool", "sell": { "item": "minecraft:diamond_pickaxe", "count": 1 }, "basePriceIn": { "item": "minecraft:emerald", "count": 32 }, "enchantment": "minecraft:efficiency", "level": 4 } ``` ### sell_enchanted_book Sells a randomly enchanted book, vanilla-style. ```json { "type": "villagertradingplus:sell_enchanted_book", "currency": { "item": "minecraft:emerald" }, "price_multiplier": 0.2 } ``` ### sell_specific_enchanted_book Sells a book with a **fixed** enchantment and level. There is no `sell` field, the item is always a book. `enchantment` defaults to `minecraft:unbreaking`, `level` to 1. ```json { "type": "villagertradingplus:sell_specific_enchanted_book", "basePriceIn": { "item": "minecraft:emerald", "count": 20 }, "enchantment": "minecraft:mending", "level": 1 } ``` ### sell_enchanted_book_from_list Sells an enchanted book drawn from a **weighted list** you define, so you control exactly which enchantments a librarian can offer. Cost is `base_cost + cost_per_level * level`, multiplied by `treasure_multiplier` for treasure enchantments. ```json { "type": "villagertradingplus:sell_enchanted_book_from_list", "currency": { "item": "minecraft:emerald" }, "enchantments": [ { "id": "minecraft:sharpness", "min_level": 1, "max_level": 3, "weight": 5 }, { "id": "minecraft:unbreaking", "min_level": 1, "max_level": 3, "weight": 5 }, { "id": "minecraft:mending", "min_level": 1, "max_level": 1, "weight": 1 } ], "base_cost": 2, "cost_per_level": 3, "treasure_multiplier": 2, "price_multiplier": 0.2 } ``` *** ## Conditions Add a `conditions` array to **any** trade to gate it. The default logic is AND; set `"logic": "or"` on the trade to require only one of them. **Timing matters.** Conditions are evaluated once, at the moment the offer is generated as the villager levels up, not continuously. Location conditions (`biome`, `dimension`, `job_site_block`, `config_flag`) are stable for a settled villager and therefore reliable. World-state conditions (`weather`, `day_night`, `moon_phase`, `gamerule`) are a snapshot of that moment: a trade gated on `night` stays available in broad daylight once it has been rolled. Conditions can be switched off globally with `enable_conditional_trades`. | Type | Fields | Example | | --- | --- | --- | | `biome` | `tag` (string) **or** `biomes` (array) | `{ "type": "biome", "tag": "minecraft:is_ocean" }` | | `dimension` | `dimension` | `{ "type": "dimension", "dimension": "minecraft:overworld" }` | | `weather` | `state`: `clear`, `rain`, `thunder` | `{ "type": "weather", "state": "rain" }` | | `day_night` | `time`: `day` or `night` | `{ "type": "day_night", "time": "night" }` | | `moon_phase` | `phases` (array of 0-7) | `{ "type": "moon_phase", "phases": [0] }` | | `config_flag` | `field` (a boolean config field name), optional `value` | `{ "type": "config_flag", "field": "can_explode" }` | | `gamerule` | `rule` (a boolean gamerule), optional `value` | `{ "type": "gamerule", "rule": "doInsomnia", "value": true }` | | `job_site_block` | `blocks` (array) **or** `wood_variant` (string matched against the block id) | `{ "type": "job_site_block", "blocks": [ "villagersplus:oceanographer_table" ] }` | Note that `biomes`, `blocks` and `phases` take **arrays**, while `tag`, `dimension` and `wood_variant` take a single string. ```json { "type": "villagertradingplus:sell_item", "sell": { "item": "minecraft:heart_of_the_sea", "count": 1 }, "priceIn": { "item": "minecraft:emerald", "count": 30 }, "logic": "or", "conditions": [ { "type": "biome", "tag": "minecraft:is_ocean" }, { "type": "day_night", "time": "night" } ] } ``` *** ## Pricing `price_multiplier` and `demand` work on any trade and feed vanilla's own price machinery: * `price_multiplier` - how strongly reputation and Hero of the Village move this trade's price. * `demand` - seeds vanilla's demand tracking. The cost climbs as the trade is used and decays again over time. Both are scaled server-wide by `trade_price_multiplier_scale` (swing size) and `trade_cost_scale` (base cost). Reputation and Hero of the Village discounts are applied by vanilla on top. ```json { "type": "villagertradingplus:sell_item", "sell": { "item": "minecraft:diamond", "count": 1 }, "priceIn": { "item": "minecraft:emerald", "count": 12 }, "price_multiplier": 0.1, "demand": 10 } ``` *** ## Custom items Any item stack in any trade type accepts this sugar, no special trade type needed: | Field | Meaning | | --- | --- | | `name` | Display name. Plain string or a raw JSON text component. | | `lore` | Array of lore lines. | | `enchantments` | Array of `{ "id": ..., "lvl": ... }`. | | `color` | Hex colour for dyeable armour. | | `potion` | Potion id for potion items. | | `skull_owner` | Player name for player heads. | | `book` | `{ "title": ..., "author": ..., "pages": [...] }` for written books. | | `nbt` | Raw SNBT, applied **last** as an escape hatch. | ```json { "type": "villagertradingplus:sell_item", "sell": { "item": "minecraft:diamond_sword", "name": "{\"text\":\"Excalibur\",\"color\":\"gold\",\"italic\":false}", "lore": [ "A blade of legend" ], "enchantments": [ { "id": "minecraft:sharpness", "lvl": 5 } ], "nbt": "{Unbreakable:1b}" }, "priceIn": { "item": "minecraft:emerald", "count": 40 } } ``` *** ## Wandering trader trades Create a datapack with this directory structure: ``` data//wandering_trader_trades ``` Any file name works. Instead of the five villager tiers, the wandering trader has two: * `common` - level 1. Several are picked, the count is set by `trade_offers_wandering_trader`. * `rare` - level 2. Exactly one is picked. Set `"replace": true` to drop the vanilla wandering-trader trades and use **only** yours. Omit it (or set `false`) to add on top of vanilla. Every trade type, the conditions block and pricing all work here exactly as they do on villagers. ```json { "replace": false, "trades": { "common": [ { "type": "villagertradingplus:sell_item", "sell": { "item": "minecraft:glowstone_dust", "count": 4 }, "priceIn": { "item": "minecraft:emerald", "count": 2 }, "conditions": [ { "type": "day_night", "time": "night" } ], "max_uses": 6, "villager_experience": 1 } ], "rare": [ { "type": "villagertradingplus:sell_item", "sell": { "item": "minecraft:trident", "name": "{\"text\":\"Traveler's Trident\",\"color\":\"aqua\",\"italic\":false}", "enchantments": [ { "id": "minecraft:loyalty", "lvl": 3 } ], "nbt": "{Unbreakable:1b}" }, "priceIn": { "item": "minecraft:emerald", "count": 30 }, "max_uses": 2, "villager_experience": 1 } ] } } ``` *** ## Ready-made example files Inside the jar under `data/villagertradingplus/available_trade_examples` you will find complete, copyable files for the cases a snippet cannot show well: * `full_profession.json` - one profession across all five tiers, mixing many trade types. * `conditions_and_pricing.json` - conditions and pricing on realistic trades. * `wandering_trader.json` - a complete wandering trader file.