chore: remove cube and goo programs

This commit is contained in:
Guillaume ARM 2026-06-07 19:45:00 +02:00
parent 9dd4455203
commit a373d140e8
8 changed files with 7 additions and 1316 deletions

View File

@ -33,27 +33,16 @@ Three layers, bottom-up:
- `9` — ping
- `10` — router / default routing channel
- `64` — cube (deployment/control)
These are duplicated as local constants across files; keep them in sync when changing.
## The `cube` deployment system
`cube` (client `programs/cube.lua`, server `servers/cube-server.lua`) manages a cluster of "cube" machines over channel 64:
- `cube ls` — list reachable cubes (broadcast ping; each replies with its boot command). `*` marks the local machine.
- `cube deploy` — walk the local filesystem (skipping `IGNORED_PATHS`: `/rom`, `/.cubeboot`, `/.git`, `/.gitignore`, `/startup.lua`), send every file to each remote cube via `deploy-file`, then reboot it.
- `cube set-boot <machineId> [command]` — write/clear the remote's `/.cubeboot`, then reboot. Empty command deletes the boot hook.
- `cube reboot <machineId>` — remote reboot.
- `.cubeboot` holds a per-machine startup shell command, run by `servers/cube-boot.lua` at boot.
## Boot flow
`startup/servers.lua` is the entry point on each machine: it adds `/programs` to `shell.path`, then `parallel.waitForAll` runs an interactive shell alongside every server in `SERVERS`. When all stop, it reboots.
## CraftOS-PC emulation
`startup/servers.lua` detects the `periphemu` global and, when present, creates an emulated modem plus (on computer 0) a few emulated peer/router computers. Code guards CraftOS-PC quirks with `if periphemu then ... end` (e.g. `os.sleep(0.5)` after reboots in `cube.lua` to avoid crashes). Preserve these guards.
`startup/servers.lua` detects the `periphemu` global and, when present, creates an emulated modem plus (on computer 0) a few emulated peer/router computers. Preserve these guards.
## Installation / distribution

View File

@ -13,14 +13,10 @@ wget run https://raw.githubusercontent.com/guillaumearm/cc-libs/master/install.l
All servers are automatically started at boot.
- `/servers/ping-server`: allows a machine to respond to a `ping` command.
- `/servers/cube-server`: allows a machine to be controllable via `cube`.
- `/servers/cube-boot.lua`: `cube` boot script.
## Programs
- `router`: routes messages. You need to set up a router to use all `apis/net`-based programs and libraries.
- `ping`: pings machines using `apis/net`.
- `cube`: cube client for deployment. Use the `cube help` command for more details.
- `goo`: turtle program for Just Dire Things goo block processing.
## Development
See [DEVELOPMENT.md](./DEVELOPMENT.md) for development setup and workflow.

View File

