Fuzzy item matching + periodic inventory check for auto-equip

- equipBestWeapon uses fuzzy substring matching on item names
- equipBestArmor uses .includes() instead of .startsWith() for tiers
- Both strip minecraft: prefix before comparing
- Added periodic inventory check every 5 seconds (playerCollect
  doesn't fire on Bedrock) — detects new items and auto-equips
- evaluateEquipment logs full inventory contents for debugging
- All name comparisons are case-insensitive

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
roberts 2026-03-30 20:22:08 -05:00
parent aa0a937171
commit 9869181071

View file

@ -386,19 +386,36 @@ async function evaluateEquipment() {
if (Date.now() - lastEquipCheck < 3000) return;
lastEquipCheck = Date.now();
// Log what we have
const allItems = bot.inventory.items();
if (allItems.length > 0) {
log('client', 'INFO', `Inventory: ${allItems.map(i => i.name).join(', ')}`);
}
const weaponResult = await equipBestWeapon();
if (weaponResult.equipped) {
log('client', 'INFO', `🛡 Auto-equipped weapon: ${weaponResult.item}`);
log('client', 'INFO', `Auto-equipped weapon: ${weaponResult.item}`);
sendEvent('equipment_changed', { type: 'weapon', item: weaponResult.item });
}
const armorResult = await equipBestArmor();
if (armorResult.equipped) {
log('client', 'INFO', `🛡 Auto-equipped armor: ${armorResult.items.join(', ')}`);
log('client', 'INFO', `Auto-equipped armor: ${armorResult.items.join(', ')}`);
sendEvent('equipment_changed', { type: 'armor', items: armorResult.items });
}
}
// Also check inventory periodically (playerCollect may not fire on Bedrock)
setInterval(() => {
if (!spawned) return;
const items = bot.inventory.items();
const hash = items.map(i => `${i.name}:${i.count}`).sort().join(',');
if (hash !== lastInventoryHash && hash !== '') {
lastInventoryHash = hash;
evaluateEquipment();
}
}, 5000);
// --- Player-friendly name → Bedrock item ID mapping ---
const ITEM_ALIASES = {
// Plural → singular
@ -634,24 +651,41 @@ async function equipBestWeapon() {
let bestTier = -1;
for (const item of items) {
const name = item.name.replace('minecraft:', '');
const tier = WEAPON_TIERS[name] || 0;
// Fuzzy match: strip prefix, try exact and partial matching
const rawName = (item.name || '').replace('minecraft:', '').toLowerCase();
let tier = WEAPON_TIERS[rawName] || 0;
// Also try matching by substring (e.g. item.name contains "diamond_sword")
if (tier === 0) {
for (const [weaponName, weaponTier] of Object.entries(WEAPON_TIERS)) {
if (rawName.includes(weaponName) || weaponName.includes(rawName)) {
tier = weaponTier;
break;
}
}
}
if (tier > bestTier) {
bestTier = tier;
bestItem = item;
}
}
if (bestItem && bestItem !== bot.heldItem) {
if (bestItem) {
// Check if already holding this item
const heldName = bot.heldItem?.name?.replace('minecraft:', '').toLowerCase() || '';
const bestName = bestItem.name.replace('minecraft:', '').toLowerCase();
if (heldName === bestName) {
return { equipped: false, reason: 'already_equipped' };
}
try {
await bot.equip(bestItem, 'hand');
log('client', 'INFO', `Equipped ${bestItem.name}`);
return { equipped: true, item: bestItem.name };
} catch (e) {
log('client', 'WARN', `Failed to equip ${bestItem.name}: ${e.message}`);
return { equipped: false, error: e.message };
}
}
return { equipped: false, reason: bestItem ? 'already_equipped' : 'no_weapons' };
return { equipped: false, reason: 'no_weapons' };
}
async function equipBestTool(blockType) {
@ -704,9 +738,9 @@ async function equipBestArmor() {
let bestTierIdx = 999;
for (const item of items) {
const name = item.name.replace('minecraft:', '');
const name = (item.name || '').replace('minecraft:', '').toLowerCase();
if (!name.includes(armorPiece)) continue;
const tierIdx = ARMOR_TIERS.findIndex(t => name.startsWith(t));
const tierIdx = ARMOR_TIERS.findIndex(t => name.includes(t));
if (tierIdx >= 0 && tierIdx < bestTierIdx) {
bestTierIdx = tierIdx;
bestItem = item;
@ -717,6 +751,7 @@ async function equipBestArmor() {
try {
await bot.equip(bestItem, slot);
equipped.push(bestItem.name);
log('client', 'INFO', `Equipped armor: ${bestItem.name}${slot}`);
} catch (e) {
log('client', 'WARN', `Failed to equip ${bestItem.name}: ${e.message}`);
}