Villager demand values decrease indefinitely over time, some reaching minus 3 million in my Realms world. This makes it pretty much impossible to ever reach positive values again (except by underflow). New villagers or new trades start with zero or low values like -24, but over time they go into negative thousands, hundred thousands and so on. Villagers from 1.13.2 which haven't been traded with in 1.14.x or have not restocked, have a demand value of 0.
Also, according to MerchantOffer.java, the following code (MCP mappings) doesn't seem to have an underflow protection, so I expect very high positive values after reaching minus 2 billion and some, potentially leading to very high prices (clamped to max. stack size):
this.demand = this.demand + this.uses - (this.maxUses - this.uses);
Relates to MC-156574 which has been marked as fixed.
Example for an 1.13.2 butcher that has been traded with in 1.14.x:
{Brain: {memories: {"minecraft:home": {pos: [I; -192, 69, -155], dimension: "minecraft:overworld"}, "minecraft:last_slept": 59095829L, "minecraft:last_worked_at_poi": 58818687L}}, HurtByTimestamp: 0, Attributes: [{Base: 20.0d, Name: "generic.maxHealth"}, {Base: 0.0d, Name: "generic.knockbackResistance"}, {Base: 0.5d, Name: "generic.movementSpeed"}, {Base: 0.0d, Name: "generic.armor"}, {Base: 0.0d, Name: "generic.armorToughness"}, {Base: 16.0d, Modifiers: [{UUIDMost: -1878018487258559006L, UUIDLeast: -9174853231443965336L, Amount: 0.07413098408231238d, Operation: 1, Name: "Random spawn bonus"}], Name: "generic.followRange"}, {Base: 0.0d, Name: "generic.attackKnockback"}], FoodLevel: 0b, Invulnerable: 0b, FallFlying: 0b, ForcedAge: 0, Gossips: [], PortalCooldown: 0, AbsorptionAmount: 0.0f, LastRestock: 2906L, FallDistance: 0.0f, DeathTime: 0s, Xp: 18, LastGossipDecay: 59084674L, HandDropChances: [0.085f, 0.085f], PersistenceRequired: 0b, Age: 0, Motion: [0.0d, -0.0784000015258789d, 0.0d], UUIDLeast: -6538277718517827106L, Health: 20.0f, LeftHanded: 0b, Air: 300s, OnGround: 1b, Dimension: 0, Offers: {Recipes: [{maxUses: 14, buyB: {id: "minecraft:air", Count: 0b}, buy: {id: "minecraft:porkchop", Count: 15b}, sell: {id: "minecraft:emerald", Count: 1b}, xp: 1, uses: 0, priceMultiplier: 0.0f, specialPrice: 0, demand: -502220, rewardExp: 1b}, {maxUses: 25, buyB: {id: "minecraft:air", Count: 0b}, buy: {id: "minecraft:chicken", Count: 15b}, sell: {id: "minecraft:emerald", Count: 1b}, xp: 1, uses: 0, priceMultiplier: 0.0f, specialPrice: 0, demand: -896806, rewardExp: 1b}, {maxUses: 7, buyB: {id: "minecraft:air", Count: 0b}, buy: {id: "minecraft:coal", Count: 21b}, sell: {id: "minecraft:emerald", Count: 1b}, xp: 1, uses: 0, priceMultiplier: 0.0f, specialPrice: 0, demand: -251106, rewardExp: 1b}, {maxUses: 7, buyB: {id: "minecraft:air", Count: 0b}, buy: {id: "minecraft:emerald", Count: 1b}, sell: {id: "minecraft:cooked_porkchop", Count: 6b}, xp: 1, uses: 0, priceMultiplier: 0.0f, specialPrice: 0, demand: -251114, rewardExp: 1b}, {maxUses: 7, buyB: {id: "minecraft:air", Count: 0b}, buy: {id: "minecraft:emerald", Count: 1b}, sell: {id: "minecraft:cooked_chicken", Count: 6b}, xp: 1, uses: 0, priceMultiplier: 0.0f, specialPrice: 0, demand: -251116, rewardExp: 1b}]}, Rotation: [179.12813f, 0.0f], HandItems: [{}, {}], RestocksToday: 0, ArmorDropChances: [0.085f, 0.085f, 0.085f, 0.085f], UUIDMost: -4706437458691471725L, Pos: [-196.49274613473273d, 72.0d, -165.24950263469773d], Fire: -1s, ArmorItems: [{}, {}, {}, {}], CanPickUpLoot: 1b, VillagerData: {profession: "minecraft:butcher", level: 9, type: "minecraft:plains"}, HurtTime: 0s, Inventory: [{id: "minecraft:wheat_seeds", Count: 24b}, {id: "minecraft:wheat", Count: 24b}, {id: "minecraft:carrot", Count: 6b}, {id: "minecraft:wheat", Count: 21b}]}
Example for an 1.14.x toolsmith:
{Brain: {memories: {"minecraft:meeting_point": {pos: [I; -205, 72, -144], dimension: "minecraft:overworld"}, "minecraft:home": {pos: [I; -213, 71, -161], dimension: "minecraft:overworld"}, "minecraft:last_slept": 59095924L, "minecraft:last_worked_at_poi": 59092641L, "minecraft:job_site": {pos: [I; -196, 68, -144], dimension: "minecraft:overworld"}}}, HurtByTimestamp: 0, Attributes: [{Base: 20.0d, Name: "generic.maxHealth"}, {Base: 0.0d, Name: "generic.knockbackResistance"}, {Base: 0.5d, Name: "generic.movementSpeed"}, {Base: 0.0d, Name: "generic.armor"}, {Base: 0.0d, Name: "generic.armorToughness"}, {Base: 48.0d, Modifiers: [{UUIDMost: -73376431933667821L, UUIDLeast: -6176652968726733404L, Amount: 0.033869891415886366d, Operation: 1, Name: "Random spawn bonus"}], Name: "generic.followRange"}, {Base: 0.0d, Name: "generic.attackKnockback"}], FoodLevel: 0b, Invulnerable: 0b, FallFlying: 0b, ForcedAge: 0, Gossips: [], PortalCooldown: 0, AbsorptionAmount: 0.0f, LastRestock: 0L, FallDistance: 0.0f, DeathTime: 0s, Xp: 154, LastGossipDecay: 59084674L, HandDropChances: [0.085f, 0.085f], PersistenceRequired: 0b, Age: 0, Motion: [1.5069371136687602E-4d, -0.0784000015258789d, 0.07366114333699925d], UUIDLeast: -6511835637120788481L, Health: 20.0f, LeftHanded: 1b, Air: 300s, OnGround: 1b, Dimension: 0, Offers: {Recipes: [{maxUses: 16, buyB: {id: "minecraft:air", Count: 1b}, buy: {id: "minecraft:coal", Count: 15b}, sell: {id: "minecraft:emerald", Count: 1b}, xp: 2, uses: 0, priceMultiplier: 0.05f, specialPrice: 0, demand: -860128, rewardExp: 1b}, {maxUses: 12, buyB: {id: "minecraft:air", Count: 1b}, buy: {id: "minecraft:emerald", Count: 1b}, sell: {id: "minecraft:stone_hoe", Count: 1b, tag: {Damage: 0}}, xp: 1, uses: 0, priceMultiplier: 0.2f, specialPrice: 0, demand: -645096, rewardExp: 1b}, {maxUses: 12, buyB: {id: "minecraft:air", Count: 1b}, buy: {id: "minecraft:iron_ingot", Count: 4b}, sell: {id: "minecraft:emerald", Count: 1b}, xp: 10, uses: 0, priceMultiplier: 0.05f, specialPrice: 0, demand: -209664, rewardExp: 1b}, {maxUses: 12, buyB: {id: "minecraft:air", Count: 1b}, buy: {id: "minecraft:emerald", Count: 36b}, sell: {id: "minecraft:bell", Count: 1b}, xp: 5, uses: 0, priceMultiplier: 0.2f, specialPrice: 0, demand: -209664, rewardExp: 1b}, {maxUses: 3, buyB: {id: "minecraft:air", Count: 1b}, buy: {id: "minecraft:emerald", Count: 13b}, sell: {id: "minecraft:iron_axe", Count: 1b, tag: {Enchantments: [{lvl: 1s, id: "minecraft:fortune"}, {lvl: 2s, id: "minecraft:efficiency"}], Damage: 0}}, xp: 10, uses: 0, priceMultiplier: 0.2f, specialPrice: 0, demand: -20880, rewardExp: 1b}, {maxUses: 3, buyB: {id: "minecraft:air", Count: 1b}, buy: {id: "minecraft:emerald", Count: 19b}, sell: {id: "minecraft:iron_pickaxe", Count: 1b, tag: {Enchantments: [{lvl: 1s, id: "minecraft:fortune"}, {lvl: 2s, id: "minecraft:efficiency"}, {lvl: 2s, id: "minecraft:unbreaking"}], Damage: 0}}, xp: 10, uses: 0, priceMultiplier: 0.2f, specialPrice: 0, demand: -20880, rewardExp: 1b}]}, Rotation: [359.74698f, 0.0f], HandItems: [{}, {}], RestocksToday: 0, ArmorDropChances: [0.085f, 0.085f, 0.085f, 0.085f], UUIDMost: 5094727900297841637L, Pos: [-205.50368003352455d, 69.0d, -142.2608681928114d], Fire: -1s, ArmorItems: [{}, {}, {}, {}], CanPickUpLoot: 1b, VillagerData: {profession: "minecraft:toolsmith", level: 3, type: "minecraft:plains"}, HurtTime: 0s, Inventory: [{id: "minecraft:wheat", Count: 64b}, {id: "minecraft:wheat_seeds", Count: 24b}, {id: "minecraft:potato", Count: 4b}, {id: "minecraft:wheat", Count: 1b}]}
Linked issues
is duplicated by 1
relates to 1
Comments 6
This patch would clamp it to zero, but negative values are possible - they just shouldn't go that much into the negative...
Well. That'll just have to be a decision that Mojang decides on.
In regards to how negative they want demand to go. It is my opinion that it shouldn't go negative at all. The demand appears to be updated quite frequently, and the current formula makes it unlikely to stay positive for more than one in-game day.
(Negative values do nothing).
I agree that it is for Mojang to decide and to find a correct fix.
Negative demand does something: it increases the necessary amount of trading before reaching positive demand again, so it does make sense to have it - but surely not below a certain level.
MC-193452 may be a duplicate of this issue. See comments in MC-193452 for a demonstration of some quite absurd demand values that are near the 32-bit integer limit and still decreasing, for a villager that has lived in spawn chunks for seven years.
MC-148949 may be a related issue.
Affects 1.16.3.
It appears that demand decreases for all items, even items that are not traded, and demand doesn't seem to increase.
Can confirm in 1.21 Release Candidate 1 by using /tick sprint to easily refresh villager trades. The more you do trade with the villagers, the lower the value gets.
Here is a command to easily view the demand
value of a villager trade, as the text output in chat for getting the entity data is very long:
/data get entity UUID Offers.Recipes[0]
I have wrote a patch for a suggested simple change to fix the issue.
This patch is built on Spigot mappings. Hope it is helpful.
https://github.com/PaperMC/Paper/commit/8a97c1634be5451e996b3045597d1dee35fb4d32