@ -1,17 +1,13 @@
local _VERSION = '2.0.3'
local _VERSION = '2.0.4'
local LIST_FILES = {
-- startup
'startup/servers.lua',
-- servers
'servers/ping-server.lua',
'servers/cube-server.lua',
'servers/cube-boot.lua',
-- programs
'programs/router.lua', -- router is not in servers folder because he's not ran on every machines
'programs/ping.lua',
'programs/cube.lua',
'programs/goo.lua',
'programs/upgrade.lua',
-- apis
'apis/net.lua',
@ -24,6 +20,10 @@ fs.delete('ping.lua') -- replaced by `programs/ping.lua`
fs.delete('cube.lua') -- replaced by `programs/cube.lua`
fs.delete('router.lua') -- replaced by `programs/router.lua`
fs.delete('servers/cube-startup.lua'); -- replaced by `servers/cube-boot.lua`
fs.delete('programs/cube.lua');
fs.delete('programs/goo.lua');
fs.delete('servers/cube-server.lua');
fs.delete('servers/cube-boot.lua');
local REPO_PREFIX = 'https://raw.githubusercontent.com/guillaumearm/cc-libs/master/'

View File

@ -1,342 +0,0 @@
local _VERSION = '2.3.0';
local CUBE_CHANNEL = 64;
local net = require('/apis/net')();
local args = table.pack(...);
local cubeCommand = args[1];
local firstArg = args[2];
local secondArg = args[3];
local function getRemainingArgs(startIndex)
local remainingArgs = {};
for i = startIndex, args.n do
table.insert(remainingArgs, tostring(args[i]));
end
return table.concat(remainingArgs, ' ');
end
local IGNORED_PATHS = {
['/rom'] = true,
['/.cubeboot'] = true,
['/.git'] = true,
['/.gitignore'] = true,
['/startup.lua'] = true,
}
local function isValidPath(givenPath)
return not IGNORED_PATHS[givenPath]
end
local function getAllFiles(basePath, result)
basePath = basePath or '/'
result = result or {};
local fileNames = fs.list(basePath)
for i = 1, #fileNames do
local filePath = basePath .. fileNames[i];
local valid = isValidPath(filePath);
if valid and fs.isDir(filePath) then
getAllFiles(filePath .. '/', result);
elseif valid and not fs.isDir(filePath) then
table.insert(result, filePath)
end
end
return result;
end
local function readFile(path)
local file = fs.open(path, "r");
if not file then
return nil;
end
local contents = file.readAll()
file.close()
return contents
end
--- Pads str to length len with char from right
local leftPad = function(str, len, char)
if char == nil then char = ' ' end
local nbRepetition = len - #str;
if nbRepetition > 0 then
return str .. string.rep(char, len - #str)
end
return str;
end
local function getRow(margin, str1, str2, str3)
margin = margin or '';
local row1 = leftPad(margin .. tostring(str1 or ''), 8, ' ')
local row2 = leftPad(tostring(str2 or ''), 16, ' ')
local row3 = leftPad(tostring(str3 or ''), 6, ' ')
return row1 .. row2 .. row3;
end
local function isFlag(name)
return function(arg)
return arg == '-' .. name or arg == '--' .. name;
end
end
local isHelpFlag = isFlag('help');
local isVersionFlag = isFlag('version');
local function printUsage()
print('cube usage:')
print();
print('\t\t\tcube ls');
print('\t\t\tcube configure');
print('\t\t\tcube set-boot <machineId> [command]')
print('\t\t\tcube reboot <machineId>')
print('\t\t\tcube deploy')
print('\t\t\tcube version')
print('\t\t\tcube help <command>')
end
local function printUsageCommand(commandName)
local function setBootUsage()
print('\t\t\tcube set-boot <machineId> [command]')
print('Setup a startup shell command on a remote cube.')
end
local USAGES = {
ls = function()
print('\t\t\tcube ls');
print('Print all available cubes in the cluster.')
end,
configure = function()
print('\t\t\tcube configure');
print('Setup remote slave cubes.')
end,
["set-boot"] = setBootUsage,
["setboot"] = setBootUsage,
["set-start"] = setBootUsage,
["setstart"] = setBootUsage,
["set-startup"] = setBootUsage,
["setstartup"] = setBootUsage,
reboot = function()
print('\t\t\tcube reboot <machineId>')
print('Reboot a cube machine.');
end,
deploy = function()
print('\t\t\tcube deploy')
print('Transfer files on all slave cubes.')
end,
version = function()
print('\t\t\tcube version')
print('Print the program version.')
end,
help = function()
print('\t\t\tcube help <command>')
print('Print help on commands.')
end,
}
local usageFn = USAGES[commandName]
if not usageFn then
return printUsage();
end
return usageFn();
end
if cubeCommand == nil or cubeCommand == '' or isHelpFlag(cubeCommand) then
printUsage();
return;
end
------------
-- reboot --
------------
local function rebootCommand(machineId, silentReboot)
if not machineId or machineId == '' then
printUsageCommand('reboot');
return;
end
local ok, results, packets = net.sendMultipleRequests(CUBE_CHANNEL, 'reboot', true, machineId);
if not ok then
error(results);
end
for k in ipairs(results) do
local packet = packets[k];
if silentReboot ~= true then
print('reboot machine \'' .. tostring(packet.sourceId) .. '\'');
end
end
end
--------------
-- set-boot --
--------------
local function setBootCommand(machineId, shellCommand)
if not machineId then
printUsageCommand('set-boot');
return;
end
local ok, results, packets = net.sendMultipleRequests(CUBE_CHANNEL, 'set-boot', shellCommand, machineId);
if not ok then
error(results);
end
for k in ipairs(results) do
local packet = packets[k];
if shellCommand == nil or shellCommand == '' then
print('boot DELETED');
else
print('boot UPDATED');
end
rebootCommand(packet.sourceId, true);
-- prevent CraftOS-PC crashes
if periphemu then
os.sleep(0.5)
end
end
end
------------
-- deploy --
------------
local function deployCommand()
local allFiles = getAllFiles()
-- 1. get all machine ids (except the current one)
local ok, results, packets = net.sendMultipleRequests(CUBE_CHANNEL, 'ping', 'ping');
if not ok then
error(results);
end
local machineIds = {};
local localComputerId = os.getComputerID();
for k in ipairs(results) do
local packet = packets[k];
if packet.sourceId ~= localComputerId then
table.insert(machineIds, packet.sourceId);
end
end
-- 2. transfer files on all concerned machines
for machineIndex = 1, #machineIds do
local machineId = machineIds[machineIndex];
local fileTransfered = 0;
for i = 1, #allFiles do
local filePath = allFiles[i];
local fileContent = readFile(filePath)
local transferOk, res = net.sendRequest(CUBE_CHANNEL, 'deploy-file', { path = filePath, content = fileContent }, machineId);
if transferOk and res then
fileTransfered = fileTransfered + 1;
else
print('Error transfering file \'' .. filePath .. '\'');
end
end
print(tostring(fileTransfered) .. ' file(s) transfered on machine ' .. tostring(machineId))
rebootCommand(machineId, true);
-- prevent CraftOS-PC crashes
if periphemu then
os.sleep(0.5)
end
end
end
local COMMANDS = {
ls = function()
local ok, results, packets = net.sendMultipleRequests(CUBE_CHANNEL, 'ping', 'ping');
if not ok then
error(results);
end
-- print('ID LABEL\t\t\t\tSTARTUP');
print(getRow(' ', 'ID', 'LABEL', 'BOOT'))
print('--------------------------------------------')
local localMachineId = os.getComputerID();
for k in ipairs(results) do
local result = results[k];
local packet = packets[k];
local prefix = ' ';
if packet.sourceId == localMachineId then
prefix = '* '
end
print(getRow(prefix, packet.sourceId, packet.sourceLabel, result.startup))
end
end,
configure = function()
print('not implemented yet.');
end,
["set-boot"] = setBootCommand,
["setboot"] = setBootCommand,
["set-start"] = setBootCommand,
["setstart"] = setBootCommand,
["set-startup"] = setBootCommand,
["setstartup"] = setBootCommand,
reboot = rebootCommand,
deploy = deployCommand,
version = function()
print('cube client v' .. _VERSION);
end,
help = function(commandName)
printUsageCommand(commandName);
end
}
local cmd;
if isVersionFlag(cubeCommand) then
cmd = COMMANDS.version;
else
cmd = COMMANDS[cubeCommand];
end
if not cmd then
printUsage();
return;
end
if (isHelpFlag(firstArg)) then
printUsageCommand(cubeCommand);
return;
end
if cmd == setBootCommand then
cmd(firstArg, getRemainingArgs(3));
else
cmd(firstArg, secondArg);
end

View File

@ -1,832 +0,0 @@
local _VERSION = "1.0.0"
local args = table.pack(...)
local command = args[1]
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",
"justdirethings:coal_t3",
"justdirethings:coal_t2",
"justdirethings:coal_t1",
"minecraft:coal",
}
local PROCESS_ITEMS = {
["minecraft:iron_block"] = { tier = 1 },
["minecraft:coal_block"] = { tier = 1 },
["mekanism:block_charcoal"] = { tier = 1 },
["justdirethings:coalblock_t1"] = { tier = 1 },
["justdirethings:coalblock_t2"] = { tier = 2 },
["justdirethings:coalblock_t3"] = { tier = 3 },
["justdirethings:coalblock_t4"] = { tier = 4 },
["minecraft:gold_block"] = { tier = 2 },
["minecraft:diamond_block"] = { tier = 3 },
["minecraft:netherite_block"] = { tier = 4 },
}
local FEEDING_ITEMS_BY_TIER = {
[1] = { "minecraft:sugar", "minecraft:rotten_flesh" },
[2] = { "minecraft:nether_wart" },
[3] = { "minecraft:chorus_fruit" },
[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)
return arg == "-" .. name or arg == "--" .. name
end
end
local isHelpFlag = isFlag("help")
local isVersionFlag = isFlag("version")
local function printUsage()
print("goo usage:")
print()
print("\t\t\tgoo start")
print("\t\t\tgoo version")
print("\t\t\tgoo help")
end
if command == "version" or isVersionFlag(command) then
print("goo v" .. _VERSION)
return
end
if command == nil or command == "" or command == "help" or isHelpFlag(command) then
printUsage()
return
end
if command ~= "start" then
printUsage()
return
end
if not turtle then
error("goo must be run on a turtle")
end
local function hasPickaxeEquipped()
local left = turtle.getEquippedLeft()
local right = turtle.getEquippedRight()
return (left and string.match(left.name or "", "_pickaxe$") ~= nil)
or (right and string.match(right.name or "", "_pickaxe$") ~= nil)
end
local function parseGooTier(blockName)
local tier = string.match(blockName or "", "^" .. GOO_BLOCK_PREFIX .. "(%d+)$")
return tonumber(tier)
end
local function isGooBlock(blockName)
return parseGooTier(blockName) ~= nil
end
local function isProcessBlock(blockName)
return PROCESS_ITEMS[blockName] ~= nil
end
local function isFuelItem(itemName)
for i = 1, #FUEL_ITEMS do
if FUEL_ITEMS[i] == itemName then
return true
end
end
return false
end
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 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)
for slot = 1, 16 do
local item = turtle.getItemDetail(slot)
if item and item.name == itemName then
return slot, item
end
end
return nil
end
local function hasFreeSlot()
for slot = 1, 16 do
if turtle.getItemCount(slot) == 0 then
return true
end
end
return false
end
local function getFuelLevel()
local fuelLevel = turtle.getFuelLevel()
if fuelLevel == "unlimited" then
return nil
end
return fuelLevel
end
local function getRefuelTarget()
local fuelLimit = turtle.getFuelLimit()
if fuelLimit == "unlimited" or fuelLimit >= REFUEL_THRESHOLD then
return REFUEL_THRESHOLD
end
return fuelLimit
end
local function findFuelSlot()
for i = 1, #FUEL_ITEMS do
local slot, item = findItemSlot(FUEL_ITEMS[i])
if slot then
return slot, item
end
end
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()
if not fuelLevel or fuelLevel >= getRefuelTarget() then
return false
end
local previousSlot = turtle.getSelectedSlot()
local consumedFuel = false
while fuelLevel < getRefuelTarget() do
local slot, item = findFuelSlot()
if not slot then
break
end
turtle.select(slot)
if turtle.refuel(1) then
consumedFuel = true
print("Refueled with " .. item.name .. ". Fuel: " .. tostring(turtle.getFuelLevel()))
fuelLevel = getFuelLevel()
else
print("Could not refuel with " .. item.name .. ".")
break
end
end
turtle.select(previousSlot)
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()
if not fuelLevel or fuelLevel >= MIN_START_FUEL then
return
end
refuelFromInventory()
fuelLevel = getFuelLevel()
if not fuelLevel or fuelLevel >= MIN_START_FUEL then
return
end
waitForProvider("Fuel is below " .. tostring(MIN_START_FUEL) .. ". Add fuel to the provider below home.")
end
end
local function ensureRuntimeFuel()
local fuelLevel = getFuelLevel()
if not fuelLevel then
return
end
if fuelLevel < getRefuelTarget() then
refuelFromInventory()
end
fuelLevel = getFuelLevel()
while fuelLevel and fuelLevel < MIN_START_FUEL do
waitForProvider("Fuel is below " .. tostring(MIN_START_FUEL) .. ". Add fuel to the provider below home.")
refuelFromInventory()
fuelLevel = getFuelLevel()
end
end
local function findFeedingSlot(gooTier)
local feedingItems = FEEDING_ITEMS_BY_TIER[gooTier] or {}
for i = 1, #feedingItems do
local slot, item = findItemSlot(feedingItems[i])
if slot then
return slot, item
end
end
return nil
end
local function findEligibleProcessSlot(gooTier)
for slot = 1, 16 do
local item = turtle.getItemDetail(slot)
local processItem = item and PROCESS_ITEMS[item.name]
if processItem then
if processItem.tier <= gooTier then
return slot, item, processItem
end
local logKey = item.name .. ":" .. tostring(gooTier)
if not loggedBlockedItems[logKey] then
print(
item.name
.. " requires goo tier "
.. tostring(processItem.tier)
.. ", current tier is "
.. tostring(gooTier)
)
loggedBlockedItems[logKey] = true
end
end
end
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, check = inspectGoo()
if not check or inspected.state and inspected.state.alive == true then
return gooTier
end
local slot, item = findFeedingSlot(gooTier)
if not slot then
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 placeDirection(check.action) then
print("Could not feed the goo. Waiting before retry...")
os.sleep(WAIT_SECONDS)
else
os.sleep(1)
end
end
end
end
local function selectProcessItem(gooTier)
local slot, item = findEligibleProcessSlot(gooTier)
if not slot then
return nil
end
turtle.select(slot)
return item
end
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
error("unknown target action " .. tostring(target.action))
end
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
local target = placedTargets[1]
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
if isGooBlock(inspected.name) then
removeQueuedTarget(1)
return true
end
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 placeAvailableTarget(gooTier)
for i = 1, #TARGETS do
local target = TARGETS[i]
if not isTargetQueued(target) then
goToTarget(target)
ensureGooAlive()
goToTarget(target)
local ok, inspected = inspectTarget(target)
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)
if digTarget(target) then
return true
end
end
else
local item = selectProcessItem(gooTier)
if not item then
return false
end
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
local function waitAtOldestTarget()
if #placedTargets == 0 then
goToGooCheck()
else
goToTarget(placedTargets[1])
end
print("Waiting for goo processing...")
os.sleep(WAIT_SECONDS)
end
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()
depositOutputs(gooTier)
pullFromProvider()
ensureRuntimeFuel()
gooTier = ensureGooAlive()
local changed = mineQueuedTarget(gooTier)
if not changed then
changed = placeAvailableTarget(gooTier)
end
if not changed then
if findEligibleProcessSlot(gooTier) then
waitAtOldestTarget()
else
waitForProvider("No eligible process block found. Add inputs to the provider below home.")
end
end
end

