AI works here
This commit is contained in:
@@ -147,7 +147,7 @@ class ShulkerHandler {
|
||||
// Wait a few ticks for the item entity to spawn
|
||||
await bot.bot.waitForTicks(3);
|
||||
|
||||
// Jump onto the drop position to collect it (like a human player)
|
||||
// Attempt 1: Jump onto the drop position to collect it (like a human player)
|
||||
console.log(`ShulkerHandler: Jumping onto ${placedPos} to collect drop`);
|
||||
try {
|
||||
await bot.bot.lookAt(placedPos.offset(0.5, 0, 0.5), true);
|
||||
@@ -167,14 +167,43 @@ class ShulkerHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If not collected yet, pathfind directly to the drop
|
||||
// Attempt 2: Pathfind directly to the drop position
|
||||
try {
|
||||
await bot.goTo({ where: placedPos, range: 0 });
|
||||
} catch (e) {
|
||||
try { await bot.goTo({ where: placedPos, range: 1 }); } catch (e2) { /* ignore */ }
|
||||
}
|
||||
|
||||
// Poll for pickup (up to 5 seconds)
|
||||
await bot.bot.waitForTicks(5);
|
||||
if (bot.bot.inventory.items().find(item => item.name.includes('shulker_box'))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Attempt 3: Search for the dropped item entity nearby and walk to it
|
||||
// Item may have bounced away from the block position
|
||||
let droppedEntity = null;
|
||||
for (const entity of Object.values(bot.bot.entities)) {
|
||||
if (!entity.name || entity.name !== 'item') continue;
|
||||
const dist = entity.position.distanceTo(placedPos);
|
||||
if (dist < 5 && (!droppedEntity || dist < droppedEntity.position.distanceTo(placedPos))) {
|
||||
droppedEntity = entity;
|
||||
}
|
||||
}
|
||||
|
||||
if (droppedEntity) {
|
||||
console.log(`ShulkerHandler: Found item entity at ${droppedEntity.position}, walking to it`);
|
||||
try {
|
||||
await bot.goTo({ where: droppedEntity.position, range: 0 });
|
||||
} catch (e) {
|
||||
try { await bot.goTo({ where: droppedEntity.position, range: 1 }); } catch (e2) { /* ignore */ }
|
||||
}
|
||||
await bot.bot.waitForTicks(5);
|
||||
if (bot.bot.inventory.items().find(item => item.name.includes('shulker_box'))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Final poll — wait up to 5 seconds in case of lag
|
||||
for (let i = 0; i < 10; i++) {
|
||||
await sleep(500);
|
||||
if (bot.bot.inventory.items().find(item => item.name.includes('shulker_box'))) {
|
||||
@@ -182,101 +211,109 @@ class ShulkerHandler {
|
||||
}
|
||||
}
|
||||
|
||||
console.error('ShulkerHandler: Failed to collect shulker after all attempts');
|
||||
return !!bot.bot.inventory.items().find(item => item.name.includes('shulker_box'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-effort recovery: return a shulker from bot inventory back to its chest slot.
|
||||
* Return a shulker from bot inventory back to its chest slot.
|
||||
* If placedPos is given, dig the placed shulker first.
|
||||
* Never throws — returns true on success, false on failure.
|
||||
* @throws Error if the shulker cannot be returned (caller should handle the failure).
|
||||
*/
|
||||
async returnShulkerToChest(bot, chestPos, chestSlot, placedPos, chestId) {
|
||||
try {
|
||||
// If shulker is placed on the ground, break it first
|
||||
if (placedPos) {
|
||||
try {
|
||||
await bot.bot.closeWindow(bot.bot.currentWindow);
|
||||
} catch (e) { /* ignore */ }
|
||||
await sleep(300);
|
||||
|
||||
await this.digAndCollectShulker(bot, placedPos);
|
||||
}
|
||||
|
||||
// Find shulker in bot inventory
|
||||
const shulkerInInv = bot.bot.inventory.items().find(item => item.name.includes('shulker_box'));
|
||||
if (!shulkerInInv) {
|
||||
console.error('ShulkerHandler: Recovery failed — no shulker in inventory');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Go to chest and open it
|
||||
await bot.goTo({ where: chestPos, range: 3 });
|
||||
const chestBlock = bot.bot.blockAt(chestPos);
|
||||
if (!chestBlock || !chestBlock.name.includes('chest')) {
|
||||
console.error(`ShulkerHandler: Recovery failed — no chest at ${chestPos}`);
|
||||
return false;
|
||||
}
|
||||
const window = await bot.openContainer(chestBlock);
|
||||
// If shulker is placed on the ground, break it first
|
||||
if (placedPos) {
|
||||
try {
|
||||
await bot.bot.closeWindow(bot.bot.currentWindow);
|
||||
} catch (e) { /* ignore */ }
|
||||
await sleep(300);
|
||||
|
||||
// Find shulker in inventory portion of the window
|
||||
let shulkerWindowSlot = null;
|
||||
for (let i = window.inventoryStart; i < window.inventoryEnd; i++) {
|
||||
const item = window.slots[i];
|
||||
if (item && item.name.includes('shulker_box')) {
|
||||
shulkerWindowSlot = i;
|
||||
await this.digAndCollectShulker(bot, placedPos);
|
||||
}
|
||||
|
||||
// Find shulker in bot inventory — throw if not found so caller knows recovery failed
|
||||
const shulkerInInv = bot.bot.inventory.items().find(item => item.name.includes('shulker_box'));
|
||||
if (!shulkerInInv) {
|
||||
throw new Error('Recovery failed — no shulker in inventory');
|
||||
}
|
||||
|
||||
// Go to chest and open it
|
||||
await bot.goTo({ where: chestPos, range: 3 });
|
||||
const chestBlock = bot.bot.blockAt(chestPos);
|
||||
if (!chestBlock || !chestBlock.name.includes('chest')) {
|
||||
throw new Error(`Recovery failed — no chest at ${chestPos}`);
|
||||
}
|
||||
const window = await bot.openContainer(chestBlock);
|
||||
await sleep(300);
|
||||
|
||||
// Find shulker in inventory portion of the window
|
||||
let shulkerWindowSlot = null;
|
||||
for (let i = window.inventoryStart; i < window.inventoryEnd; i++) {
|
||||
const item = window.slots[i];
|
||||
if (item && item.name.includes('shulker_box')) {
|
||||
shulkerWindowSlot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (shulkerWindowSlot === null) {
|
||||
await bot.bot.closeWindow(window);
|
||||
throw new Error('Recovery failed — shulker not found in window inventory');
|
||||
}
|
||||
|
||||
// Try original slot first; if occupied, find any empty chest slot
|
||||
let targetSlot = chestSlot;
|
||||
if (window.slots[chestSlot]) {
|
||||
targetSlot = null;
|
||||
for (let i = 0; i < window.inventoryStart; i++) {
|
||||
if (!window.slots[i]) {
|
||||
targetSlot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (shulkerWindowSlot === null) {
|
||||
await bot.bot.closeWindow(window);
|
||||
console.error('ShulkerHandler: Recovery failed — shulker not found in window inventory');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try original slot first; if occupied, find any empty chest slot
|
||||
let targetSlot = chestSlot;
|
||||
if (window.slots[chestSlot]) {
|
||||
targetSlot = null;
|
||||
for (let i = 0; i < window.inventoryStart; i++) {
|
||||
if (!window.slots[i]) {
|
||||
targetSlot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (targetSlot === null) {
|
||||
await bot.bot.closeWindow(window);
|
||||
console.error('ShulkerHandler: Recovery failed — no empty chest slot');
|
||||
return false;
|
||||
}
|
||||
|
||||
await bot.bot.moveSlotItem(shulkerWindowSlot, targetSlot);
|
||||
await sleep(300);
|
||||
|
||||
// Read the NBT and sync DB immediately
|
||||
const updatedSlotItem = window.slots[targetSlot];
|
||||
await bot.bot.closeWindow(window);
|
||||
await sleep(200);
|
||||
|
||||
if (updatedSlotItem && chestId && this.scanner) {
|
||||
try {
|
||||
await this.scanner.scanShulkerFromNBT(bot, Database, chestId, targetSlot, updatedSlotItem);
|
||||
await Database.rebuildItemIndex();
|
||||
console.log(`ShulkerHandler: Recovery DB synced — shulker at chest slot ${targetSlot}`);
|
||||
} catch (e) {
|
||||
console.error(`ShulkerHandler: Recovery DB sync failed: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`ShulkerHandler: Recovery succeeded — shulker returned to chest slot ${targetSlot}`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('ShulkerHandler: Recovery error:', error.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (targetSlot === null) {
|
||||
await bot.bot.closeWindow(window);
|
||||
throw new Error('Recovery failed — no empty chest slot');
|
||||
}
|
||||
|
||||
await bot.bot.moveSlotItem(shulkerWindowSlot, targetSlot);
|
||||
await sleep(300);
|
||||
|
||||
// Read the NBT and sync DB immediately
|
||||
const updatedSlotItem = window.slots[targetSlot];
|
||||
await bot.bot.closeWindow(window);
|
||||
await sleep(200);
|
||||
|
||||
if (updatedSlotItem && chestId && this.scanner) {
|
||||
try {
|
||||
await this.scanner.scanShulkerFromNBT(bot, Database, chestId, targetSlot, updatedSlotItem);
|
||||
await Database.rebuildItemIndex();
|
||||
console.log(`ShulkerHandler: Recovery DB synced — shulker at chest slot ${targetSlot}`);
|
||||
} catch (e) {
|
||||
console.error(`ShulkerHandler: Recovery DB sync failed: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the shulker is actually back in the chest
|
||||
await bot.goTo({ where: chestPos, range: 3 });
|
||||
const verifyBlock = bot.bot.blockAt(chestPos);
|
||||
if (!verifyBlock || !verifyBlock.name.includes('chest')) {
|
||||
throw new Error('Recovery verification failed — chest not found');
|
||||
}
|
||||
const verifyWindow = await bot.openContainer(verifyBlock);
|
||||
await sleep(200);
|
||||
const verifyItem = verifyWindow.slots[targetSlot];
|
||||
await bot.bot.closeWindow(verifyWindow);
|
||||
await sleep(200);
|
||||
|
||||
if (!verifyItem || !verifyItem.name.includes('shulker_box')) {
|
||||
throw new Error(`Recovery verification failed — shulker not found at chest slot ${targetSlot} after return`);
|
||||
}
|
||||
|
||||
console.log(`ShulkerHandler: Recovery succeeded — shulker returned to chest slot ${targetSlot}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -573,7 +610,18 @@ class ShulkerHandler {
|
||||
placedPos = result.placedPos;
|
||||
} catch (placeError) {
|
||||
console.error('ShulkerHandler: Failed to place shulker, recovering:', placeError.message);
|
||||
await this.returnShulkerToChest(bot, chestPos, chestSlot, null, chestId);
|
||||
let recovered = false;
|
||||
try {
|
||||
await this.returnShulkerToChest(bot, chestPos, chestSlot, null, chestId);
|
||||
recovered = true;
|
||||
} catch (recoverError) {
|
||||
console.error('ShulkerHandler: Recovery failed:', recoverError.message);
|
||||
}
|
||||
if (!recovered) {
|
||||
// Recovery failed — shulker state is uncertain, propagate error upward
|
||||
// so the caller knows not to retry this same shulker
|
||||
throw recoverError;
|
||||
}
|
||||
return { deposited: 0, updatedSlotItem: null };
|
||||
}
|
||||
|
||||
@@ -646,13 +694,27 @@ class ShulkerHandler {
|
||||
return { deposited, updatedSlotItem };
|
||||
} catch (returnError) {
|
||||
console.error('ShulkerHandler: Failed to close/break/return, recovering:', returnError.message);
|
||||
await this.returnShulkerToChest(bot, chestPos, chestSlot, placedPos, chestId);
|
||||
return { deposited: 0, updatedSlotItem: null };
|
||||
let recovered = false;
|
||||
try {
|
||||
await this.returnShulkerToChest(bot, chestPos, chestSlot, placedPos, chestId);
|
||||
recovered = true;
|
||||
} catch (recoverError) {
|
||||
console.error('ShulkerHandler: Recovery failed:', recoverError.message);
|
||||
}
|
||||
if (!recovered) throw returnError;
|
||||
return { deposited, updatedSlotItem: null };
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('ShulkerHandler: Deposit failed, attempting recovery:', error.message);
|
||||
await this.returnShulkerToChest(bot, chestPos, chestSlot, placedPos, chestId);
|
||||
let recovered = false;
|
||||
try {
|
||||
await this.returnShulkerToChest(bot, chestPos, chestSlot, placedPos, chestId);
|
||||
recovered = true;
|
||||
} catch (recoverError) {
|
||||
console.error('ShulkerHandler: Recovery failed:', recoverError.message);
|
||||
}
|
||||
if (!recovered) throw error;
|
||||
return { deposited: 0, updatedSlotItem: null };
|
||||
} finally {
|
||||
this.operationInProgress = false;
|
||||
@@ -822,7 +884,14 @@ class ShulkerHandler {
|
||||
placedPos = result.placedPos;
|
||||
} catch (placeError) {
|
||||
console.error('ShulkerHandler: Failed to place shulker, recovering:', placeError.message);
|
||||
await this.returnShulkerToChest(bot, chestPos, chestSlot, null, chestId);
|
||||
let recovered = false;
|
||||
try {
|
||||
await this.returnShulkerToChest(bot, chestPos, chestSlot, null, chestId);
|
||||
recovered = true;
|
||||
} catch (recoverError) {
|
||||
console.error('ShulkerHandler: Recovery failed:', recoverError.message);
|
||||
}
|
||||
if (!recovered) throw placeError;
|
||||
return { withdrawn: 0, updatedSlotItem: null };
|
||||
}
|
||||
|
||||
@@ -841,6 +910,9 @@ class ShulkerHandler {
|
||||
const shulkerItem = shulkerWindow.slots[s];
|
||||
if (!shulkerItem || shulkerItem.name !== itemName) continue;
|
||||
|
||||
// Skip special/named items — only withdraw via special item handler
|
||||
if (shulkerItem.nbt?.value?.display) continue;
|
||||
|
||||
// Check if inventory has space
|
||||
const hasInvSpace = (() => {
|
||||
for (let i = shulkerWindow.inventoryStart; i < shulkerWindow.inventoryEnd; i++) {
|
||||
@@ -906,13 +978,27 @@ class ShulkerHandler {
|
||||
return { withdrawn, updatedSlotItem };
|
||||
} catch (returnError) {
|
||||
console.error('ShulkerHandler: Failed to close/break/return, recovering:', returnError.message);
|
||||
await this.returnShulkerToChest(bot, chestPos, chestSlot, placedPos, chestId);
|
||||
let recovered = false;
|
||||
try {
|
||||
await this.returnShulkerToChest(bot, chestPos, chestSlot, placedPos, chestId);
|
||||
recovered = true;
|
||||
} catch (recoverError) {
|
||||
console.error('ShulkerHandler: Recovery failed:', recoverError.message);
|
||||
}
|
||||
if (!recovered) throw returnError;
|
||||
return { withdrawn: 0, updatedSlotItem: null };
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('ShulkerHandler: Withdraw failed, attempting recovery:', error.message);
|
||||
await this.returnShulkerToChest(bot, chestPos, chestSlot, placedPos, chestId);
|
||||
let recovered = false;
|
||||
try {
|
||||
await this.returnShulkerToChest(bot, chestPos, chestSlot, placedPos, chestId);
|
||||
recovered = true;
|
||||
} catch (recoverError) {
|
||||
console.error('ShulkerHandler: Recovery failed:', recoverError.message);
|
||||
}
|
||||
if (!recovered) throw error;
|
||||
return { withdrawn: 0, updatedSlotItem: null };
|
||||
} finally {
|
||||
this.operationInProgress = false;
|
||||
@@ -945,7 +1031,14 @@ class ShulkerHandler {
|
||||
placedPos = result.placedPos;
|
||||
} catch (placeError) {
|
||||
console.error('ShulkerHandler: Failed to place shulker, recovering:', placeError.message);
|
||||
await this.returnShulkerToChest(bot, chestPos, chestSlot, null, chestId);
|
||||
let recovered = false;
|
||||
try {
|
||||
await this.returnShulkerToChest(bot, chestPos, chestSlot, null, chestId);
|
||||
recovered = true;
|
||||
} catch (recoverError) {
|
||||
console.error('ShulkerHandler: Recovery failed:', recoverError.message);
|
||||
}
|
||||
if (!recovered) throw placeError;
|
||||
return { withdrawn: 0, updatedSlotItem: null };
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user