Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion src/agent/library/skills.js
Original file line number Diff line number Diff line change
Expand Up @@ -846,12 +846,27 @@ export async function discard(bot, itemName, num=-1) {
* await skills.discard(bot, "oak_log");
**/
let discarded = 0;
// Helper: find an item by name anywhere in the inventory slots (including off-hand)
function findItemByName(name) {
// prefer the inventory.items() convenience list
let it = bot.inventory.items().find(i => i.name === name);
if (it) return it;
// fallback: scan all slots (this will include off-hand and armor slots)
const slots = bot.inventory.slots || {};
for (const key of Object.keys(slots)) {
const slot = slots[key];
if (slot && slot.name === name) return slot;
}
return null;
}

while (true) {
let item = bot.inventory.items().find(item => item.name === itemName);
let item = findItemByName(itemName);
if (!item) {
break;
}
let to_discard = num === -1 ? item.count : Math.min(num - discarded, item.count);
// Use toss with the item type (toss will remove from any slot containing that type)
await bot.toss(item.type, null, to_discard);
discarded += to_discard;
if (num !== -1 && discarded >= num) {
Expand Down
13 changes: 12 additions & 1 deletion src/mindcraft/mindcraft.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,18 @@ export async function init(host_public=false, port=8080, auto_open_ui=true) {
setTimeout(() => {
// check if browser listener is already open
if (numStateListeners() === 0) {
open('http://localhost:'+port);
// dynamically import `open` only when we need to open the UI so
// running the code (or tests) without the `open` package
// installed won't fail at module import time.
(async () => {
try {
const openModule = await import('open');
const open = openModule?.default || openModule;
open('http://localhost:'+port);
} catch (e) {
console.warn('`open` package not available, skipping auto-open of UI');
}
})();
}
}, 3000);
}
Expand Down
53 changes: 53 additions & 0 deletions tests/test_discard_offhand.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
(async () => {
// lightweight test for skills.discard to ensure items in off-hand slots are found
const path = '../src/agent/library/skills.js';
const skills = await import(path);

const tossCalls = [];

const bot = {
inventory: {
// no items() entries (simulates bug where off-hand isn't included)
items: () => [],
// slots: include an off-hand slot with index commonly 45 in mineflayer (varies) — we don't rely on index meaning
slots: {
0: null,
1: null,
40: { type: 5000, name: 'torch', count: 2 }, // off-hand-like slot
},
},
// toss should be called with (type, null, count)
toss: async (type, _null, count) => {
tossCalls.push({ type, count });
// simulate removing the item from slots
for (const k of Object.keys(bot.inventory.slots)) {
const s = bot.inventory.slots[k];
if (s && s.type === type) {
s.count -= count;
if (s.count <= 0) bot.inventory.slots[k] = null;
break;
}
}
},
};

console.log('Running discard test (off-hand)');
const ok = await skills.discard(bot, 'torch', 1);
console.log('discard returned:', ok);
console.log('tossCalls:', JSON.stringify(tossCalls));

if (!ok) {
console.error('TEST FAILED: discard returned false');
process.exit(1);
}
if (tossCalls.length !== 1) {
console.error('TEST FAILED: toss was not called exactly once');
process.exit(1);
}
if (tossCalls[0].count !== 1) {
console.error('TEST FAILED: toss called with wrong count', tossCalls[0]);
process.exit(1);
}

console.log('TEST PASSED');
})();