This commit is contained in:
2026-07-12 17:26:59 -04:00
parent 60663b8d4a
commit ba1bef8ff9
25 changed files with 158880 additions and 1529 deletions
+60 -7
View File
@@ -162,12 +162,31 @@ module.exports = {
return;
}
let tradeResult = null;
let pending = null;
let itemsReceived = [];
try {
storage._busy = true;
const pending = storage.pendingWithdrawals.get(from);
// The task we interrupted has exited (it released the lock);
// reset the interrupt flag so our own work isn't flagged
this.registerTask('Storage', 'trade', null);
pending = storage.pendingWithdrawals.get(from);
// Set up listener BEFORE accepting to avoid race with window opening
const windowPromise = this.once('windowOpen');
await this.say('/trade accept');
let window = await this.once('windowOpen');
// If no window ever opens (expired request, player left), bail
// instead of holding the storage lock forever
let window = await Promise.race([
windowPromise,
sleep(30000).then(() => null),
]);
if (!window) {
this.whisper(from, 'Trade window never opened — send the trade request again.');
return;
}
// If there's a pending withdrawal, place items in bot's trade slots
if (pending) {
@@ -202,7 +221,8 @@ module.exports = {
console.log(`Storage trade: Placed ${placed} stack(s) in trade window`);
}
// Poll for customer confirmation (lime_dye at slot 53)
// Poll for other party's lock indicator (slot 53 grey_dye → lime_dye)
// Both parties must click green wool (slot 37) twice: 1st locks, 2nd finalizes
let timeoutCheck = setTimeout(() => {
this.bot.closeWindow(window);
this.whisper(from, 'Trade timed out.');
@@ -210,9 +230,25 @@ module.exports = {
let confirmationCheck = setInterval(async () => {
try {
// Never click a closed window — invalid window IDs
// trip anti-cheat ("unusual packets")
if (this.bot.currentWindow !== window) return;
const indicator = window.slots[53];
if (indicator && indicator.name === 'lime_dye') {
this.bot.moveSlotItem(37, 37);
clearInterval(confirmationCheck);
// Click 1: lock items — single left-click, not the
// pickup+putdown pair moveSlotItem sends
await this.bot.clickWindow(37, 0, 0);
console.log('Storage trade: click 1 — items locked');
await sleep(1000); // Both now locked, brief pause
// Click 2: finalize (second confirmation)
if (this.bot.currentWindow === window) {
await this.bot.clickWindow(37, 0, 0);
console.log('Storage trade: click 2 — final confirm');
}
}
} catch (e) {
// window may have closed
@@ -229,7 +265,7 @@ module.exports = {
}
clearTimeout(timeoutCheck);
let tradeResult = null;
if (pending) {
// Withdrawal complete — clear pending
@@ -241,7 +277,7 @@ module.exports = {
await sleep(500);
const hotbarNames = new Set((storage.config.hotbarItems || []).map(h => h.name));
const itemsReceived = [];
itemsReceived = [];
for (const item of this.bot.inventory.items()) {
if (hotbarNames.has(item.name)) continue;
itemsReceived.push({ name: item.name, id: item.type, count: item.count, nbt: item.nbt });
@@ -254,18 +290,35 @@ module.exports = {
}
}
} finally {
this.clearTask();
storage._busy = false;
storage._releaseOperationLock();
}
// Organize after lock is released (handleTrade runs under the lock)
if (tradeResult && tradeResult.needsOrganize) {
storage._busy = true;
try {
await storage.organizeLooseItems();
await storage.organizeLooseItems(true);
} catch (error) {
console.error('Storage: Post-trade organize failed:', error.message);
}
}
// Notify the AI face bot about this trade so it can respond naturally
try {
const { getInstance } = require('../ai/manager');
const manager = getInstance();
if (manager.isActive) {
if (pending) {
manager.notifySystemEvent(`${this.bot.entity.username} completed withdrawal: ${pending.count}x ${pending.itemName} for ${from}. Trade finished.`);
} else if (itemsReceived && itemsReceived.length > 0) {
const itemSummary = itemsReceived.slice(0, 5).map(i => `${i.count}x ${i.name}`).join(', ');
const extra = itemsReceived.length > 5 ? ` +${itemsReceived.length - 5} more types` : '';
manager.notifySystemEvent(`${this.bot.entity.username} received deposit from ${from}: ${itemSummary}${extra}. All items stored.`);
}
}
} catch (e) { /* ignore */ }
}
},
};