let bot let mcData let quiet // import v from 'vec3' const v = require('vec3') let cfg = { info: { quiet: quiet, recentCommand: null, }, // to satisfy typescript quiet: null, bot: bot } function isVec3(vec) { return vec?.length === 3 || vec.x && vec.y && vec.z } function block(entity = bot.entity, pos = entity?.position?.offset(0, -1, 0)) { console.assert(pos || entity) const block = isVec3(pos) ? bot.blockAt(v(pos)) : pos console.log(block, block?.getProperties && block.getProperties()) if (!block) { quiet || bot.chat("empty block") return block } bot.lookAt(block?.position) let info = [block.type, block.name] if (block.metadata) info.push(Object.entries(block.getProperties())) quiet || bot.chat(info.join(": ")) } function item( entity = bot.entity, slot = entity.heldItem ) { const item = typeof slot === "number" ? bot.inventory.slots[slot + bot.QUICK_BAR_START] : slot console.log("info item:", item) if (!item) { quiet || bot.chat("no item") return item } let info = [item.type, item.name, item.count] if (item.metadata) info.push("meta: " + item.metadata.length) if (item.nbt) { info.push(compound_value(item.nbt)) } quiet || bot.chat(info.join("; ")) function compound_value(obj) { if (typeof obj.value == "object") { return compound_value(obj.value) } else if (obj.value) { return obj.value } else if (typeof obj == "object") { const keys = Object.keys(obj) return keys.map(key => { return `${key}: ${compound_value(obj[key])}` }); } else { return obj } } return item } function entity(name) { const entity = typeof name === "string" ? bot.nearestEntity((entity) => { const ename = entity.name || entity.username return name && ename ? ename == name : true }) : entity console.log(entity) if (!entity) { quiet || bot.chat("no entity") return entity } let info = [entity.type, entity.username || entity.name] // TODO various info depending on the type of entity; player, villager, etc if (entity.metadata) info.push("len: " + entity.metadata.length) quiet || bot.chat(info.join("; ")) return entity } function command(message_parts, player) { if (message_parts.length > 0) { cfg.info.recentCommand = message_parts } switch (message_parts.length) { case 0: if (cfg.info.recentCommand) { command(cfg.info.recentCommand, player) } else { // TODO dispatch on instance of entity, block, etc.. // TODO have the logic inside the function or with a utility function block() } break; case 1: switch (message_parts[0]) { case "quiet": cfg.info.quiet = quiet = !quiet; quiet || bot.chat(`info: ${quiet ? "" : "not "}being quiet`); break; case "i": case "item": item() break case "e": case "entity": entity() break case "me": block(player) break case "b": case "block": default: block() break; } break; case 2: switch (message_parts[0]) { case "i": case "item": switch (message_parts[1]) { case "me": item(player) break default: const slot = parseInt(message_parts[1]) slot && item(undefined, slot) break } break case "b": case "block": switch (message_parts[1]) { case "me": block(player) break default: console.log(bot.players[message_parts[1]]) quiet || bot.chat("info: not yet implemented") } break case "e": case "entity": default: entity(message_parts[1]) break; } break case 4: switch (message_parts[0]) { case "b": case "block": default: block(undefined, message_parts.slice(1)) break; } break; default: cfg.quiet || bot.chat("info: unknown command") break; } } const load = (config) => { config.info = cfg.info cfg = config bot = cfg.bot mcData = bot.mcData || (bot.mcData = require('minecraft-data')(bot.version)) } const unload = () => {} module.exports = { load, unload, command, block, item, entity }