CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PrismarineJS

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

GitHub Repository: PrismarineJS/mineflayer
Path: blob/master/test/externalTests/trade.js
Views: 789
1
const assert = require('assert')
2
const { once } = require('../../lib/promise_utils')
3
4
module.exports = () => async (bot) => {
5
function expectAmount (amount, greaterThan) {
6
// TODO: 1.20.5+ does not seem to respect "Count" NBT anymore in /summon
7
// ...as NBT was removed in favor of components that may have something to do
8
if (bot.registry.version['>=']('1.20.5')) {
9
if (amount < 1) throw new Error(`${amount} < 1`) // accept anything >=1
10
} else {
11
assert.strictEqual(amount, greaterThan)
12
}
13
}
14
15
const Item = require('prismarine-item')(bot.registry)
16
17
const villagerType = bot.registry.entitiesByName.villager ? 'villager' : 'Villager'
18
const testFluctuations = bot.supportFeature('selectingTradeMovesItems')
19
20
const summonCommand = bot.supportFeature('indexesVillagerRecipes')
21
? `/summon ${villagerType} ~ ~1 ~ {NoAI:1, Offers:{Recipes:[0:{maxUses:12,buy:{id:"minecraft:emerald",Count:2},sell:{id:"minecraft:pumpkin_pie",Count:2},uses: 1},1:{maxUses:12,buy:{id:"minecraft:emerald",Count:2},buyB:{id:"minecraft:pumpkin_pie",Count:2},sell:{id:"minecraft:wheat",Count:2}, uses:1},2:{maxUses:12,buy:{id:"minecraft:emerald",Count:1},sell:{id:"minecraft:glass",Count:4},uses: 1},3:{maxUses:12,buy:{id:"minecraft:emerald",Count:36},buyB:{id:"minecraft:book",Count:1},sell:{id:"minecraft:wooden_sword",Count:1},uses: 1}]}}`
22
: `/summon ${villagerType} ~ ~1 ~ {NoAI:1, Offers:{Recipes:[{maxUses:12,buy:{id:"minecraft:emerald",Count:2},sell:{id:"minecraft:pumpkin_pie",Count:2},${testFluctuations ? 'demand:60,priceMultiplier:0.05f,specialPrice:-4,' : ''}uses: 1},{maxUses:12,buy:{id:"minecraft:emerald",Count:2},buyB:{id:"minecraft:pumpkin_pie",Count:2},sell:{id:"minecraft:wheat",Count:2}, uses:1},{maxUses:12,buy:{id:"minecraft:emerald",Count:1},sell:{id:"minecraft:glass",Count:4},uses: 1},{maxUses:12,buy:{id:"minecraft:emerald",Count:36},buyB:{id:"minecraft:book",Count:1},sell:{id:"minecraft:wooden_sword",Count:1},uses: 1}]}}`
23
24
const commandBlockPos = bot.entity.position.offset(0.5, 0, 0.5)
25
const redstoneBlockPos = commandBlockPos.offset(1, 0, 0)
26
27
let shouldHaveEmeralds = 0
28
for (let slot = 9; slot <= 17; slot += 1) {
29
await bot.test.setInventorySlot(slot, new Item(bot.registry.itemsByName.emerald.id, 64, 0))
30
shouldHaveEmeralds += 64
31
}
32
await bot.test.setInventorySlot(18, new Item(bot.registry.itemsByName.book.id, 11, 0))
33
34
// A command block is needed to spawn the villager due to the chat's character limit in some versions
35
bot.test.sayEverywhere(`/setblock ${commandBlockPos.toArray().join(' ')} command_block`)
36
await bot.test.wait(500)
37
bot.setCommandBlock(commandBlockPos, summonCommand)
38
bot.test.sayEverywhere(`/setblock ${redstoneBlockPos.toArray().join(' ')} redstone_block`) // Activate the command block
39
40
const [entity] = await once(bot, 'entitySpawn')
41
assert(entity.name === villagerType)
42
43
const villager = await bot.openVillager(entity)
44
console.log('Opened villager')
45
console.dir(villager, { depth: null })
46
47
// Handle trade #1 -- takes 2x emerald and returns 2x pumpkin_pie
48
{
49
const trade = villager.trades[0]
50
assert.strictEqual(trade.inputs.length, 1, 'Expected single input from villager on first trade')
51
verifyTrade(trade)
52
53
const [input] = trade.inputs
54
assert.strictEqual(input.name, 'emerald')
55
expectAmount(input.count, 2)
56
57
const [output] = trade.outputs
58
assert.strictEqual(output.name, 'pumpkin_pie')
59
expectAmount(output.count, 2)
60
61
await bot.trade(villager, 0, 11)
62
shouldHaveEmeralds -= testFluctuations ? (2 * 2 * 11) : (2 * 11)
63
expectAmount(bot.currentWindow.count(bot.registry.itemsByName.emerald.id), shouldHaveEmeralds)
64
expectAmount(bot.currentWindow.count(bot.registry.itemsByName.pumpkin_pie.id), 22)
65
}
66
67
// Handle trade #2 -- takes [2x emerald, 2x pumpkin_pie] and returns 2x wheat
68
{
69
const trade = villager.trades[1]
70
assert.strictEqual(trade.inputs.length, 2, 'Expected two inputs from villager on second trade')
71
verifyTrade(trade)
72
73
const [input1, input2] = trade.inputs
74
assert.strictEqual(input1.name, 'emerald')
75
expectAmount(input1.count, 2)
76
assert.strictEqual(input2.name, 'pumpkin_pie')
77
expectAmount(input2.count, 2)
78
79
const [output] = trade.outputs
80
assert.strictEqual(output.name, 'wheat')
81
expectAmount(output.count, 2)
82
83
await bot.trade(villager, 1, 11)
84
shouldHaveEmeralds -= 11 * 2
85
expectAmount(bot.currentWindow.count(bot.registry.itemsByName.emerald.id), shouldHaveEmeralds)
86
assert.strictEqual(bot.currentWindow.count(bot.registry.itemsByName.pumpkin_pie.id), 0)
87
expectAmount(bot.currentWindow.count(bot.registry.itemsByName.wheat.id), 22)
88
}
89
90
// Handle trade #3 -- takes 1x emerald and returns 4x glass
91
{
92
const trade = villager.trades[2]
93
assert.strictEqual(trade.inputs.length, 1, 'Expected single input from villager on first trade')
94
verifyTrade(trade)
95
96
const [input] = trade.inputs
97
assert.strictEqual(input.name, 'emerald')
98
expectAmount(input.count, 1)
99
100
const [output] = trade.outputs
101
assert.strictEqual(output.name, 'glass')
102
expectAmount(output.count, 4)
103
104
await bot.trade(villager, 2, 11)
105
shouldHaveEmeralds -= 11
106
expectAmount(bot.currentWindow.count(bot.registry.itemsByName.emerald.id), shouldHaveEmeralds)
107
expectAmount(bot.currentWindow.count(bot.registry.itemsByName.glass.id), 44)
108
}
109
110
// Handle trade #4 -- takes [36x emerald, 1x book] and returns 1x wooden sword
111
{
112
const trade = villager.trades[3]
113
assert.strictEqual(trade.inputs.length, 2, 'Expected two inputs from villager on second trade')
114
verifyTrade(trade)
115
116
const [input1, input2] = trade.inputs
117
assert.strictEqual(input1.name, 'emerald')
118
expectAmount(input1.count, 36)
119
assert.strictEqual(input2.name, 'book')
120
assert.strictEqual(input2.count, 1)
121
122
const [output] = trade.outputs
123
assert.strictEqual(output.name, 'wooden_sword')
124
assert.strictEqual(output.count, 1)
125
126
await bot.trade(villager, 3, 11)
127
shouldHaveEmeralds -= 11 * 36
128
expectAmount(bot.currentWindow.count(bot.registry.itemsByName.emerald.id), shouldHaveEmeralds)
129
assert.strictEqual(bot.currentWindow.count(bot.registry.itemsByName.book.id), 0)
130
expectAmount(bot.currentWindow.count(bot.registry.itemsByName.wooden_sword.id), 11)
131
}
132
133
function verifyTrade (trade) {
134
assert.strictEqual(trade.nbTradeUses, 1)
135
assert.strictEqual(trade.maximumNbTradeUses, 12)
136
assert.strictEqual(trade.tradeDisabled, false)
137
138
const printCountInv = function (item) {
139
return `${bot.currentWindow.count(bot.registry.itemsByName[item.name].id)}x ${item.displayName}`
140
}
141
const printCountTrade = function (item) {
142
return `${item.count}x ${item.displayName}`
143
}
144
145
bot.test.sayEverywhere(`I have ${printCountInv(trade.inputItem1)} ${trade.hasItem2 ? 'and ' + printCountInv(trade.inputItem2) : ''}`)
146
bot.test.sayEverywhere(`I can trade ${printCountTrade(trade.inputItem1)} ${trade.hasItem2 ? 'and ' + printCountTrade(trade.inputItem2) : ''} for ${printCountTrade(trade.outputItem)}`)
147
}
148
149
assert.rejects(bot.trade(villager, 1, 1)) // Shouldn't be able, the trade is blocked!
150
villager.close()
151
bot.test.sayEverywhere(`/kill @e[type=${villagerType}]`)
152
}
153
154