Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- MineColonies Builder Request Fulfillment Bot
- Version 2.1
- Changelog v2.1:
- - Robust Startup: Script always tries to go home, refuel, and clear inventory on startup.
- - Clear Location-Based Peripheral Access: Ensures turtle is at the correct warp point (home or colony)
- before attempting to use peripherals specific to those locations.
- Setup: (Same as v2.0)
- 1. ME Bridge, End Automata, Colony Integrator connected.
- 2. "home" warp: Above coal, facing ME Bridge. IO Chest for ME bridge is in front after turtle.up().
- 3. Warp points: "home", "colony", "[BuildingName]_storage" or "X,Y,Z" for builders.
- 4. Turtle's slot 16 for coal.
- ]]
- -- 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
- -- Peripherals
- local bridge = peripheral.find(ME_BRIDGE_NAME)
- local automata = peripheral.find(END_AUTOMATA_NAME)
- local colony = peripheral.find(COLONY_INTEGRATOR_NAME)
- -- [[ HELPER FUNCTIONS from previous versions: checkPeripherals, ensureFuel, warpTo, findEmptySlot, consolidateInventory, returnUnusedItemsToME, getItemsFromME, deliverItems ]]
- -- Ensure these functions are defined here as in the previous complete script.
- -- For brevity, I'm omitting their full code here but they are assumed to be present.
- local function checkPeripherals()
- if not bridge then print("ERROR: ME Bridge ('" .. ME_BRIDGE_NAME .. "') not found!") return false end
- if not automata then print("ERROR: End Automata ('" .. END_AUTOMATA_NAME .. "') not found!") return false end
- if not colony then print("ERROR: Colony Integrator ('" .. COLONY_INTEGRATOR_NAME .. "') not found!") return false end
- print("All peripherals found.")
- return true
- end
- local function ensureFuel()
- print("Checking fuel...")
- local neededFuel = automata.getWarpFuelCost(HOME_WARP_POINT)
- if neededFuel == nil then neededFuel = 500 end
- if turtle.getFuelLevel() < neededFuel * 2 then
- turtle.select(COAL_SLOT)
- if turtle.getItemCount(COAL_SLOT) > 0 then
- print("Refueling from inventory...")
- turtle.refuel()
- print("Fuel level: " .. turtle.getFuelLevel())
- else
- print("WARNING: No coal in slot " .. COAL_SLOT .. " for refueling!")
- end
- end
- turtle.select(COAL_SLOT)
- if turtle.getItemCount(COAL_SLOT) < COAL_RESERVE_AMOUNT / 2 then
- print("Coal reserve low. Attempting to restock at home (suckDown).")
- local suckedAmount = turtle.suckDown(COAL_RESERVE_AMOUNT - turtle.getItemCount(COAL_SLOT))
- if suckedAmount > 0 then
- print("Sucked " .. suckedAmount .. " coal.")
- turtle.select(COAL_SLOT)
- turtle.refuel()
- print("Fuel level after restocking: " .. turtle.getFuelLevel())
- else
- print("Failed to suck more coal from below.")
- end
- end
- if turtle.getFuelLevel() < neededFuel then
- print("CRITICAL: Insufficient fuel! Waiting...")
- return false
- end
- print("Fuel check OK. Level: " .. turtle.getFuelLevel())
- return true
- end
- local function warpTo(pointName)
- print("Attempting to warp to '" .. pointName .. "'...")
- -- No fuel check here, ensureFuel should be called strategically *before* warping.
- local currentFuel = turtle.getFuelLevel()
- local cost = automata.getWarpFuelCost(pointName) or 0
- print(" Current Fuel: " .. currentFuel .. ", Est. Cost: " .. cost)
- if currentFuel < cost and cost > 0 then -- cost can be 0 if warping to current location
- print(" WARN: Potentially insufficient fuel to reach " .. pointName .. ". Attempting anyway if some fuel exists.")
- if currentFuel == 0 then
- print(" ERROR: Zero fuel. Cannot warp.")
- return false
- end
- end
- local success, reason = automata.warpToPoint(pointName)
- if success then
- print("Warp successful to " .. pointName)
- os.sleep(2) -- Allow world to load, peripherals to re-attach
- return true
- else
- print("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()
- print("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()
- print("Returning unused items to ME system (at home)...")
- -- Assumes turtle is AT HOME_WARP_POINT, base Z, facing ME Bridge.
- turtle.up() -- Move to where the IO chest is in front
- local itemsDroppedDetails = {}
- for i = 1, 15 do
- turtle.select(i)
- local itemDetail = turtle.getItemDetail(i)
- if itemDetail and itemDetail.count > 0 then
- print(" Dropping " .. itemDetail.count .. " of " .. itemDetail.displayName .. " (Slot " .. i .. ") into IO chest.")
- if turtle.drop() then
- table.insert(itemsDroppedDetails, itemDetail)
- else
- print(" WARN: Failed to drop " .. itemDetail.displayName .. " from slot " .. i .. " into IO chest.")
- end
- end
- end
- turtle.down() -- Return to base Z, facing ME Bridge
- if #itemsDroppedDetails == 0 then
- print(" No items were in turtle (slots 1-15) to return, or all drops failed.")
- return
- end
- print(" Importing items from IO chest into ME system:")
- for _, itemToImport in ipairs(itemsDroppedDetails) do
- local importFilter = {name=itemToImport.name, count=itemToImport.count}
- if itemToImport.nbt then importFilter.nbt = itemToImport.nbt end
- print(" Importing " .. itemToImport.count .. " of " .. itemToImport.displayName)
- local importedAmount, importError = bridge.importItem(importFilter, "up")
- if importError then
- print(" ERROR importing " .. itemToImport.displayName .. ": " .. importError)
- elseif importedAmount > 0 then
- print(" Successfully imported " .. importedAmount .. " of " .. itemToImport.displayName)
- if importedAmount < itemToImport.count then print(" WARN: Imported " .. importedAmount .. "/" .. itemToImport.count) end
- else
- print(" Imported 0 of " .. itemToImport.displayName .. ". (No error, 0 moved)")
- end
- os.sleep(0.2)
- end
- print("Finished returning items.")
- end
- local function getItemsFromME(itemsToGet)
- print("Requesting items from ME system (at home):")
- -- Assumes turtle is AT HOME_WARP_POINT and has been refueled.
- local successfullyFetched = {}
- for _, itemReq in ipairs(itemsToGet) do
- local itemName = itemReq.item
- local itemDisplayName = itemReq.displayName
- local neededCount = itemReq.needed
- if neededCount <= 0 then goto continue_me_req_v21 end
- print("- Need " .. neededCount .. " of " .. itemDisplayName .. " (" .. itemName .. ")")
- local emptySlot = findEmptySlot()
- if not emptySlot then print(" No empty slot. Skipping further ME requests.") break end
- turtle.select(emptySlot)
- local exportFilter = {name=itemName, count=neededCount}
- if itemReq.nbt then exportFilter.nbt = itemReq.nbt end
- print(" Exporting " .. neededCount .. " " .. itemDisplayName .. "...")
- local exportedAmount, exportReason = bridge.exportItem(exportFilter, "up")
- if not exportedAmount or exportedAmount == 0 then
- print(" ERROR or No items exported for " .. itemDisplayName .. ": " .. (exportReason or "0 items"))
- goto continue_me_req_v21
- end
- print(" ME Bridge exported " .. exportedAmount .. ". Turtle up to access IO chest.")
- turtle.up()
- local itemActuallySucked = 0
- turtle.select(emptySlot)
- for _ = 1, exportedAmount do
- if turtle.suck(1) then itemActuallySucked = itemActuallySucked + 1 else break end
- end
- turtle.down()
- if itemActuallySucked > 0 then
- local fetchedDetail = turtle.getItemDetail(emptySlot)
- print(" Sucked " .. itemActuallySucked .. " of " .. fetchedDetail.displayName .. " into slot " .. emptySlot)
- table.insert(successfullyFetched, {
- slot = emptySlot, name = fetchedDetail.name, displayName = fetchedDetail.displayName,
- count = itemActuallySucked, nbt = fetchedDetail.nbt
- })
- if itemActuallySucked < neededCount then print(" WARN: Received " ..itemActuallySucked.."/"..neededCount) end
- elseif exportedAmount > 0 then
- print(" Exported " .. exportedAmount .. " but failed to suck " .. itemDisplayName)
- end
- ::continue_me_req_v21::
- end
- consolidateInventory()
- return successfullyFetched
- end
- local function deliverItems(deliveryWarpPointName, itemsToDeliver)
- print("Attempting delivery to " .. deliveryWarpPointName)
- -- Assumes warpTo this point was successful before calling.
- print("Delivering items by dropping down:")
- local allDelivered = true
- for _, itemDetail in ipairs(itemsToDeliver) do
- turtle.select(itemDetail.slot)
- local currentItemInSlot = turtle.getItemDetail(itemDetail.slot)
- if currentItemInSlot and currentItemInSlot.name == itemDetail.name and (currentItemInSlot.nbt == itemDetail.nbt) then
- local countToDrop = currentItemInSlot.count
- print(" Dropping " .. countToDrop .. " of " .. itemDetail.displayName .. " (Slot " .. itemDetail.slot .. ")")
- if turtle.dropDown(countToDrop) then
- print(" Dropped successfully.")
- else
- print(" DropDown failed. Trying alternative (L, F, Drop)...")
- turtle.turnLeft() turtle.forward()
- if turtle.dropDown(countToDrop) then
- print(" Dropped at alternative spot.")
- else
- print(" ERROR: Failed at alternative spot for " .. itemDetail.displayName)
- allDelivered = false
- end
- turtle.back() turtle.turnRight() -- Return to original orientation
- end
- else
- print(" WARN: Item " .. itemDetail.displayName .. " (NBT: "..(itemDetail.nbt or "nil")..") not in slot " .. itemDetail.slot .. " as expected.")
- allDelivered = false
- end
- end
- if allDelivered then print("All items in batch appear delivered to " .. deliveryWarpPointName)
- else print("Some items could not be delivered to " .. deliveryWarpPointName .. ". They remain in turtle.") end
- return allDelivered
- end
- -- END OF HELPER FUNCTION DEFINITIONS
- -- Function to ensure turtle is at home and prepared (fueled, inventory cleared)
- function prepareAtHomeBase()
- print("Ensuring turtle is prepared at home base...")
- if not warpTo(HOME_WARP_POINT) then
- print("CRITICAL: Cannot reach " .. HOME_WARP_POINT .. " to prepare.")
- print("Please manually move turtle home, ensure coal, refuel, save 'home' warp, then restart script.")
- return false -- Fatal error for this attempt
- end
- -- Now at home, ensure fuel and clear inventory
- if not ensureFuel() then
- print("CRITICAL: Failed to ensure fuel at " .. HOME_WARP_POINT .. ".")
- return false -- Fatal error for this attempt
- end
- returnUnusedItemsToME() -- Clear out any old items
- print("Turtle is at home and prepared.")
- return true
- end
- -- MAIN SCRIPT EXECUTION
- if not checkPeripherals() then
- print("Initial peripheral check failed. Please fix and restart. Exiting.")
- return
- end
- print("Builder Bot v2.1 Starting Up...")
- if not prepareAtHomeBase() then
- print("Initial home preparation failed. Waiting 5 minutes before retrying...")
- os.sleep(300)
- if not prepareAtHomeBase() then -- Second attempt
- print("Second attempt at home preparation failed. Exiting script.")
- return
- end
- end
- print("Successfully initialized at home base. Starting main loop.")
- -- Main Operational Loop
- while true do
- print("\n--- Starting New Operational Cycle ---")
- local workOrderFoundAndTargeted = false
- local actualDeliveryWarpPoint = nil
- local originalTargetBuildingName = nil
- local currentWorkOrderItems = nil
- -- 1. Go to Colony to check for work orders
- print("Going to colony to check for work orders...")
- if not warpTo(COLONY_WARP_POINT) then
- print("Failed to reach colony. Will attempt to return home and restart cycle.")
- if not prepareAtHomeBase() then -- Try to recover by going home
- print("CRITICAL: Could not return home after failing to reach colony. Waiting 5 mins...")
- os.sleep(300) -- Long pause before trying the whole loop again
- end
- goto continue_main_loop_v21
- end
- -- Now at COLONY_WARP_POINT, access colonyIntegrator
- print("At colony. Checking for work orders...")
- local workOrders = colony.getWorkOrders()
- if not workOrders or #workOrders == 0 then
- print("No active work orders found.")
- else
- for _, wo in ipairs(workOrders) do
- -- (Logic to parse wo, get resources, determine if itemsNeededForThisOrder, needsSomething - from previous script)
- local itemsNeededForThisOrder = {}
- local needsSomething = false
- local resources = colony.getWorkOrderResources(wo.id)
- if resources and #resources > 0 then
- for _, res in ipairs(resources) do
- if res.needed > 0 and (res.available == false or (res.status and string.lower(res.status) ~= "met" and string.lower(res.status) ~= "fulfilled")) then
- table.insert(itemsNeededForThisOrder, {item = res.item, displayName = res.displayName, needed = res.needed, nbt = res.nbt})
- needsSomething = true
- end
- end
- end
- if needsSomething then
- originalTargetBuildingName = wo.buildingName or "Unknown Target"
- currentWorkOrderItems = itemsNeededForThisOrder
- if wo.buildingName and not string.match(string.lower(wo.buildingName), "com.minecolonies.building.") and not string.match(string.lower(wo.buildingName), "minecolonies:") then
- actualDeliveryWarpPoint = wo.buildingName .. NAMED_BUILDING_STORAGE_SUFFIX
- elseif wo.builder and wo.builder.x ~= nil then
- actualDeliveryWarpPoint = wo.builder.x .. "," .. wo.builder.y .. "," .. wo.builder.z
- else
- actualDeliveryWarpPoint = nil -- Cannot determine warp
- end
- if actualDeliveryWarpPoint then
- print("Targeting Work Order for: " .. originalTargetBuildingName .. " (Warp: " .. actualDeliveryWarpPoint .. ")")
- workOrderFoundAndTargeted = true
- break -- Found a work order to process
- else
- print("Found work order for "..originalTargetBuildingName.." but could not determine valid warp point.")
- end
- end
- end
- end
- -- 2. Decision point: Got a work order?
- if workOrderFoundAndTargeted and actualDeliveryWarpPoint and currentWorkOrderItems then
- print("Work order identified. Returning home to fetch items for: " .. originalTargetBuildingName)
- if not warpTo(HOME_WARP_POINT) then
- print("Failed to warp home to get items. Cycle will restart.")
- -- prepareAtHomeBase() will be called at the start of the next loop iteration
- goto continue_main_loop_v21
- end
- -- Now at HOME_WARP_POINT, ensure fuel and get items
- if not ensureFuel() then -- Quick fuel check/top-up
- print("Failed to ensure fuel at home before getting items. Cycle will restart.")
- goto continue_main_loop_v21
- end
- local fetchedItems = getItemsFromME(currentWorkOrderItems)
- if not fetchedItems or #fetchedItems == 0 then
- print("No items fetched from ME for " .. originalTargetBuildingName .. ". Cycle will restart.")
- -- Leftover items (if any) will be handled by prepareAtHomeBase on next loop
- goto continue_main_loop_v21
- end
- -- 3. Deliver Items
- print("Items fetched. Proceeding to deliver to " .. originalTargetBuildingName .. " via warp " .. actualDeliveryWarpPoint)
- if warpTo(actualDeliveryWarpPoint) then
- deliverItems(actualDeliveryWarpPoint, fetchedItems)
- else
- print("Failed to warp to delivery point " .. actualDeliveryWarpPoint .. ". Items remain in turtle.")
- -- Items will be returned to ME by prepareAtHomeBase() on next loop
- end
- print("Delivery attempt for " .. originalTargetBuildingName .. " complete.")
- else
- print("No suitable work orders found this cycle, or failed to target one.")
- -- If not already home, go home before waiting.
- print("Returning home to wait.")
- if not warpTo(HOME_WARP_POINT) then
- print("Failed to return home. Will retry preparation next cycle.")
- -- The prepareAtHomeBase() at the start of the loop will handle this.
- end
- end
- print("Cycle finished. Waiting 60 seconds before next cycle.")
- os.sleep(60)
- -- Before looping, ensure we are prepared at home base for the next iteration
- if not prepareAtHomeBase() then
- print("Failed home preparation before new cycle. Waiting 5 minutes...")
- os.sleep(300)
- if not prepareAtHomeBase() then
- print("Second attempt at home preparation failed. Exiting script to prevent issues.")
- return -- Hard stop if can't get to a good state
- end
- end
- ::continue_main_loop_v21::
- end
Add Comment
Please, Sign In to add comment