.
Example trades from a librarian specialized in max-level, armor and water-related enchantments.
A revisitation of the Villager trading mechanics that aims to get rid of those big trading halls filled with villagers with mostly useless trades, instead allowing you to get everything you need from a smaller number of villagers, which can become specialized in the long term through deliberate trading. To achieve this, the mod makes these two changes:
Additionally, this mod allows you to add or replace villager trades through datapacks. In multiplayer, the mod is only required on the server.
Note about mods that add their own trades: The default configuration is automatically generated with all the modded trades that would be present without this mod installed, and the generator does its best to make meaningful associations between the trades, based on tool materials, enchantment names, etc.. If you want to tweak those trades, you can create a datapack with the current configuration using the "/dynamicvillagertrades export" command. Some modded trades cannot be encoded in the datapack (e.g. random map from Supplementaries) and cause the export for that profession to fail, but those trades are still added at runtime if the profession is not being replaced by a datapack altogether; in such cases, additional trades can be configured with a datapack that doesn't replace the faulty profession (see below).
Note about mods that replace vanilla trades: These will never be compatible with DVT. This includes other mods that allow trade configuration via JSON, DVT has its own system for this and that's what you should use.
Note about NeoForge 1.21+: You can use Sinytra Connector to make the Fabric version work with it.
Datapack format
You can refer to the generated vanilla datapack for some examples of configured trades. Each JSON file expands or replaces (if replace is true) the trades of a particular profession, which are specified in the offers dictionary. Each entry in the dictionary represents a group of trades and specifies the min_trades and max_trades that can be selected from the group, and, optionally, the affinity of the group (more on this later) and the randomness within the group (lower values indicate that the villager will quickly settle on specific trades). If replace is false, the trades will be added to the preexisting group with the same name, otherwise the group is replaced altogether. Although the name of the group (the key) is arbitrary, it does affect the order in which the trades appear in the GUI, which is why the names of the groups in the default datapack begin with a number (otherwise the order would be alphabetical). Each entry in the trade list specifies the minimum level at which the trade can be selected (e.g. apprentice), the type of offer (documented in the SJVT wiki* for 1.18-1.20, refer to the new example datapack for 1.21+), the increment of the attributes that the trades applies to the villager when it's used and, optionally, the affinity. The attributes of a villager represent the memory of the past interactions with the players and function as a sort of sub-profession that gives more weight to some trades compared to others. Each attribute consists of an arbitrary name (e.g. "luck") and a numeric value that is initially set to 0 and is adjusted each time a trade with that attribute is used (e.g. when purchasing a Looting or Fortune book), based on the "attributes" increments specified in the trade (note that each villager possesses all the attributes mentioned in your configuration, so you don't need to "declare" them, it's always valid to increase an attribute with any name). On the other hand, the trade's affinity to each attribute determines how the value of the attribute of the villager affects the likelihood of selecting that trade. If the affinities are not explicitly defined, they're automatically calculated from the attribute increments (higher increments result in higher affinities). If you want a trade to increase an attribute without having affinity with it, or vice versa, you can specify both the attributes and the affinities of the trade. As mentioned earlier, the affinity dictionary can also appear in a group of trades instead of a trade. This makes it so that the trades between different groups don't directly compete against each other, as the mod will first select a group based on the affinity and then choose a trade inside of the group. This is useful if the number of trades in each group is highly unbalanced, as it prevents larger groups from being selected more frequently solely because of their size. It only makes sense if max_trades > min_trades.
Note that if a configuration is missing for a specific profession (for instance, a modded one), the mod will automatically generate one at run-time. The trades in this configuration will closely resemble the vanilla ones, but the offers that are not guaranteed to be present in vanilla will each have their own unique attribute and will belong to a group with the trades of the same level (basically, the villager specializes in specific trades, but only those for which the villager would normally have to make a choice in vanilla, and trades between different levels don't compete against each other).
* This mod adds two more offer types, enchant_specific_book and sell_specific_potion_holding_item.
Notes on adding enchanted book trades to the librarian profession
The default librarian configuration is generated at runtime and uses four identical groups for enchanted book trades, with the only difference being the experience given, so that the trades resemble the vanilla ones as much as possible. This means that, unless you want to replace the librarian profession altogether, you should add each new trade to all four groups. As for the attributes, you're recommended to use the preexisting ones (offense, defense, bow, etc.) to keep the trade weights balanced. When choosing the attributes, keep in mind that:
Options
global_randomness (default 1.0): Lower values cause the villagers to quickly settle on a subset of its trades, higher values increase the time required to get the desired trades. This is multiplied by the group randomness specified in the datapack.
refresh_delay (default 0): How many times the villager has to restock before its trades are changed. Note that they're always changed when it levels up regardless of this value.
no_book_duplicates (default true): Whether each librarian should not sell books with the same enchantment at the same time (e.g. Protection III and Protection IV).
enchant_repair_compat (default false): Adds the Curse of Vanishing to every book sold by librarians (for compatibility with Enchant & Repair).
Credits
The source code of this mod is based on SimpleJsonVillagerTrades