/** * ScanState - Systematic scanning of surroundings using peripheral scanners * * Supports multiple scanner types: * - geoScanner (Advanced Peripherals) * - universal_scanner * - plethora:scanner (Plethora mod) * - Native turtle.inspect() fallback (6-directional scan) */ import { BaseState } from './BaseState.js'; export class ScanState extends BaseState { constructor(turtle, data = {}) { super(turtle, data); this.scanRadius = data.scanRadius || 16; this.blocksScanned = 0; this.scannerType = null; } get name() { return 'scanning'; } get description() { return `Scanning (${this.scannerType || 'detecting'}) - ${this.blocksScanned} blocks`; } async *act() { console.log(`[${this.turtle.id}] Starting scan`); // Detect available scanner peripheral this.scannerType = await this._detectScanner(); yield; if (this.scannerType === 'geoScanner') { yield* this._geoScan(); } else if (this.scannerType === 'universal_scanner') { yield* this._universalScan(); } else if (this.scannerType === 'plethora:scanner') { yield* this._plethuraScan(); } else { // Fallback to native inspect-based scanning yield* this._nativeScan(); } console.log(`[${this.turtle.id}] Scan complete: ${this.blocksScanned} blocks`); this.turtle.setState('idle'); } async _detectScanner() { // Check for geoScanner const geoResult = await this.exec(` local names = peripheral.getNames() for _, name in ipairs(names) do local types = {peripheral.getType(name)} for _, t in ipairs(types) do if t == "geoScanner" then return "geoScanner" end end end return nil `); if (geoResult) return geoResult; // Check for universal_scanner const uniResult = await this.exec(` local names = peripheral.getNames() for _, name in ipairs(names) do local types = {peripheral.getType(name)} for _, t in ipairs(types) do if t == "universal_scanner" then return "universal_scanner" end end end return nil `); if (uniResult) return uniResult; // Check for plethora scanner const plResult = await this.exec(` local names = peripheral.getNames() for _, name in ipairs(names) do local types = {peripheral.getType(name)} for _, t in ipairs(types) do if t == "plethora:scanner" then return "plethora:scanner" end end end return nil `); if (plResult) return plResult; return 'native'; } async *_geoScan() { // Wait for cooldown yield; await this._sleep(500); const result = await this.exec(` local scanner = peripheral.find("geoScanner") if not scanner then return nil end local ok, blocks = pcall(scanner.scan, ${this.scanRadius}) if ok then return blocks end return nil `); if (result && Array.isArray(result)) { this._processScannedBlocks(result); } yield; } async *_universalScan() { yield; await this._sleep(500); const result = await this.exec(` local scanner = peripheral.find("universal_scanner") if not scanner then return nil end local ok, blocks = pcall(scanner.scan, "block", ${this.scanRadius}) if ok then return blocks end return nil `); if (result && Array.isArray(result)) { this._processScannedBlocks(result); } yield; } async *_plethuraScan() { yield; const result = await this.exec(` local scanner = peripheral.find("plethora:scanner") if not scanner then return nil end local ok, blocks = pcall(scanner.scan) if ok then return blocks end return nil `); if (result && Array.isArray(result)) { this._processScannedBlocks(result); } yield; } async *_nativeScan() { // Fallback: scan all 6 directions using turtle.inspect const scanResult = await this.scanSurroundings(); if (scanResult) { this.blocksScanned += Object.keys(scanResult).length; } yield; } _processScannedBlocks(blocks) { const pos = this.turtle.position; if (!pos) return; const discoveredBlocks = []; for (const block of blocks) { if (!block || !block.name) continue; if (block.name === 'minecraft:air') continue; if (block.x === 0 && block.y === 0 && block.z === 0) continue; discoveredBlocks.push({ x: pos.x + (block.x || 0), y: pos.y + (block.y || 0), z: pos.z + (block.z || 0), name: block.name, metadata: block.metadata || 0, state: block.state || {}, tags: block.tags || {}, discoveredBy: this.turtle.id, }); } this.blocksScanned = discoveredBlocks.length; if (discoveredBlocks.length > 0) { this.turtle.emit('blocksDiscovered', discoveredBlocks); } } }