From bdc4dade9f5588d1299a1d745f786ccb68597ff2 Mon Sep 17 00:00:00 2001 From: MayaTheShy Date: Fri, 20 Feb 2026 01:46:09 -0500 Subject: [PATCH] feat: Implement RefuelingState class for turtle state machine to manage fuel replenishment --- server/states/RefuelingState.js | 126 ++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 server/states/RefuelingState.js diff --git a/server/states/RefuelingState.js b/server/states/RefuelingState.js new file mode 100644 index 0000000..26f25c7 --- /dev/null +++ b/server/states/RefuelingState.js @@ -0,0 +1,126 @@ +/** + * RefuelingState - Refuel the turtle from inventory or nearby containers + * Prioritizes fuel sources: lava buckets > coal blocks > coal > logs > sticks + */ +import { BaseState } from './BaseState.js'; + +const FUEL_PRIORITY = [ + 'minecraft:lava_bucket', + 'minecraft:coal_block', + 'minecraft:charcoal', + 'minecraft:coal', + 'minecraft:oak_log', 'minecraft:birch_log', 'minecraft:spruce_log', + 'minecraft:dark_oak_log', 'minecraft:jungle_log', 'minecraft:acacia_log', + 'minecraft:mangrove_log', 'minecraft:cherry_log', + 'minecraft:oak_planks', 'minecraft:birch_planks', 'minecraft:spruce_planks', + 'minecraft:stick', +]; + +export class RefuelingState extends BaseState { + constructor(turtle, data = {}) { + super(turtle, data); + this.returnState = data.returnState || null; + this.returnData = data.returnData || {}; + this.targetFuel = data.targetFuel || 5000; + } + + get name() { + return 'refueling'; + } + + get description() { + return 'Refueling turtle'; + } + + async *act() { + console.log(`[${this.turtle.id}] Starting refueling, target: ${this.targetFuel}`); + + // First try to refuel from own inventory using priority order + const refueled = await this.exec(` + local fuelPriority = ${this._luaFuelTable()} + local targetFuel = ${this.targetFuel} + local refueled = false + + for _, fuelName in ipairs(fuelPriority) do + for slot = 1, 16 do + local item = turtle.getItemDetail(slot) + if item and item.name == fuelName then + turtle.select(slot) + turtle.refuel() + refueled = true + if turtle.getFuelLevel() >= targetFuel then + turtle.select(1) + return {success = true, fuel = turtle.getFuelLevel()} + end + end + end + end + + turtle.select(1) + return {success = refueled, fuel = turtle.getFuelLevel()} + `); + + if (refueled) { + this.turtle.fuel = refueled.fuel; + console.log(`[${this.turtle.id}] Refueled to ${refueled.fuel}`); + } + + yield; + + // Try to refuel from nearby containers (chests, barrels) + if (!refueled || !refueled.success || refueled.fuel < this.targetFuel) { + console.log(`[${this.turtle.id}] Trying nearby containers for fuel`); + + const containerResult = await this.exec(` + local directions = {"front", "top", "bottom"} + local suckFns = {turtle.suck, turtle.suckUp, turtle.suckDown} + + for i, dir in ipairs(directions) do + -- Try to suck items from container + for attempt = 1, 16 do + if suckFns[i]() then + -- Check if it's fuel + local slot = turtle.getSelectedSlot() + if turtle.refuel(0) then + turtle.refuel() + end + else + break + end + end + end + + return {fuel = turtle.getFuelLevel()} + `); + + if (containerResult) { + this.turtle.fuel = containerResult.fuel; + } + } + + yield; + + // Transition to next state + if (this.returnState) { + this.turtle.setState(this.returnState, this.returnData); + } else { + this.turtle.setState('idle'); + } + } + + _luaFuelTable() { + const items = FUEL_PRIORITY.map(name => `"${name}"`).join(', '); + return `{${items}}`; + } + + getRecoveryData() { + return { + ...super.getRecoveryData(), + data: { + returnState: this.returnState, + returnData: this.returnData, + targetFuel: this.targetFuel, + }, + }; + } +}