feat(goo): rewrite automation flow
This commit is contained in:
parent
7f6bd477d4
commit
9dd4455203
717
programs/goo.lua
717
programs/goo.lua
@ -1,4 +1,4 @@
|
||||
local _VERSION = "0.2.1"
|
||||
local _VERSION = "1.0.0"
|
||||
|
||||
local args = table.pack(...)
|
||||
local command = args[1]
|
||||
@ -7,6 +7,8 @@ local GOO_BLOCK_PREFIX = "justdirethings:gooblock_tier"
|
||||
local MIN_START_FUEL = 50
|
||||
local REFUEL_THRESHOLD = 1000
|
||||
local WAIT_SECONDS = 2
|
||||
local MIN_FEEDING_ITEMS = 4
|
||||
local MAX_SUCK_ATTEMPTS = 16
|
||||
|
||||
local FUEL_ITEMS = {
|
||||
"justdirethings:coal_t4",
|
||||
@ -36,7 +38,42 @@ local FEEDING_ITEMS_BY_TIER = {
|
||||
[4] = { "minecraft:sculk" },
|
||||
}
|
||||
|
||||
local DIR_NORTH = 0
|
||||
local DIR_EAST = 1
|
||||
local DIR_SOUTH = 2
|
||||
local DIR_WEST = 3
|
||||
|
||||
local DIRECTION_DELTAS = {
|
||||
[DIR_NORTH] = { x = 0, z = -1 },
|
||||
[DIR_EAST] = { x = 1, z = 0 },
|
||||
[DIR_SOUTH] = { x = 0, z = 1 },
|
||||
[DIR_WEST] = { x = -1, z = 0 },
|
||||
}
|
||||
|
||||
local HOME = { x = -2, y = 0, z = 0, facing = DIR_EAST }
|
||||
local GOO_CHECK = { x = -1, y = 0, z = 0, facing = DIR_EAST }
|
||||
|
||||
local GOO_CHECKS = {
|
||||
{ name = "west goo check", x = -1, y = 0, z = 0, facing = DIR_EAST, action = "forward" },
|
||||
{ name = "east goo check", x = 1, y = 0, z = 0, facing = DIR_WEST, action = "forward" },
|
||||
{ name = "north goo check", x = 0, y = 0, z = -1, facing = DIR_SOUTH, action = "forward" },
|
||||
{ name = "south goo check", x = 0, y = 0, z = 1, facing = DIR_NORTH, action = "forward" },
|
||||
{ name = "top goo check", x = 0, y = 1, z = 0, facing = DIR_EAST, action = "down" },
|
||||
}
|
||||
|
||||
local TARGETS = {
|
||||
{ name = "west side", x = -2, y = 0, z = 0, facing = DIR_EAST, action = "forward" },
|
||||
{ name = "east side", x = 2, y = 0, z = 0, facing = DIR_WEST, action = "forward" },
|
||||
{ name = "north side", x = 0, y = 0, z = -2, facing = DIR_SOUTH, action = "forward" },
|
||||
{ name = "south side", x = 0, y = 0, z = 2, facing = DIR_NORTH, action = "forward" },
|
||||
{ name = "top", x = -1, y = 1, z = 0, facing = DIR_EAST, action = "forward" },
|
||||
}
|
||||
|
||||
local position = { x = HOME.x, y = HOME.y, z = HOME.z }
|
||||
local facing = HOME.facing
|
||||
local loggedBlockedItems = {}
|
||||
local placedTargets = {}
|
||||
local lastGooTier = nil
|
||||
|
||||
local function isFlag(name)
|
||||
return function(arg)
|
||||
@ -82,11 +119,6 @@ local function hasPickaxeEquipped()
|
||||
or (right and string.match(right.name or "", "_pickaxe$") ~= nil)
|
||||
end
|
||||
|
||||
local function turnAround()
|
||||
turtle.turnRight()
|
||||
turtle.turnRight()
|
||||
end
|
||||
|
||||
local function parseGooTier(blockName)
|
||||
local tier = string.match(blockName or "", "^" .. GOO_BLOCK_PREFIX .. "(%d+)$")
|
||||
|
||||
@ -101,20 +133,51 @@ local function isProcessBlock(blockName)
|
||||
return PROCESS_ITEMS[blockName] ~= nil
|
||||
end
|
||||
|
||||
local function inspectGoo()
|
||||
local ok, inspected = turtle.inspectUp()
|
||||
|
||||
if not ok then
|
||||
error("expected a Just Dire Things goo block above the turtle")
|
||||
local function isFuelItem(itemName)
|
||||
for i = 1, #FUEL_ITEMS do
|
||||
if FUEL_ITEMS[i] == itemName then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local tier = parseGooTier(inspected.name)
|
||||
return false
|
||||
end
|
||||
|
||||
if not tier then
|
||||
error("expected a Just Dire Things goo block above the turtle, got " .. tostring(inspected.name))
|
||||
local function isFeedingItemForTier(itemName, gooTier)
|
||||
local feedingItems = FEEDING_ITEMS_BY_TIER[gooTier] or {}
|
||||
|
||||
for i = 1, #feedingItems do
|
||||
if feedingItems[i] == itemName then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return tier, inspected
|
||||
return false
|
||||
end
|
||||
|
||||
local function countItem(itemName)
|
||||
local count = 0
|
||||
|
||||
for slot = 1, 16 do
|
||||
local item = turtle.getItemDetail(slot)
|
||||
|
||||
if item and item.name == itemName then
|
||||
count = count + item.count
|
||||
end
|
||||
end
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
local function countFeedingItems(gooTier)
|
||||
local count = 0
|
||||
local feedingItems = FEEDING_ITEMS_BY_TIER[gooTier] or {}
|
||||
|
||||
for i = 1, #feedingItems do
|
||||
count = count + countItem(feedingItems[i])
|
||||
end
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
local function findItemSlot(itemName)
|
||||
@ -129,14 +192,6 @@ local function findItemSlot(itemName)
|
||||
return nil
|
||||
end
|
||||
|
||||
local function waitForInventory(message)
|
||||
if message then
|
||||
print(message)
|
||||
end
|
||||
|
||||
os.pullEvent("turtle_inventory")
|
||||
end
|
||||
|
||||
local function hasFreeSlot()
|
||||
for slot = 1, 16 do
|
||||
if turtle.getItemCount(slot) == 0 then
|
||||
@ -147,12 +202,6 @@ local function hasFreeSlot()
|
||||
return false
|
||||
end
|
||||
|
||||
local function ensureMiningSpace()
|
||||
while not hasFreeSlot() do
|
||||
waitForInventory("Inventory is full. Remove items to keep mining.")
|
||||
end
|
||||
end
|
||||
|
||||
local function getFuelLevel()
|
||||
local fuelLevel = turtle.getFuelLevel()
|
||||
|
||||
@ -185,6 +234,143 @@ local function findFuelSlot()
|
||||
return nil
|
||||
end
|
||||
|
||||
local function turnRight()
|
||||
turtle.turnRight()
|
||||
facing = (facing + 1) % 4
|
||||
end
|
||||
|
||||
local function turnLeft()
|
||||
turtle.turnLeft()
|
||||
facing = (facing + 3) % 4
|
||||
end
|
||||
|
||||
local function turnTo(direction)
|
||||
while facing ~= direction do
|
||||
local rightTurns = (direction - facing) % 4
|
||||
|
||||
if rightTurns == 3 then
|
||||
turnLeft()
|
||||
else
|
||||
turnRight()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function moveForward()
|
||||
if not turtle.forward() then
|
||||
return false
|
||||
end
|
||||
|
||||
local delta = DIRECTION_DELTAS[facing]
|
||||
position.x = position.x + delta.x
|
||||
position.z = position.z + delta.z
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function moveUp()
|
||||
if not turtle.up() then
|
||||
return false
|
||||
end
|
||||
|
||||
position.y = position.y + 1
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function moveDown()
|
||||
if not turtle.down() then
|
||||
return false
|
||||
end
|
||||
|
||||
position.y = position.y - 1
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function moveAxis(target, positiveDirection, negativeDirection, axis)
|
||||
while position[axis] ~= target do
|
||||
if position[axis] < target then
|
||||
turnTo(positiveDirection)
|
||||
else
|
||||
turnTo(negativeDirection)
|
||||
end
|
||||
|
||||
if not moveForward() then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function goTo(target)
|
||||
while position.y < target.y do
|
||||
if not moveUp() then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
while position.y > target.y do
|
||||
if not moveDown() then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
if not moveAxis(target.x, DIR_EAST, DIR_WEST, "x") then
|
||||
return false
|
||||
end
|
||||
|
||||
if not moveAxis(target.z, DIR_SOUTH, DIR_NORTH, "z") then
|
||||
return false
|
||||
end
|
||||
|
||||
if target.facing then
|
||||
turnTo(target.facing)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function mustGoTo(target, description)
|
||||
while not goTo(target) do
|
||||
print("Cannot reach " .. description .. ". Clear the path and waiting...")
|
||||
os.sleep(WAIT_SECONDS)
|
||||
end
|
||||
end
|
||||
|
||||
local function goHome()
|
||||
mustGoTo(HOME, "home/provider")
|
||||
end
|
||||
|
||||
local function goToGooCheck()
|
||||
mustGoTo(GOO_CHECK, "goo check position")
|
||||
end
|
||||
|
||||
local function inspectDirection(action)
|
||||
if action == "forward" then
|
||||
return turtle.inspect()
|
||||
elseif action == "up" then
|
||||
return turtle.inspectUp()
|
||||
elseif action == "down" then
|
||||
return turtle.inspectDown()
|
||||
end
|
||||
|
||||
error("unknown inspect action " .. tostring(action))
|
||||
end
|
||||
|
||||
local function placeDirection(action)
|
||||
if action == "forward" then
|
||||
return turtle.place()
|
||||
elseif action == "up" then
|
||||
return turtle.placeUp()
|
||||
elseif action == "down" then
|
||||
return turtle.placeDown()
|
||||
end
|
||||
|
||||
error("unknown place action " .. tostring(action))
|
||||
end
|
||||
|
||||
local function refuelFromInventory()
|
||||
local fuelLevel = getFuelLevel()
|
||||
|
||||
@ -219,6 +405,83 @@ local function refuelFromInventory()
|
||||
return consumedFuel
|
||||
end
|
||||
|
||||
local function isProviderBelow()
|
||||
local ok = turtle.inspectDown()
|
||||
|
||||
return ok
|
||||
end
|
||||
|
||||
local function pullFromProvider()
|
||||
goHome()
|
||||
|
||||
local pulled = false
|
||||
|
||||
for _ = 1, MAX_SUCK_ATTEMPTS do
|
||||
if not hasFreeSlot() then
|
||||
break
|
||||
end
|
||||
|
||||
if turtle.suckDown() then
|
||||
pulled = true
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return pulled
|
||||
end
|
||||
|
||||
local function shouldKeepItem(item, gooTier)
|
||||
if isFuelItem(item.name) then
|
||||
return true
|
||||
end
|
||||
|
||||
local processItem = PROCESS_ITEMS[item.name]
|
||||
|
||||
if processItem and processItem.tier <= gooTier then
|
||||
return true
|
||||
end
|
||||
|
||||
if isFeedingItemForTier(item.name, gooTier) then
|
||||
return countFeedingItems(gooTier) <= MIN_FEEDING_ITEMS
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function depositOutputs(gooTier)
|
||||
goHome()
|
||||
|
||||
local previousSlot = turtle.getSelectedSlot()
|
||||
|
||||
for slot = 1, 16 do
|
||||
local item = turtle.getItemDetail(slot)
|
||||
|
||||
if item and not shouldKeepItem(item, gooTier) then
|
||||
turtle.select(slot)
|
||||
|
||||
if turtle.dropDown() then
|
||||
print("Deposited " .. item.name .. ".")
|
||||
else
|
||||
print("Could not deposit " .. item.name .. ". Provider may be full.")
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
turtle.select(previousSlot)
|
||||
end
|
||||
|
||||
local function waitForProvider(message)
|
||||
if message then
|
||||
print(message)
|
||||
end
|
||||
|
||||
repeat
|
||||
os.sleep(WAIT_SECONDS)
|
||||
until pullFromProvider()
|
||||
end
|
||||
|
||||
local function ensureStartFuel()
|
||||
while true do
|
||||
local fuelLevel = getFuelLevel()
|
||||
@ -234,7 +497,7 @@ local function ensureStartFuel()
|
||||
return
|
||||
end
|
||||
|
||||
waitForInventory("Fuel is below " .. tostring(MIN_START_FUEL) .. ". Insert fuel to start.")
|
||||
waitForProvider("Fuel is below " .. tostring(MIN_START_FUEL) .. ". Add fuel to the provider below home.")
|
||||
end
|
||||
end
|
||||
|
||||
@ -252,7 +515,7 @@ local function ensureRuntimeFuel()
|
||||
fuelLevel = getFuelLevel()
|
||||
|
||||
while fuelLevel and fuelLevel < MIN_START_FUEL do
|
||||
waitForInventory("Fuel is below " .. tostring(MIN_START_FUEL) .. ". Insert fuel to continue.")
|
||||
waitForProvider("Fuel is below " .. tostring(MIN_START_FUEL) .. ". Add fuel to the provider below home.")
|
||||
refuelFromInventory()
|
||||
fuelLevel = getFuelLevel()
|
||||
end
|
||||
@ -300,23 +563,51 @@ local function findEligibleProcessSlot(gooTier)
|
||||
return nil
|
||||
end
|
||||
|
||||
local function inspectGoo()
|
||||
for i = 1, #GOO_CHECKS do
|
||||
local check = GOO_CHECKS[i]
|
||||
|
||||
if goTo(check) then
|
||||
local ok, inspected = inspectDirection(check.action)
|
||||
|
||||
if ok then
|
||||
local tier = parseGooTier(inspected.name)
|
||||
|
||||
if tier then
|
||||
lastGooTier = tier
|
||||
|
||||
return tier, inspected, check
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if lastGooTier then
|
||||
print("Cannot reach the goo to inspect it. Using last known tier " .. tostring(lastGooTier) .. ".")
|
||||
|
||||
return lastGooTier, { state = { alive = true } }, nil
|
||||
end
|
||||
|
||||
error("expected a reachable Just Dire Things goo block around the turtle")
|
||||
end
|
||||
|
||||
local function ensureGooAlive()
|
||||
while true do
|
||||
local gooTier, inspected = inspectGoo()
|
||||
local gooTier, inspected, check = inspectGoo()
|
||||
|
||||
if inspected.state and inspected.state.alive == true then
|
||||
if not check or inspected.state and inspected.state.alive == true then
|
||||
return gooTier
|
||||
end
|
||||
|
||||
local slot, item = findFeedingSlot(gooTier)
|
||||
|
||||
if not slot then
|
||||
waitForInventory("Goo tier " .. tostring(gooTier) .. " is not alive. Waiting for feeding item...")
|
||||
waitForProvider("Goo tier " .. tostring(gooTier) .. " is not alive. Add feeding items to the provider.")
|
||||
else
|
||||
turtle.select(slot)
|
||||
print("Goo tier " .. tostring(gooTier) .. " is not alive. Feeding with " .. item.name .. "...")
|
||||
|
||||
if not turtle.placeUp() then
|
||||
if not placeDirection(check.action) then
|
||||
print("Could not feed the goo. Waiting before retry...")
|
||||
os.sleep(WAIT_SECONDS)
|
||||
else
|
||||
@ -327,7 +618,7 @@ local function ensureGooAlive()
|
||||
end
|
||||
|
||||
local function selectProcessItem(gooTier)
|
||||
local slot, item, processItem = findEligibleProcessSlot(gooTier)
|
||||
local slot, item = findEligibleProcessSlot(gooTier)
|
||||
|
||||
if not slot then
|
||||
return nil
|
||||
@ -335,245 +626,207 @@ local function selectProcessItem(gooTier)
|
||||
|
||||
turtle.select(slot)
|
||||
|
||||
return item, processItem
|
||||
return item
|
||||
end
|
||||
|
||||
local function workTarget(inspectFn, digFn, placeFn, gooTier, targetName)
|
||||
local ok, inspected = inspectFn()
|
||||
|
||||
if ok then
|
||||
if isGooBlock(inspected.name) then
|
||||
return false
|
||||
end
|
||||
|
||||
if isProcessBlock(inspected.name) then
|
||||
return false
|
||||
end
|
||||
|
||||
print("Mining processed " .. targetName .. " block: " .. tostring(inspected.name))
|
||||
ensureMiningSpace()
|
||||
return digFn()
|
||||
local function inspectTarget(target)
|
||||
if target.action == "forward" then
|
||||
return turtle.inspect()
|
||||
elseif target.action == "up" then
|
||||
return turtle.inspectUp()
|
||||
elseif target.action == "down" then
|
||||
return turtle.inspectDown()
|
||||
end
|
||||
|
||||
local item = selectProcessItem(gooTier)
|
||||
error("unknown target action " .. tostring(target.action))
|
||||
end
|
||||
|
||||
if not item then
|
||||
local function digTarget(target)
|
||||
if target.action == "forward" then
|
||||
return turtle.dig()
|
||||
elseif target.action == "up" then
|
||||
return turtle.digUp()
|
||||
elseif target.action == "down" then
|
||||
return turtle.digDown()
|
||||
end
|
||||
|
||||
error("unknown target action " .. tostring(target.action))
|
||||
end
|
||||
|
||||
local function placeTarget(target)
|
||||
if target.action == "forward" then
|
||||
return turtle.place()
|
||||
elseif target.action == "up" then
|
||||
return turtle.placeUp()
|
||||
elseif target.action == "down" then
|
||||
return turtle.placeDown()
|
||||
end
|
||||
|
||||
error("unknown target action " .. tostring(target.action))
|
||||
end
|
||||
|
||||
local function ensureMiningSpace(gooTier)
|
||||
while not hasFreeSlot() do
|
||||
depositOutputs(gooTier)
|
||||
|
||||
if not hasFreeSlot() then
|
||||
print("Inventory is full and provider may be full. Waiting...")
|
||||
os.sleep(WAIT_SECONDS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function isTargetQueued(target)
|
||||
for i = 1, #placedTargets do
|
||||
if placedTargets[i] == target then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function removeQueuedTarget(index)
|
||||
table.remove(placedTargets, index)
|
||||
end
|
||||
|
||||
local function goToTarget(target)
|
||||
mustGoTo(target, target.name)
|
||||
end
|
||||
|
||||
local function mineQueuedTarget(gooTier)
|
||||
if #placedTargets == 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
print("Placing " .. item.name .. " on goo " .. targetName)
|
||||
return placeFn()
|
||||
end
|
||||
local target = placedTargets[1]
|
||||
|
||||
local function workHorizontalSide(gooTier, sideIndex)
|
||||
if not turtle.forward() then
|
||||
print("Cannot move to horizontal side " .. tostring(sideIndex) .. ". Waiting...")
|
||||
goToTarget(target)
|
||||
ensureGooAlive()
|
||||
goToTarget(target)
|
||||
|
||||
local ok, inspected = inspectTarget(target)
|
||||
|
||||
if not ok then
|
||||
print("Queued " .. target.name .. " is empty.")
|
||||
removeQueuedTarget(1)
|
||||
return true
|
||||
end
|
||||
|
||||
if isProcessBlock(inspected.name) then
|
||||
return false
|
||||
end
|
||||
|
||||
local changed = workTarget(turtle.inspectUp, turtle.digUp, turtle.placeUp, gooTier, "side")
|
||||
|
||||
if not turtle.back() then
|
||||
error("could not return below the goo")
|
||||
if isGooBlock(inspected.name) then
|
||||
removeQueuedTarget(1)
|
||||
return true
|
||||
end
|
||||
|
||||
return changed
|
||||
print("Mining processed " .. target.name .. " block: " .. tostring(inspected.name))
|
||||
ensureMiningSpace(gooTier)
|
||||
goToTarget(target)
|
||||
|
||||
if digTarget(target) then
|
||||
removeQueuedTarget(1)
|
||||
return true
|
||||
end
|
||||
|
||||
print("Could not mine " .. target.name .. ".")
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function workHorizontalSides(gooTier)
|
||||
local changed = false
|
||||
local function placeAvailableTarget(gooTier)
|
||||
for i = 1, #TARGETS do
|
||||
local target = TARGETS[i]
|
||||
|
||||
for sideIndex = 1, 4 do
|
||||
changed = workHorizontalSide(gooTier, sideIndex) or changed
|
||||
turtle.turnRight()
|
||||
end
|
||||
if not isTargetQueued(target) then
|
||||
goToTarget(target)
|
||||
ensureGooAlive()
|
||||
goToTarget(target)
|
||||
|
||||
return changed
|
||||
end
|
||||
local ok, inspected = inspectTarget(target)
|
||||
|
||||
-- Returns `changed, reachedTop`. `reachedTop` is true only once we have actually
|
||||
-- climbed above the goo and inspected its top face, so the caller can stop trying
|
||||
-- the remaining sides; it stays false when this side is blocked or unclimbable.
|
||||
local function workTopFromCurrentSide(gooTier)
|
||||
if not turtle.forward() then
|
||||
return false, false
|
||||
end
|
||||
if ok then
|
||||
if not isProcessBlock(inspected.name) and not isGooBlock(inspected.name) then
|
||||
print("Mining existing " .. target.name .. " block: " .. tostring(inspected.name))
|
||||
ensureMiningSpace(gooTier)
|
||||
goToTarget(target)
|
||||
|
||||
-- Only the presence of a block above matters here; ignore the inspect metadata.
|
||||
local sideOccupied = turtle.inspectUp()
|
||||
local changed = false
|
||||
local reachedTop = false
|
||||
|
||||
if not sideOccupied then
|
||||
if turtle.up() then
|
||||
if turtle.up() then
|
||||
turnAround()
|
||||
changed = workTarget(turtle.inspect, turtle.dig, turtle.place, gooTier, "top")
|
||||
reachedTop = true
|
||||
turnAround()
|
||||
|
||||
if not turtle.down() then
|
||||
error("could not descend from top placement position")
|
||||
if digTarget(target) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
else
|
||||
print("Cannot climb high enough to work on the top side.")
|
||||
end
|
||||
|
||||
if not turtle.down() then
|
||||
error("could not return to side floor position")
|
||||
end
|
||||
else
|
||||
print("Cannot climb to work on the top side.")
|
||||
end
|
||||
end
|
||||
|
||||
if not turtle.back() then
|
||||
error("could not return below the goo after top side check")
|
||||
end
|
||||
|
||||
return changed, reachedTop
|
||||
end
|
||||
|
||||
local function workTop(gooTier)
|
||||
local changed = false
|
||||
local done = false
|
||||
|
||||
-- Iterate all four sides so the four turnRight calls net to zero (facing is
|
||||
-- restored), but skip the climb once the single top face has been handled.
|
||||
for _ = 1, 4 do
|
||||
if not done then
|
||||
local sideChanged, reachedTop = workTopFromCurrentSide(gooTier)
|
||||
changed = sideChanged or changed
|
||||
done = sideChanged or reachedTop
|
||||
end
|
||||
|
||||
turtle.turnRight()
|
||||
end
|
||||
|
||||
return changed
|
||||
end
|
||||
|
||||
local function turnLeft(times)
|
||||
for _ = 1, times do
|
||||
turtle.turnLeft()
|
||||
end
|
||||
end
|
||||
|
||||
local function moveToSideFacingCenter()
|
||||
for turns = 0, 3 do
|
||||
if turtle.forward() then
|
||||
turnAround()
|
||||
return turns
|
||||
end
|
||||
|
||||
turtle.turnRight()
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function returnFromBottomSide(turns)
|
||||
if not turtle.forward() then
|
||||
return false
|
||||
end
|
||||
|
||||
turnAround()
|
||||
turnLeft(turns)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function workBottom()
|
||||
local gooTier = ensureGooAlive()
|
||||
|
||||
local turns = moveToSideFacingCenter()
|
||||
|
||||
if not turns then
|
||||
print("Cannot move to a side position for bottom placement. Waiting...")
|
||||
return false
|
||||
end
|
||||
|
||||
local changed = false
|
||||
|
||||
-- The bottom face is worked as one atomic round-trip (place -> wait -> mine ->
|
||||
-- return) rather than fire-and-forget like the other faces, because the turtle
|
||||
-- must vacate and then reclaim its home cell within a single pass.
|
||||
while true do
|
||||
local ok, inspected = turtle.inspect()
|
||||
|
||||
if not ok then
|
||||
if changed then
|
||||
if returnFromBottomSide(turns) then
|
||||
return changed
|
||||
end
|
||||
|
||||
print("Center position is clear, but the turtle could not return. Waiting...")
|
||||
os.sleep(WAIT_SECONDS)
|
||||
else
|
||||
local item = selectProcessItem(gooTier)
|
||||
|
||||
if item then
|
||||
print("Placing " .. item.name .. " on goo bottom")
|
||||
|
||||
if turtle.place() then
|
||||
changed = true
|
||||
else
|
||||
print("Could not place bottom block.")
|
||||
end
|
||||
elseif returnFromBottomSide(turns) then
|
||||
return changed
|
||||
else
|
||||
print("Center position is blocked. Waiting...")
|
||||
os.sleep(WAIT_SECONDS)
|
||||
if not item then
|
||||
return false
|
||||
end
|
||||
end
|
||||
elseif isProcessBlock(inspected.name) then
|
||||
print("Bottom block is still processing. Waiting outside...")
|
||||
os.sleep(WAIT_SECONDS)
|
||||
elseif isGooBlock(inspected.name) then
|
||||
error("unexpected goo block in the turtle center position")
|
||||
else
|
||||
print("Mining processed bottom block: " .. tostring(inspected.name))
|
||||
ensureMiningSpace()
|
||||
|
||||
if turtle.dig() then
|
||||
changed = true
|
||||
else
|
||||
print("Could not mine bottom block. Waiting...")
|
||||
os.sleep(WAIT_SECONDS)
|
||||
print("Placing " .. item.name .. " on goo " .. target.name)
|
||||
|
||||
if placeTarget(target) then
|
||||
placedTargets[#placedTargets + 1] = target
|
||||
return true
|
||||
end
|
||||
|
||||
print("Could not place " .. target.name .. ".")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
print("goo started. Place the turtle directly below the goo block.")
|
||||
local function waitAtOldestTarget()
|
||||
if #placedTargets == 0 then
|
||||
goToGooCheck()
|
||||
else
|
||||
goToTarget(placedTargets[1])
|
||||
end
|
||||
|
||||
if not hasPickaxeEquipped() then
|
||||
error("goo requires a turtle with a pickaxe equipped")
|
||||
print("Waiting for goo processing...")
|
||||
os.sleep(WAIT_SECONDS)
|
||||
end
|
||||
|
||||
ensureStartFuel()
|
||||
local function startup()
|
||||
print("goo started. Layout: provider below turtle, goo two blocks ahead, turtle facing goo.")
|
||||
|
||||
if not hasPickaxeEquipped() then
|
||||
error("goo requires a turtle with a pickaxe equipped")
|
||||
end
|
||||
|
||||
if not isProviderBelow() then
|
||||
error("goo requires a provider/deposit barrel below the turtle")
|
||||
end
|
||||
|
||||
pullFromProvider()
|
||||
ensureStartFuel()
|
||||
end
|
||||
|
||||
startup()
|
||||
|
||||
while true do
|
||||
ensureRuntimeFuel()
|
||||
|
||||
local gooTier = ensureGooAlive()
|
||||
-- Also relied on for its side effect: emits the "requires goo tier X" warnings
|
||||
-- for blocks the current tier cannot process yet.
|
||||
local hasEligibleBlocks = findEligibleProcessSlot(gooTier) ~= nil
|
||||
depositOutputs(gooTier)
|
||||
pullFromProvider()
|
||||
ensureRuntimeFuel()
|
||||
|
||||
local changed = false
|
||||
|
||||
changed = workTop(gooTier) or changed
|
||||
changed = workHorizontalSides(gooTier) or changed
|
||||
changed = workBottom() or changed
|
||||
gooTier = ensureGooAlive()
|
||||
local changed = mineQueuedTarget(gooTier)
|
||||
|
||||
if not changed then
|
||||
if hasEligibleBlocks then
|
||||
print("No free goo side found. Waiting for processing...")
|
||||
os.sleep(WAIT_SECONDS)
|
||||
changed = placeAvailableTarget(gooTier)
|
||||
end
|
||||
|
||||
if not changed then
|
||||
if findEligibleProcessSlot(gooTier) then
|
||||
waitAtOldestTarget()
|
||||
else
|
||||
waitForInventory("No eligible process block found. Waiting for inventory...")
|
||||
waitForProvider("No eligible process block found. Add inputs to the provider below home.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
Reference in New Issue
Block a user