View File

@ -1,28 +0,0 @@
local _VERSION = '2.0.0';
local function trim(s)
return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
end
local function readFile(path)
local file = fs.open(path, "r");
if not file then
return nil;
end
local contents = file.readAll()
file.close()
return contents
end
local startupCommand = trim(readFile('.cubeboot') or "");
if startupCommand ~= "" then
print('cube-boot v' .. _VERSION .. ': execute \'' .. startupCommand .. '\'...');
shell.run(startupCommand);
else
print('cube-startup v' .. _VERSION .. ' no startup command detected.')
end

View File

@ -1,90 +0,0 @@
local _VERSION = '2.1.0';
local net = require('/apis/net')();
local CUBE_CHANNEL = 64;
local function trim(s)
return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
end
local function readFile(path)
local file = fs.open(path, "r");
if not file then
return nil;
end
local contents = file.readAll()
file.close()
return contents
end
local function writeFile(path, content)
local file = fs.open(path, "w");
if not file then
return false;
end
file.write(content)
file.close();
return true;
end
local function ensureParentDir(path)
local parentPath = string.match(path, '^(.+)/[^/]+$');
if parentPath and parentPath ~= '' and not fs.exists(parentPath) then
fs.makeDir(parentPath);
end
end
local function getStartupCommand()
return trim(readFile('.cubeboot') or "")
end
-- ping event
net.listenRequest(CUBE_CHANNEL, "ping", function(_, reply)
local startupCommand = getStartupCommand();
reply({ startup = startupCommand });
end)
-- reboot event
net.listenRequest(CUBE_CHANNEL, "reboot", function(_, reply)
reply(true);
os.sleep(0.2)
os.reboot()
end)
-- set-boot event
net.listenRequest(CUBE_CHANNEL, "set-boot", function(startupCommand, reply)
if startupCommand == nil or startupCommand == '' then
fs.delete('/.cubeboot');
reply(true);
return;
end
local res = writeFile('/.cubeboot', startupCommand);
reply(res);
end)
-- deploy-file event
net.listenRequest(CUBE_CHANNEL, "deploy-file", function(payload, reply)
if type(payload) ~= 'table' or type(payload.path) ~= 'string' or type(payload.content) ~= 'string' then
reply(false);
return;
end
ensureParentDir(payload.path);
reply(writeFile(payload.path, payload.content));
end)
print('cube-server v' .. _VERSION .. ' started.')
-- start event loop
net.startLoop();

View File

@ -1,9 +1,7 @@
local _VERSION = '1.1.1'
local _VERSION = '1.1.2'
local SERVERS = {
"servers/ping-server",
"servers/cube-server.lua",
"servers/cube-boot.lua",
};
local function init()