Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- MineColonies Builder Request Fulfillment Bot
- Version 3.9
- Changelog v3.9:
- - Fixed `goto` Scope Error in `getItemsFromME`:
- - Ensured all per-item-request local variables (including `exportFilter`,
- `exportedAmount`, `exportReason`) are declared at the beginning of each
- iteration of the item request loop, preventing `goto` from bypassing their
- initialization on subsequent iterations.
- - Previous fixes from v3.8 remain.
- Changelog v3.8:
- - Simplified Home Base ME Interaction (Reverted from v3.7 turns):
- - Turtle now only performs: turtle.up() then turtle.down() for IO Chest interaction.
- - Uses turtle.drop() / turtle.suck() when at the higher Y-level.
- - Retained `goto` scope error fix from v3.7 (initial attempt).
- - Previous fixes from v3.6 remain.
- Setup: (Same as v2.0)
- Physical ME Interaction Setup at HOME_WARP_POINT (Side View):
- Level +1: [ IO Chest ] (After turtle.up(), turtle is at Level +1, in front of IO Chest)
- Level 0: [ Turtle ] (Turtle resting spot)
- [ ME Bridge ] (Adjacent to turtle or turtle is on it. IO Chest is "up" from bridge)
- Level -1: [ Coal Chest ] (Coal chest below turtle's resting spot)
- ]]
- -- Configuration
- local ME_BRIDGE_NAME = "meBridge"
- local END_AUTOMATA_NAME = "endAutomata"
- local COLONY_INTEGRATOR_NAME = "colonyIntegrator"
- local HOME_WARP_POINT = "home"
- local COLONY_WARP_POINT = "colony"
- local NAMED_BUILDING_STORAGE_SUFFIX = "_storage"
- local COAL_SLOT = 16
- local COAL_RESERVE_AMOUNT = 64
- local LOW_FUEL_THRESHOLD = 200
- local DETAILED_RESOURCE_LOG_FILE = "builder_bot_resource_details.log"
- local MAIN_LOG_FILE = "builder_bot_main.log"
- -- DEBUG FLAG (v3.4)
- local DEBUG_MODE = true -- Set to true for detailed file logging and longer waits, false for production
- local automata = nil
- -- [[ Logging Function (Modified v3.4) ]]
- local function log(message, isDebugMessage)
- local timestamp = textutils.formatTime(os.time(), false)
- local logMessage = "[" .. timestamp .. "] " .. tostring(message)
- print(logMessage)
- if DEBUG_MODE then
- if not isDebugMessage or (isDebugMessage and DEBUG_MODE) then
- local file = fs.open(MAIN_LOG_FILE, "a")
- if file then file.writeLine(logMessage) file.close()
- else print("ERROR: Could not write to main log file: " .. MAIN_LOG_FILE) end
- end
- end
- end
- local function debugLog(message) if DEBUG_MODE then log("DEBUG: " .. tostring(message), true) end end
- local function debugNbtLog(message) if DEBUG_MODE then log("DEBUG NBT: " .. tostring(message), true) end end
- -- [[ HELPER FUNCTIONS ]]
- local function initialPeripheralCheck()
- automata = peripheral.find(END_AUTOMATA_NAME)
- if not automata then log("CRITICAL ERROR: End Automata ('" .. END_AUTOMATA_NAME .. "') not found!") return false end
- log("End Automata found.")
- return true
- end
- local function ensureFuel(atHome)
- log("Ensuring fuel. Turtle is " .. (atHome and "at home." or "not at home."))
- if turtle.getFuelLevel() < LOW_FUEL_THRESHOLD then
- turtle.select(COAL_SLOT)
- if turtle.getItemCount(COAL_SLOT) > 0 then log("Fuel is low (" .. turtle.getFuelLevel() .. "). Refueling from coal slot...") turtle.refuel() log("Fuel level after attempting refuel: " .. turtle.getFuelLevel())
- else log("Fuel is low, but no coal in slot " .. COAL_SLOT .. " to use.") end
- end
- if atHome then
- log("At home: Attempting to stock coal and maximize fuel.")
- turtle.select(COAL_SLOT)
- local currentCoal = turtle.getItemCount(COAL_SLOT)
- if currentCoal < COAL_RESERVE_AMOUNT then
- local amountToSuck = COAL_RESERVE_AMOUNT - currentCoal
- log("Coal slot " .. COAL_SLOT .. " has " .. currentCoal .. "/" .. COAL_RESERVE_AMOUNT .. ". Sucking up to " .. amountToSuck .. " from coal chest below...")
- local suckResult = turtle.suckDown(amountToSuck)
- if type(suckResult) == "number" then
- if suckResult > 0 then log("Sucked " .. suckResult .. " additional coal (numeric return).")
- else log("Sucked 0 items (numeric return; chest empty or other issue).") end
- elseif suckResult == true then log("suckDown returned true. Assuming " .. amountToSuck .. " (or available) coal sucked.")
- elseif suckResult == false then log("Failed to suck coal (suckDown returned false).")
- else log("WARN: turtle.suckDown returned unexpected type: " .. type(suckResult) .. ", value: " .. tostring(suckResult)) end
- else log("Coal slot " .. COAL_SLOT .. " is already full or has sufficient reserve.") end
- turtle.select(COAL_SLOT)
- if turtle.getItemCount(COAL_SLOT) > 0 then log("Refueling turtle at home base from slot " .. COAL_SLOT .. "...") turtle.refuel() log("Fuel level after home refueling: " .. turtle.getFuelLevel())
- else log("No coal in slot " .. COAL_SLOT .. " to perform home refueling.") end
- end
- if turtle.getFuelLevel() == 0 then log("CRITICAL: Turtle has zero fuel!") return false end
- log("Fuel check complete. Current level: " .. turtle.getFuelLevel())
- return true
- end
- local function warpTo(pointName)
- log("Attempting to warp to '" .. pointName .. "'...")
- if turtle.getFuelLevel() == 0 then log(" ERROR: Zero fuel. Cannot warp.") return false end
- local success, reason = automata.warpToPoint(pointName)
- if success then log("Warp successful to " .. pointName) os.sleep(2) return true
- else log("ERROR: Failed to warp to " .. pointName .. ": " .. (reason or "unknown error")) return false end
- end
- local function findEmptySlot() for i = 1, 15 do if turtle.getItemCount(i) == 0 then return i end end return nil end
- local function consolidateInventory() log("Consolidating inventory...") for i = 1, 15 do turtle.select(i) if turtle.getItemCount(i) > 0 then for j = i + 1, 15 do if turtle.compareTo(j) then local space = turtle.getItemSpace(i) if space > 0 then turtle.select(j) turtle.transferTo(i, math.min(space, turtle.getItemCount(j))) end end end end end turtle.select(1) end
- local function returnUnusedItemsToME(bridge)
- if not bridge then log("ERROR (returnUnused): ME Bridge not provided!") return end
- log("Returning unused items to ME system (at home)...")
- log(" Moving turtle UP to interact with IO Chest (Level +1)...")
- if not turtle.up() then
- log(" CRITICAL ERROR: Failed to move turtle.up(). Cannot return items.")
- return
- end
- local itemsAttemptedToDrop = {}
- for i = 1, 15 do
- turtle.select(i)
- local itemDetail = turtle.getItemDetail(i)
- if itemDetail and itemDetail.count > 0 then
- local displayNameToPrint = itemDetail.displayName or itemDetail.name or "UnknownItemInTurtle"
- log(" Attempting to drop " .. itemDetail.count .. " of " .. displayNameToPrint .. " (Slot " .. i .. ") into IO Chest (in front at Level +1).")
- if turtle.drop() then
- log(" Dropped successfully into IO Chest.")
- table.insert(itemsAttemptedToDrop, itemDetail)
- else
- log(" WARN: Failed to drop " .. displayNameToPrint .. " into IO Chest from slot " .. i .. ". Item remains in turtle.")
- end
- end
- end
- log(" Moving turtle DOWN to resting position (Level 0)...")
- if not turtle.down() then
- log(" WARN: Failed to move turtle.down() after attempting to drop items.")
- end
- if #itemsAttemptedToDrop == 0 then
- log(" No items were successfully dropped into IO chest by turtle to return via bridge.")
- local itemsStillInTurtle = false
- for i = 1, 15 do if turtle.getItemCount(i) > 0 then itemsStillInTurtle = true; break; end end
- if not itemsStillInTurtle then log(" Turtle inventory (slots 1-15) is clear.")
- else log(" Some items remain in turtle inventory that could not be dropped.") end
- return
- end
- log(" Attempting to import items from IO chest (up from bridge) into ME system:")
- for _, itemToImport in ipairs(itemsAttemptedToDrop) do
- local displayNameToImport = itemToImport.displayName or itemToImport.name or "UnknownItemToImport"
- local importFilter = {name=itemToImport.name, count=itemToImport.count}
- if itemToImport.nbt then importFilter.nbt = itemToImport.nbt end
- log(" Bridge: Attempting to import " .. itemToImport.count .. " of " .. displayNameToImport .. " from IO Chest (up).")
- local importedAmount, importError = bridge.importItem(importFilter, "up")
- if importError then log(" ERROR importing " .. displayNameToImport .. " via bridge: " .. importError)
- elseif importedAmount > 0 then
- log(" Successfully imported " .. importedAmount .. " of " .. displayNameToImport .. " via bridge.")
- if importedAmount < itemToImport.count then log(" WARN: Bridge imported " .. importedAmount .. "/" .. itemToImport.count) end
- else log(" Bridge imported 0 of " .. displayNameToImport .. ". (No error, 0 moved, or item not found/match)") end
- os.sleep(0.2)
- end
- log("Finished returning items from IO Chest via bridge.")
- end
- -- Fixed v3.9 for goto scope issues
- local function getItemsFromME(bridge, itemsToGet)
- if not bridge then log("ERROR (getItems): ME Bridge not provided!") return {} end
- log("Requesting items from ME system (at home):")
- local successfullyFetched = {}
- for itemReqIdx, itemReq in ipairs(itemsToGet) do
- -- Initialize all per-item-request locals here
- local currentRequestMainItemSlot = nil
- local itemActuallySuckedThisRequest = 0
- local unexpectedItemWasSucked = false
- local contaminationCheckSlotUsed = nil
- local exportFilter = nil -- v3.9: Declare here
- local exportedAmount = 0 -- v3.9: Initialize
- local exportReason = nil -- v3.9: Initialize
- local itemName = "" ; local itemDisplayName = ""
- if type(itemReq.item) == "table" then itemName = itemReq.item.name or "UnknownItemRegistry"
- elseif type(itemReq.item) == "string" then itemName = itemReq.item else itemName = "InvalidItemRegistry" end
- if type(itemReq.displayName) == "table" then itemDisplayName = itemReq.displayName.name or itemReq.displayName.displayName or itemName
- elseif type(itemReq.displayName) == "string" then itemDisplayName = itemReq.displayName else itemDisplayName = itemName end
- local neededCount = itemReq.needs
- if neededCount == nil or type(neededCount) ~= "number" or neededCount <= 0 then
- log(" Skipping item " .. itemDisplayName .. " for ME fetch (invalid neededCount: " .. tostring(neededCount) .. ")")
- goto continue_me_req_v39
- end
- currentRequestMainItemSlot = findEmptySlot()
- if not currentRequestMainItemSlot then
- log(" No empty turtle slot for main item. Skipping further ME requests this cycle.")
- break
- end
- turtle.select(currentRequestMainItemSlot)
- exportFilter = {name=itemName, count=neededCount} -- v3.9: Assign here
- if itemReq.nbt then exportFilter.nbt = itemReq.nbt end
- log(" Requesting " .. neededCount .. " of " .. itemDisplayName .. " (NBT: " ..tostring(itemReq.nbt).. ") from ME to IO Chest (up from bridge).")
- exportedAmount, exportReason = bridge.exportItem(exportFilter, "up") -- v3.9: Use declared vars
- if not exportedAmount or exportedAmount == 0 then
- log(" Export failed for " .. itemDisplayName .. ": " .. (exportReason or "0 items exported to IO Chest"))
- -- No items to suck, so itemActuallySuckedThisRequest remains 0. Flow to end of loop.
- else
- log(" ME system reported exporting " .. exportedAmount .. ". Preparing to suck from IO Chest.")
- log(" Moving turtle UP to interact with IO Chest (Level +1)...")
- if not turtle.up() then
- log(" CRITICAL: Failed turtle.up(). Cannot retrieve " .. itemDisplayName .. ". Items may be in IO chest.")
- goto continue_me_req_v39 -- Skips rest of *this* item, goes to next in itemsToGet
- end
- log(" Attempting to suck " .. exportedAmount .. " of " .. itemDisplayName .. " into slot " .. currentRequestMainItemSlot .. " from IO Chest (in front at Level +1).")
- for _ = 1, exportedAmount do
- if turtle.suck(1) then
- itemActuallySuckedThisRequest = itemActuallySuckedThisRequest + 1
- else
- debugLog(" WARN: Expected to suck " .. exportedAmount .. " but only got " .. itemActuallySuckedThisRequest .. ". IO Chest empty or slot full.")
- break
- end
- end
- if itemActuallySuckedThisRequest > 0 then
- local detail = turtle.getItemDetail(currentRequestMainItemSlot)
- log(" Sucked " .. itemActuallySuckedThisRequest .. " of " .. (detail.displayName or detail.name) .. " (intended: " .. itemDisplayName .. ")")
- if itemActuallySuckedThisRequest < neededCount then
- log(" WARN: Sucked " ..itemActuallySuckedThisRequest.."/"..neededCount .. " (exported: " .. exportedAmount .. ")")
- end
- elseif exportedAmount > 0 then
- log(" ME reported export of " .. exportedAmount .. " but failed to suck any " .. itemDisplayName .. " from IO chest.")
- end
- log(" Performing post-suck check for unexpected items in IO Chest...")
- local contaminationCheckSlot = nil -- This local is fine, specific to this block
- if turtle.getItemCount(currentRequestMainItemSlot) == 0 then
- contaminationCheckSlot = currentRequestMainItemSlot
- else
- contaminationCheckSlot = findEmptySlot()
- end
- contaminationCheckSlotUsed = contaminationCheckSlot
- if contaminationCheckSlot then
- local originalSelectedSlotForCheck = turtle.getSelectedSlot()
- turtle.select(contaminationCheckSlot)
- if turtle.suck(1) then
- unexpectedItemWasSucked = true
- local unexpectedItemDetail = turtle.getItemDetail(contaminationCheckSlot)
- log(" CRITICAL: Unexpected item found in IO Chest! First: " .. (unexpectedItemDetail.displayName or unexpectedItemDetail.name) .. " x" .. unexpectedItemDetail.count .. " in slot " .. contaminationCheckSlot)
- while turtle.getItemCount(contaminationCheckSlot) < turtle.getItemSpace(contaminationCheckSlot) and turtle.suck(1) do end
- unexpectedItemDetail = turtle.getItemDetail(contaminationCheckSlot)
- if unexpectedItemDetail then log(" Total unexpected in slot " .. contaminationCheckSlot .. ": " .. (unexpectedItemDetail.displayName or unexpectedItemDetail.name) .. " x" .. unexpectedItemDetail.count) end
- else
- log(" Post-suck check: IO Chest is clear of further items.")
- end
- turtle.select(originalSelectedSlotForCheck)
- else
- log(" WARN: No empty slot for contamination check.")
- end
- log(" Moving turtle DOWN to resting position (Level 0)...")
- if not turtle.down() then log(" WARN: Failed turtle.down() when returning to resting spot.") end
- end
- if unexpectedItemWasSucked then
- log(" IO Chest contamination detected. Items for '"..itemDisplayName.."' (slot " .. currentRequestMainItemSlot ..") and unexpected (slot " .. contaminationCheckSlotUsed .. ") remain in turtle.")
- log(" Skipping current item request '"..itemDisplayName.."' for this WO.")
- elseif itemActuallySuckedThisRequest > 0 then
- local detail = turtle.getItemDetail(currentRequestMainItemSlot)
- table.insert(successfullyFetched, {
- slot = currentRequestMainItemSlot, name = detail.name, displayName = detail.displayName,
- count = detail.count, nbt = detail.nbt
- })
- else
- debugLog(" No items were successfully sucked for '"..itemDisplayName.."' this attempt (or export failed).")
- end
- ::continue_me_req_v39::
- os.sleep(0.1)
- end
- consolidateInventory()
- return successfullyFetched
- end
- local function nbtValuesMatch(itemNbtFromTurtle, requestedNbtFromColony)
- if requestedNbtFromColony == nil or (type(requestedNbtFromColony) == "table" and next(requestedNbtFromColony) == nil) then
- debugNbtLog("Colony requested no specific NBT. Match TRUE.")
- return true
- end
- local directMatch = (itemNbtFromTurtle == requestedNbtFromColony)
- debugNbtLog("Colony requested specific NBT. Turtle NBT: '" .. tostring(itemNbtFromTurtle) .. "', Requested NBT: '" .. tostring(requestedNbtFromColony) .. "'. Direct Match: " .. tostring(directMatch))
- return directMatch
- end
- local function deliverItems(deliveryWarpPointName, itemsExpectedToDeliver)
- log("Attempting delivery to " .. deliveryWarpPointName)
- log("Delivering items by dropping down:")
- local allItemsFullyDelivered = true
- local remainingToDeliver = {}
- for _, itemDetail in ipairs(itemsExpectedToDeliver) do
- table.insert(remainingToDeliver, {
- name = itemDetail.name, displayName = itemDetail.displayName or itemDetail.name or "UnknownItem",
- nbt = itemDetail.nbt, count = itemDetail.count
- })
- end
- local deliveryAttempted = false
- for deliveryPass = 1, 2 do
- if deliveryAttempted and deliveryPass == 2 then
- local anyLeft = false; for _, item in ipairs(remainingToDeliver) do if item.count > 0 then anyLeft = true break end end
- if not anyLeft then break end
- log(" Some items remain. Trying alternative drop spot...")
- turtle.turnLeft() turtle.forward()
- elseif deliveryPass == 2 then break end
- deliveryAttempted = true
- for i = 1, #remainingToDeliver do
- local wantedItem = remainingToDeliver[i]
- if wantedItem.count > 0 then
- local wantedItemDisplayName = wantedItem.displayName
- log(" Seeking to deliver " .. wantedItem.count .. " of " .. wantedItemDisplayName .. " (Req NBT type: " .. type(wantedItem.nbt) .. ", val: " .. tostring(wantedItem.nbt) .. ")")
- for slot = 1, 15 do
- turtle.select(slot)
- local itemInSlot = turtle.getItemDetail(slot)
- if itemInSlot and itemInSlot.name == wantedItem.name then
- debugLog("Checking slot " .. slot .. ": Item '" .. itemInSlot.name .. "', Count: " .. itemInSlot.count .. ", Slot NBT type: " .. type(itemInSlot.nbt) .. ", val: " .. tostring(itemInSlot.nbt))
- if nbtValuesMatch(itemInSlot.nbt, wantedItem.nbt) then
- debugLog("NBTs MATCH for slot " .. slot .. " for item " .. wantedItemDisplayName)
- local amountToDrop = math.min(itemInSlot.count, wantedItem.count)
- if amountToDrop > 0 then
- log(" Found " .. itemInSlot.count .. " of " .. wantedItemDisplayName .. " in slot " .. slot .. ". Attempting to dropDown " .. amountToDrop)
- if turtle.dropDown(amountToDrop) then
- log(" DroppedDown " .. amountToDrop .. " successfully.")
- wantedItem.count = wantedItem.count - amountToDrop
- if wantedItem.count == 0 then log(" Requirement for " .. wantedItemDisplayName .. " met.") break end
- else
- log(" DropDown failed for " .. amountToDrop .. " of " .. wantedItemDisplayName .. " from slot " .. slot .. ".")
- allItemsFullyDelivered = false
- end
- end
- else
- debugLog("NBTs DO NOT MATCH for slot " .. slot .. " for item " .. wantedItemDisplayName)
- end
- end
- end
- end
- end
- local allMetThisPass = true
- for _, item in ipairs(remainingToDeliver) do if item.count > 0 then allMetThisPass = false break end end
- if allMetThisPass then log(" All item requirements met in this delivery pass.") break end
- if deliveryPass == 2 then turtle.back() turtle.turnRight() end
- end
- for _, item in ipairs(remainingToDeliver) do
- if item.count > 0 then log(" WARN: Could not deliver " .. item.count .. " of " .. item.displayName .. ".") allItemsFullyDelivered = false end
- end
- if allItemsFullyDelivered then log("All requested items appear fully delivered to " .. deliveryWarpPointName)
- else log("Some items were not fully delivered to " .. deliveryWarpPointName) end
- local waitTime = DEBUG_MODE and 30 or 10
- log("Waiting " .. waitTime .. " seconds at builder's hut: " .. deliveryWarpPointName .. (DEBUG_MODE and " (DEBUG MODE)" or ""))
- os.sleep(waitTime)
- return allItemsFullyDelivered
- end
- function prepareAtHomeBase()
- log("Ensuring turtle is prepared at home base...")
- if not warpTo(HOME_WARP_POINT) then log("CRITICAL: Cannot reach " .. HOME_WARP_POINT) return false, nil end
- local bridge = peripheral.find(ME_BRIDGE_NAME)
- if not bridge then log("ERROR: ME Bridge ('"..ME_BRIDGE_NAME.."') not found at " .. HOME_WARP_POINT .. "!") return false, nil end
- log("ME Bridge found at home base.")
- if not ensureFuel(true) then log("CRITICAL: Failed to ensure fuel at " .. HOME_WARP_POINT .. ".") return false, bridge end
- returnUnusedItemsToME(bridge)
- log("Turtle is at home and prepared.")
- return true, bridge
- end
- -- MAIN SCRIPT EXECUTION
- log("Builder Bot v3.9 Initializing..." .. (DEBUG_MODE and " (DEBUG MODE ENABLED)" or ""))
- if not initialPeripheralCheck() then log("Essential End Automata not found. Exiting.") return end
- if DEBUG_MODE then
- local resLogClearFile = fs.open(DETAILED_RESOURCE_LOG_FILE, "w")
- if resLogClearFile then resLogClearFile.close() log("Cleared " .. DETAILED_RESOURCE_LOG_FILE) end
- end
- local homePrepared, currentBridge = prepareAtHomeBase()
- if not homePrepared then
- log("Initial home preparation failed. Waiting 5 minutes...") os.sleep(300)
- homePrepared, currentBridge = prepareAtHomeBase()
- if not homePrepared then log("Second home prep failed. Exiting.") return end
- end
- log("Successfully initialized. Starting main loop.")
- while true do
- log("\n--- Starting New Cycle ---")
- local workOrderFoundAndTargeted = false ; local actualDeliveryWarpPoint = nil
- local originalTargetBuildingName = nil ; local currentWorkOrderItems = nil
- local detailedResFile = nil
- log("Going to colony for work orders...")
- if not ensureFuel(false) then log("Warn: Low fuel before leaving home.") end
- if not warpTo(COLONY_WARP_POINT) then
- log("Failed to reach colony.") ; homePrepared, currentBridge = prepareAtHomeBase()
- if not homePrepared then log("CRIT: No recovery. Wait 5m...") os.sleep(300) end
- goto continue_main_loop_v39
- end
- local colony = peripheral.find(COLONY_INTEGRATOR_NAME)
- if not colony then
- log("ERROR: CI not found at "..COLONY_WARP_POINT) ; homePrepared, currentBridge = prepareAtHomeBase()
- if not homePrepared then os.sleep(300) end
- goto continue_main_loop_v39
- end
- log("CI found. Checking work orders...")
- local workOrders = colony.getWorkOrders()
- local suitableWorkOrders = {}
- if not workOrders or #workOrders == 0 then log("No active work orders.")
- else
- log("Found " .. #workOrders .. " WOs. Evaluating...")
- for _, wo in ipairs(workOrders) do
- if not wo or wo.id == nil then log(" WARN: Invalid WO entry.") goto continue_eval_wo_loop_v39 end
- log("\n Evaluating WO ID: " .. wo.id .. " for: " .. (wo.buildingName or "N/A"))
- if DEBUG_MODE then
- detailedResFile = fs.open(DETAILED_RESOURCE_LOG_FILE, "a")
- if detailedResFile then detailedResFile.write("\n--- Eval WO ID: " .. wo.id .. " for: " .. (wo.buildingName or "N/A") .. ", Type: " .. (wo.workOrderType or "N/A") .. " ---\n") end
- end
- local itemsNeededForThisOrder = {} ; local needsSomething = false
- local resources = colony.getWorkOrderResources(wo.id)
- if resources then
- if #resources > 0 then
- local headerMsg = " Found " .. #resources .. " resource entries:"
- if detailedResFile then detailedResFile.write(headerMsg .. "\n") elseif DEBUG_MODE then log(headerMsg) end
- for resIdx, res in ipairs(resources) do
- local sResItem = "UnknownItemRegistry"
- if type(res.item) == "table" then sResItem = res.item.name or (res.item.displayName or "UnknownInTable") elseif type(res.item) == "string" then sResItem = res.item end
- local sResDisplayName = sResItem
- if type(res.displayName) == "table" then sResDisplayName = res.displayName.name or (res.displayName.displayName or sResItem) elseif type(res.displayName) == "string" then sResDisplayName = res.displayName end
- local res_needs_val = res.needs ; local resAvailable = res.available
- local resStatus = res.status ; local resDelivering = res.delivering
- local logEntry = (" Res #" .. resIdx .. ": '" .. sResDisplayName .. "' (Reg: " .. sResItem .. ")\n") ..
- (" Raw needs: " .. tostring(res_needs_val) .. " (Type: " .. type(res_needs_val) .. ")\n") ..
- (" Raw Avail: " .. tostring(resAvailable) .. " (Type: " .. type(resAvailable) .. ")\n") ..
- (" Raw Status: " .. tostring(resStatus) .. " (Type: " .. type(resStatus) .. ")\n") ..
- (" Raw Deliver: " .. tostring(resDelivering) .. " (Type: " .. type(resDelivering) .. ")\n") ..
- (" Raw NBT: " .. tostring(res.nbt) .. " (Type: " .. type(res.nbt) .. ")\n")
- if detailedResFile then detailedResFile.write(logEntry) elseif DEBUG_MODE then log(logEntry) end
- if res_needs_val == nil then
- local skipMsg = " SKIP: 'needs' is nil."
- if detailedResFile then detailedResFile.write(skipMsg .. "\n") elseif DEBUG_MODE then log(skipMsg) end
- goto continue_res_loop_v39
- end
- local isStillNeeded = false ; local evalMsg = ""
- if type(res_needs_val) == "number" and res_needs_val > 0 then
- if resAvailable == false then isStillNeeded = true evalMsg = " EVAL: Need (avail false).\n"
- elseif resStatus and string.lower(resStatus) ~= "met" and string.lower(resStatus) ~= "fulfilled" and string.lower(resStatus) ~= "not_needed" then
- isStillNeeded = true evalMsg = " EVAL: Need (status '"..tostring(resStatus).."').\n"
- else evalMsg = " EVAL: Not Need (avail true or status met/fulfilled/not_needed). Needs: "..tostring(res_needs_val)..", Avail: "..tostring(resAvailable)..", Status: "..tostring(resStatus).."\n" end
- else evalMsg = " EVAL: Not Need (needs not >0 or not num). Needs: "..tostring(res_needs_val).."\n" end
- if detailedResFile then detailedResFile.write(evalMsg) elseif DEBUG_MODE then log(evalMsg) end
- if isStillNeeded then
- local actionMsg = " ACTION: Add " .. res_needs_val .. " of " .. sResDisplayName .. " to list. (WO NBT Type: " .. type(res.nbt) .. ", Val: " .. tostring(res.nbt) .. ")\n"
- if detailedResFile then detailedResFile.write(actionMsg) elseif DEBUG_MODE then log(actionMsg) end
- table.insert(itemsNeededForThisOrder, {item = sResItem, displayName = sResDisplayName, needs = res_needs_val, nbt = res.nbt})
- needsSomething = true
- end
- ::continue_res_loop_v39::
- end
- else
- local noResMsg = " WO " .. wo.id .. " no resource entries."
- if detailedResFile then detailedResFile.write(noResMsg .. "\n") else log(noResMsg) end
- end
- else
- local failGetResMsg = " WARN: Failed to get resources for WO " .. wo.id
- if detailedResFile then detailedResFile.write(failGetResMsg .. "\n") else log(failGetResMsg) end
- end
- if detailedResFile then detailedResFile.close() detailedResFile = nil end
- if needsSomething then
- local tempDeliveryWarpPoint = nil
- if wo.buildingName and not string.match(string.lower(wo.buildingName), "com.minecolonies.building.") and not string.match(string.lower(wo.buildingName), "minecolonies:") then
- tempDeliveryWarpPoint = wo.buildingName .. NAMED_BUILDING_STORAGE_SUFFIX
- elseif wo.builder and wo.builder.x ~= nil then tempDeliveryWarpPoint = wo.builder.x .. "," .. wo.builder.y .. "," .. wo.builder.z
- end
- if tempDeliveryWarpPoint then
- log(" WO ID " .. wo.id .. " for " .. (wo.buildingName or "N/A") .. " is suitable and has a valid warp point.")
- table.insert(suitableWorkOrders, { woData = wo, items = itemsNeededForThisOrder, warpPoint = tempDeliveryWarpPoint })
- else
- log(" WO ID " .. wo.id .. " for " .. (wo.buildingName or "N/A") .. " needs items, but no valid warp point determined. Skipping as suitable.")
- end
- else log(" WO " .. wo.id .. " no items needed based on eval.") end
- ::continue_eval_wo_loop_v39::
- end
- end
- colony = nil
- if #suitableWorkOrders > 0 then
- local randomIndex = math.random(1, #suitableWorkOrders)
- local chosenTask = suitableWorkOrders[randomIndex]
- log("Found " .. #suitableWorkOrders .. " suitable work order(s). Randomly selected task for WO ID: " .. chosenTask.woData.id)
- originalTargetBuildingName = chosenTask.woData.buildingName or "Unknown Target"
- currentWorkOrderItems = chosenTask.items
- actualDeliveryWarpPoint = chosenTask.warpPoint
- workOrderFoundAndTargeted = true
- else
- log("No suitable work orders found this cycle that require items and have valid warp points.")
- end
- if not workOrderFoundAndTargeted then log("No suitable WOs at colony.") log("Wait 10s at colony...") os.sleep(10) end
- if workOrderFoundAndTargeted and actualDeliveryWarpPoint and currentWorkOrderItems then
- log("WO targeted. Home for items: " .. originalTargetBuildingName)
- if not warpTo(HOME_WARP_POINT) then log("Failed warp home.") goto continue_main_loop_v39 end
- currentBridge = peripheral.find(ME_BRIDGE_NAME)
- if not currentBridge then log("ERROR: ME Bridge missing at home!") goto continue_main_loop_v39 end
- if not ensureFuel(true) then log("Fuel fail home.") goto continue_main_loop_v39 end
- local fetchedItems = getItemsFromME(currentBridge, currentWorkOrderItems)
- if not fetchedItems then fetchedItems = {} end
- log("ME fetch attempt complete. Fetched " .. #fetchedItems .. " types of items for delivery. Delivering to " .. originalTargetBuildingName .. " via " .. actualDeliveryWarpPoint)
- if not ensureFuel(false) then log("Warn: Low fuel pre-delivery.") end
- if warpTo(actualDeliveryWarpPoint) then
- if #fetchedItems > 0 then
- deliverItems(actualDeliveryWarpPoint, fetchedItems)
- else
- log("No items were successfully fetched from ME (or all were compromised by contamination). Nothing to deliver for this WO.")
- local waitTimeNoItems = DEBUG_MODE and 30 or 10
- log("Waiting " .. waitTimeNoItems .. " seconds at builder's hut (even with no items): " .. actualDeliveryWarpPoint .. (DEBUG_MODE and " (DEBUG MODE)" or ""))
- os.sleep(waitTimeNoItems)
- end
- else log("Failed warp to " .. actualDeliveryWarpPoint .. ". Items (if any) remain in turtle.") end
- log("Delivery attempt for " .. originalTargetBuildingName .. " done.")
- else log("No WO targeted this cycle. Home if not there.") end
- log("Cycle end. Prep for next.")
- homePrepared, currentBridge = prepareAtHomeBase()
- if not homePrepared then log("Home prep fail. Wait 5m...") os.sleep(300) homePrepared, currentBridge = prepareAtHomeBase()
- if not homePrepared then log("2nd home prep fail. Exit.") return end
- end
- log("Wait 10s before next cycle...") os.sleep(10)
- ::continue_main_loop_v39::
- end
Add Comment
Please, Sign In to add comment