diff --git a/server/states/MovingState.js b/server/states/MovingState.js new file mode 100644 index 0000000..addfc98 --- /dev/null +++ b/server/states/MovingState.js @@ -0,0 +1,78 @@ +/** + * MovingState - Navigate the turtle to a target position using D* Lite + */ +import { BaseState } from './BaseState.js'; + +export class MovingState extends BaseState { + constructor(turtle, data = {}) { + super(turtle, data); + this.target = data.target; // {x, y, z} + this.onArrival = data.onArrival || null; // Callback/next state when arrived + this.canMine = data.canMine !== false; + } + + get name() { + return 'moving'; + } + + get description() { + const pos = this.target; + if (pos) { + return `Moving to (${pos.x}, ${pos.y}, ${pos.z})`; + } + return 'Moving to target'; + } + + async *act() { + if (!this.target) { + console.log(`[${this.turtle.id}] MovingState: No target set`); + this.turtle.setState('idle'); + return; + } + + console.log(`[${this.turtle.id}] Moving to ${this.target.x},${this.target.y},${this.target.z}`); + + // Use the navigateTo generator from BaseState + const nav = this.navigateTo(this.target, { canMine: this.canMine }); + + for await (const _ of nav) { + if (this.cancelled) return; + yield; + } + + // Check if we actually arrived + const pos = this.turtle.position; + if (pos) { + const { Point } = await import('../pathfinding/index.js'); + const current = Point.from(pos); + const goal = Point.from(this.target); + + if (current.distanceTo(goal) <= 1) { + console.log(`[${this.turtle.id}] Arrived at destination`); + + if (this.onArrival === 'idle') { + this.turtle.setState('idle'); + } else if (this.onArrival === 'mine') { + this.turtle.setState('mining', this.data); + } else { + this.turtle.setState('idle'); + } + return; + } + } + + console.log(`[${this.turtle.id}] Failed to reach destination`); + this.turtle.setState('idle'); + } + + getRecoveryData() { + return { + ...super.getRecoveryData(), + data: { + target: this.target, + onArrival: this.onArrival, + canMine: this.canMine, + }, + }; + } +}