feat: Implement ScanState for systematic scanning with multiple scanner types
This commit is contained in:
184
server/states/ScanState.js
Normal file
184
server/states/ScanState.js
Normal file
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user