From ffeaf795324afcbb689002ebb0b6fb8c956209c2 Mon Sep 17 00:00:00 2001 From: Trap Date: Sun, 31 May 2026 01:37:19 +0200 Subject: [PATCH] feat: add goo v1 --- .luacheckrc | 1 + README.md | 3 +- install.lua | 3 +- programs/goo.lua | 399 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 404 insertions(+), 2 deletions(-) create mode 100644 programs/goo.lua diff --git a/.luacheckrc b/.luacheckrc index a67133c..a107025 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -23,6 +23,7 @@ stds.cc = { "vector", "commands", "disk", + "turtle", "periphemu", -- CraftOS-PC emulator only "read", "sleep", diff --git a/README.md b/README.md index dc0fe9c..6abac5d 100644 --- a/README.md +++ b/README.md @@ -19,4 +19,5 @@ All servers are automatically started at boot ## Programs - `router`: route messages (you need to setup a router to be able to use all `apis/net` based programs and libs) - `ping` : ping machines (use `apis/net`) -- `cube`: cube client for deployment (use `cube help` command for more details) \ No newline at end of file +- `cube`: cube client for deployment (use `cube help` command for more details) +- `goo`: turtle program for Just Dire Things goo block processing. diff --git a/install.lua b/install.lua index 9b95bc3..a989505 100644 --- a/install.lua +++ b/install.lua @@ -1,4 +1,4 @@ -local _VERSION = '2.0.1' +local _VERSION = '2.0.2' local LIST_FILES = { -- startup @@ -11,6 +11,7 @@ local LIST_FILES = { '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', -- apis 'apis/net.lua', 'apis/eventloop.lua', diff --git a/programs/goo.lua b/programs/goo.lua new file mode 100644 index 0000000..70ee5ba --- /dev/null +++ b/programs/goo.lua @@ -0,0 +1,399 @@ +local _VERSION = '0.1.0'; + +local args = table.pack(...); +local command = args[1]; + +local GOO_BLOCK_PREFIX = 'justdirethings:gooblock_tier'; +local WAIT_SECONDS = 2; + +local PROCESS_ITEMS = { + ['minecraft:iron_block'] = { tier = 1, label = 'iron' }, + ['minecraft:coal_block'] = { tier = 1, label = 'coal' }, + ['mekanism:block_charcoal'] = { tier = 1, label = 'charcoal' }, + ['minecraft:gold_block'] = { tier = 2, label = 'gold' }, + ['minecraft:diamond_block'] = { tier = 3, label = 'diamond' }, + ['minecraft:netherite_block'] = { tier = 4, label = 'netherite' }, +}; + +local FEEDING_ITEMS_BY_TIER = { + [1] = { 'minecraft:sugar', 'minecraft:rotten_flesh' }, + [2] = { 'minecraft:nether_wart' }, + [3] = { 'minecraft:chorus_fruit' }, + [4] = { 'minecraft:sculk' }, +}; + +local loggedBlockedItems = {}; + +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 turnAround() + turtle.turnRight(); + turtle.turnRight(); +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 inspectGoo() + local ok, inspected = turtle.inspectUp(); + + if not ok then + error('expected a Just Dire Things goo block above the turtle'); + end + + local tier = parseGooTier(inspected.name); + + if not tier then + error('expected a Just Dire Things goo block above the turtle, got ' .. tostring(inspected.name)); + end + + return tier, inspected; +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 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 ensureGooAlive() + while true do + local gooTier, inspected = inspectGoo(); + + if inspected.state and inspected.state.alive == true then + return gooTier; + end + + local slot, item = findFeedingSlot(gooTier); + + if not slot then + print('Goo tier ' .. tostring(gooTier) .. ' is not alive. Waiting for feeding item...'); + os.sleep(WAIT_SECONDS); + else + turtle.select(slot); + print('Goo tier ' .. tostring(gooTier) .. ' is not alive. Feeding with ' .. item.name .. '...'); + + if not turtle.placeUp() 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, processItem = findEligibleProcessSlot(gooTier); + + if not slot then + return nil; + end + + turtle.select(slot); + + return item, processItem; +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)); + return digFn(); + end + + local item = selectProcessItem(gooTier); + + if not item then + return false; + end + + print('Placing ' .. item.name .. ' on goo ' .. targetName); + return placeFn(); +end + +local function workHorizontalSide(gooTier, sideIndex) + if not turtle.forward() then + print('Cannot move to horizontal side ' .. tostring(sideIndex) .. '. Waiting...'); + 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'); + end + + return changed; +end + +local function workHorizontalSides(gooTier) + local changed = false; + + for sideIndex = 1, 4 do + changed = workHorizontalSide(gooTier, sideIndex) or changed; + turtle.turnRight(); + end + + return changed; +end + +local function workTopFromCurrentSide(gooTier) + if not turtle.forward() then + return false; + end + + local sideOccupied = turtle.inspectUp(); + local changed = false; + + if not sideOccupied then + if turtle.up() then + if turtle.up() then + turnAround(); + changed = workTarget(turtle.inspect, turtle.dig, turtle.place, gooTier, 'top'); + turnAround(); + + if not turtle.down() then + error('could not descend from top placement position'); + 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; +end + +local function workTop(gooTier) + local changed = false; + + for _ = 1, 4 do + if not changed then + changed = workTopFromCurrentSide(gooTier); + 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; + + 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); + 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)); + + if turtle.dig() then + changed = true; + else + print('Could not mine bottom block. Waiting...'); + os.sleep(WAIT_SECONDS); + end + end + end +end + +print('goo started. Place the turtle directly below the goo block.'); + +while true do + local gooTier = ensureGooAlive(); + local hasEligibleBlocks = findEligibleProcessSlot(gooTier) ~= nil; + + local changed = false; + + changed = workTop(gooTier) or changed; + changed = workHorizontalSides(gooTier) or changed; + changed = workBottom() or changed; + + if not changed then + if hasEligibleBlocks then + print('No free goo side found. Waiting for processing...'); + else + print('No eligible process block found. Waiting for inventory...'); + end + + os.sleep(WAIT_SECONDS); + end +end