Myros27

ColonySupplier

May 16th, 2025 (edited)
32
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 18.54 KB | None | 0 0
  1. --[[
  2. MineColonies Builder Request Fulfillment Bot
  3. Version 2.1
  4.  
  5. Changelog v2.1:
  6. - Robust Startup: Script always tries to go home, refuel, and clear inventory on startup.
  7. - Clear Location-Based Peripheral Access: Ensures turtle is at the correct warp point (home or colony)
  8.   before attempting to use peripherals specific to those locations.
  9.  
  10. Setup: (Same as v2.0)
  11. 1.  ME Bridge, End Automata, Colony Integrator connected.
  12. 2.  "home" warp: Above coal, facing ME Bridge. IO Chest for ME bridge is in front after turtle.up().
  13. 3.  Warp points: "home", "colony", "[BuildingName]_storage" or "X,Y,Z" for builders.
  14. 4.  Turtle's slot 16 for coal.
  15. ]]
  16.  
  17. -- Configuration
  18. local ME_BRIDGE_NAME = "meBridge"
  19. local END_AUTOMATA_NAME = "endAutomata"
  20. local COLONY_INTEGRATOR_NAME = "colonyIntegrator"
  21.  
  22. local HOME_WARP_POINT = "home"
  23. local COLONY_WARP_POINT = "colony"
  24. local NAMED_BUILDING_STORAGE_SUFFIX = "_storage"
  25.  
  26. local COAL_SLOT = 16
  27. local COAL_RESERVE_AMOUNT = 64
  28.  
  29. -- Peripherals
  30. local bridge = peripheral.find(ME_BRIDGE_NAME)
  31. local automata = peripheral.find(END_AUTOMATA_NAME)
  32. local colony = peripheral.find(COLONY_INTEGRATOR_NAME)
  33.  
  34. -- [[ HELPER FUNCTIONS from previous versions: checkPeripherals, ensureFuel, warpTo, findEmptySlot, consolidateInventory, returnUnusedItemsToME, getItemsFromME, deliverItems ]]
  35. -- Ensure these functions are defined here as in the previous complete script.
  36. -- For brevity, I'm omitting their full code here but they are assumed to be present.
  37.  
  38. local function checkPeripherals()
  39.     if not bridge then print("ERROR: ME Bridge ('" .. ME_BRIDGE_NAME .. "') not found!") return false end
  40.     if not automata then print("ERROR: End Automata ('" .. END_AUTOMATA_NAME .. "') not found!") return false end
  41.     if not colony then print("ERROR: Colony Integrator ('" .. COLONY_INTEGRATOR_NAME .. "') not found!") return false end
  42.     print("All peripherals found.")
  43.     return true
  44. end
  45.  
  46. local function ensureFuel()
  47.     print("Checking fuel...")
  48.     local neededFuel = automata.getWarpFuelCost(HOME_WARP_POINT)
  49.     if neededFuel == nil then neededFuel = 500 end
  50.  
  51.     if turtle.getFuelLevel() < neededFuel * 2 then
  52.         turtle.select(COAL_SLOT)
  53.         if turtle.getItemCount(COAL_SLOT) > 0 then
  54.             print("Refueling from inventory...")
  55.             turtle.refuel()
  56.             print("Fuel level: " .. turtle.getFuelLevel())
  57.         else
  58.             print("WARNING: No coal in slot " .. COAL_SLOT .. " for refueling!")
  59.         end
  60.     end
  61.  
  62.     turtle.select(COAL_SLOT)
  63.     if turtle.getItemCount(COAL_SLOT) < COAL_RESERVE_AMOUNT / 2 then
  64.         print("Coal reserve low. Attempting to restock at home (suckDown).")
  65.         local suckedAmount = turtle.suckDown(COAL_RESERVE_AMOUNT - turtle.getItemCount(COAL_SLOT))
  66.         if suckedAmount > 0 then
  67.             print("Sucked " .. suckedAmount .. " coal.")
  68.             turtle.select(COAL_SLOT)
  69.             turtle.refuel()
  70.             print("Fuel level after restocking: " .. turtle.getFuelLevel())
  71.         else
  72.             print("Failed to suck more coal from below.")
  73.         end
  74.     end
  75.  
  76.     if turtle.getFuelLevel() < neededFuel then
  77.         print("CRITICAL: Insufficient fuel! Waiting...")
  78.         return false
  79.     end
  80.     print("Fuel check OK. Level: " .. turtle.getFuelLevel())
  81.     return true
  82. end
  83.  
  84. local function warpTo(pointName)
  85.     print("Attempting to warp to '" .. pointName .. "'...")
  86.     -- No fuel check here, ensureFuel should be called strategically *before* warping.
  87.     local currentFuel = turtle.getFuelLevel()
  88.     local cost = automata.getWarpFuelCost(pointName) or 0
  89.     print("  Current Fuel: " .. currentFuel .. ", Est. Cost: " .. cost)
  90.     if currentFuel < cost and cost > 0 then -- cost can be 0 if warping to current location
  91.         print("  WARN: Potentially insufficient fuel to reach " .. pointName .. ". Attempting anyway if some fuel exists.")
  92.         if currentFuel == 0 then
  93.              print("  ERROR: Zero fuel. Cannot warp.")
  94.              return false
  95.         end
  96.     end
  97.  
  98.     local success, reason = automata.warpToPoint(pointName)
  99.     if success then
  100.         print("Warp successful to " .. pointName)
  101.         os.sleep(2) -- Allow world to load, peripherals to re-attach
  102.         return true
  103.     else
  104.         print("ERROR: Failed to warp to " .. pointName .. ": " .. (reason or "unknown error"))
  105.         return false
  106.     end
  107. end
  108.  
  109. local function findEmptySlot()
  110.     for i = 1, 15 do if turtle.getItemCount(i) == 0 then return i end end
  111.     return nil
  112. end
  113.  
  114. local function consolidateInventory()
  115.     print("Consolidating inventory...")
  116.     for i = 1, 15 do
  117.         turtle.select(i)
  118.         if turtle.getItemCount(i) > 0 then
  119.             for j = i + 1, 15 do
  120.                 if turtle.compareTo(j) then
  121.                     local space = turtle.getItemSpace(i)
  122.                     if space > 0 then turtle.select(j) turtle.transferTo(i, math.min(space, turtle.getItemCount(j))) end
  123.                 end
  124.             end
  125.         end
  126.     end
  127.     turtle.select(1)
  128. end
  129.  
  130. local function returnUnusedItemsToME()
  131.     print("Returning unused items to ME system (at home)...")
  132.     -- Assumes turtle is AT HOME_WARP_POINT, base Z, facing ME Bridge.
  133.  
  134.     turtle.up() -- Move to where the IO chest is in front
  135.  
  136.     local itemsDroppedDetails = {}
  137.     for i = 1, 15 do
  138.         turtle.select(i)
  139.         local itemDetail = turtle.getItemDetail(i)
  140.         if itemDetail and itemDetail.count > 0 then
  141.             print("  Dropping " .. itemDetail.count .. " of " .. itemDetail.displayName .. " (Slot " .. i .. ") into IO chest.")
  142.             if turtle.drop() then
  143.                 table.insert(itemsDroppedDetails, itemDetail)
  144.             else
  145.                 print("    WARN: Failed to drop " .. itemDetail.displayName .. " from slot " .. i .. " into IO chest.")
  146.             end
  147.         end
  148.     end
  149.     turtle.down() -- Return to base Z, facing ME Bridge
  150.  
  151.     if #itemsDroppedDetails == 0 then
  152.         print("  No items were in turtle (slots 1-15) to return, or all drops failed.")
  153.         return
  154.     end
  155.  
  156.     print("  Importing items from IO chest into ME system:")
  157.     for _, itemToImport in ipairs(itemsDroppedDetails) do
  158.         local importFilter = {name=itemToImport.name, count=itemToImport.count}
  159.         if itemToImport.nbt then importFilter.nbt = itemToImport.nbt end
  160.        
  161.         print("    Importing " .. itemToImport.count .. " of " .. itemToImport.displayName)
  162.         local importedAmount, importError = bridge.importItem(importFilter, "up")
  163.         if importError then
  164.             print("    ERROR importing " .. itemToImport.displayName .. ": " .. importError)
  165.         elseif importedAmount > 0 then
  166.             print("    Successfully imported " .. importedAmount .. " of " .. itemToImport.displayName)
  167.             if importedAmount < itemToImport.count then print("    WARN: Imported " .. importedAmount .. "/" .. itemToImport.count) end
  168.         else
  169.             print("    Imported 0 of " .. itemToImport.displayName .. ". (No error, 0 moved)")
  170.         end
  171.         os.sleep(0.2)
  172.     end
  173.     print("Finished returning items.")
  174. end
  175.  
  176.  
  177. local function getItemsFromME(itemsToGet)
  178.     print("Requesting items from ME system (at home):")
  179.     -- Assumes turtle is AT HOME_WARP_POINT and has been refueled.
  180.     local successfullyFetched = {}
  181.  
  182.     for _, itemReq in ipairs(itemsToGet) do
  183.         local itemName = itemReq.item
  184.         local itemDisplayName = itemReq.displayName
  185.         local neededCount = itemReq.needed
  186.         if neededCount <= 0 then goto continue_me_req_v21 end
  187.  
  188.         print("- Need " .. neededCount .. " of " .. itemDisplayName .. " (" .. itemName .. ")")
  189.         local emptySlot = findEmptySlot()
  190.         if not emptySlot then print("  No empty slot. Skipping further ME requests.") break end
  191.         turtle.select(emptySlot)
  192.  
  193.         local exportFilter = {name=itemName, count=neededCount}
  194.         if itemReq.nbt then exportFilter.nbt = itemReq.nbt end
  195.  
  196.         print("  Exporting " .. neededCount .. " " .. itemDisplayName .. "...")
  197.         local exportedAmount, exportReason = bridge.exportItem(exportFilter, "up")
  198.  
  199.         if not exportedAmount or exportedAmount == 0 then
  200.             print("  ERROR or No items exported for " .. itemDisplayName .. ": " .. (exportReason or "0 items"))
  201.             goto continue_me_req_v21
  202.         end
  203.        
  204.         print("  ME Bridge exported " .. exportedAmount .. ". Turtle up to access IO chest.")
  205.         turtle.up()
  206.         local itemActuallySucked = 0
  207.         turtle.select(emptySlot)
  208.         for _ = 1, exportedAmount do
  209.             if turtle.suck(1) then itemActuallySucked = itemActuallySucked + 1 else break end
  210.         end
  211.         turtle.down()
  212.  
  213.         if itemActuallySucked > 0 then
  214.             local fetchedDetail = turtle.getItemDetail(emptySlot)
  215.             print("  Sucked " .. itemActuallySucked .. " of " .. fetchedDetail.displayName .. " into slot " .. emptySlot)
  216.             table.insert(successfullyFetched, {
  217.                 slot = emptySlot, name = fetchedDetail.name, displayName = fetchedDetail.displayName,
  218.                 count = itemActuallySucked, nbt = fetchedDetail.nbt
  219.             })
  220.             if itemActuallySucked < neededCount then print("  WARN: Received " ..itemActuallySucked.."/"..neededCount) end
  221.         elseif exportedAmount > 0 then
  222.              print("  Exported " .. exportedAmount .. " but failed to suck " .. itemDisplayName)
  223.         end
  224.         ::continue_me_req_v21::
  225.     end
  226.     consolidateInventory()
  227.     return successfullyFetched
  228. end
  229.  
  230. local function deliverItems(deliveryWarpPointName, itemsToDeliver)
  231.     print("Attempting delivery to " .. deliveryWarpPointName)
  232.     -- Assumes warpTo this point was successful before calling.
  233.     print("Delivering items by dropping down:")
  234.     local allDelivered = true
  235.     for _, itemDetail in ipairs(itemsToDeliver) do
  236.         turtle.select(itemDetail.slot)
  237.         local currentItemInSlot = turtle.getItemDetail(itemDetail.slot)
  238.         if currentItemInSlot and currentItemInSlot.name == itemDetail.name and (currentItemInSlot.nbt == itemDetail.nbt) then
  239.             local countToDrop = currentItemInSlot.count
  240.             print("  Dropping " .. countToDrop .. " of " .. itemDetail.displayName .. " (Slot " .. itemDetail.slot .. ")")
  241.             if turtle.dropDown(countToDrop) then
  242.                 print("    Dropped successfully.")
  243.             else
  244.                 print("    DropDown failed. Trying alternative (L, F, Drop)...")
  245.                 turtle.turnLeft() turtle.forward()
  246.                 if turtle.dropDown(countToDrop) then
  247.                     print("    Dropped at alternative spot.")
  248.                 else
  249.                     print("    ERROR: Failed at alternative spot for " .. itemDetail.displayName)
  250.                     allDelivered = false
  251.                 end
  252.                 turtle.back() turtle.turnRight() -- Return to original orientation
  253.             end
  254.         else
  255.             print("  WARN: Item " .. itemDetail.displayName .. " (NBT: "..(itemDetail.nbt or "nil")..") not in slot " .. itemDetail.slot .. " as expected.")
  256.             allDelivered = false
  257.         end
  258.     end
  259.     if allDelivered then print("All items in batch appear delivered to " .. deliveryWarpPointName)
  260.     else print("Some items could not be delivered to " .. deliveryWarpPointName .. ". They remain in turtle.") end
  261.     return allDelivered
  262. end
  263. -- END OF HELPER FUNCTION DEFINITIONS
  264.  
  265.  
  266. -- Function to ensure turtle is at home and prepared (fueled, inventory cleared)
  267. function prepareAtHomeBase()
  268.     print("Ensuring turtle is prepared at home base...")
  269.     if not warpTo(HOME_WARP_POINT) then
  270.         print("CRITICAL: Cannot reach " .. HOME_WARP_POINT .. " to prepare.")
  271.         print("Please manually move turtle home, ensure coal, refuel, save 'home' warp, then restart script.")
  272.         return false -- Fatal error for this attempt
  273.     end
  274.  
  275.     -- Now at home, ensure fuel and clear inventory
  276.     if not ensureFuel() then
  277.         print("CRITICAL: Failed to ensure fuel at " .. HOME_WARP_POINT .. ".")
  278.         return false -- Fatal error for this attempt
  279.     end
  280.  
  281.     returnUnusedItemsToME() -- Clear out any old items
  282.     print("Turtle is at home and prepared.")
  283.     return true
  284. end
  285.  
  286.  
  287. -- MAIN SCRIPT EXECUTION
  288. if not checkPeripherals() then
  289.     print("Initial peripheral check failed. Please fix and restart. Exiting.")
  290.     return
  291. end
  292.  
  293. print("Builder Bot v2.1 Starting Up...")
  294. if not prepareAtHomeBase() then
  295.     print("Initial home preparation failed. Waiting 5 minutes before retrying...")
  296.     os.sleep(300)
  297.     if not prepareAtHomeBase() then -- Second attempt
  298.          print("Second attempt at home preparation failed. Exiting script.")
  299.          return
  300.     end
  301. end
  302. print("Successfully initialized at home base. Starting main loop.")
  303.  
  304.  
  305. -- Main Operational Loop
  306. while true do
  307.     print("\n--- Starting New Operational Cycle ---")
  308.     local workOrderFoundAndTargeted = false
  309.     local actualDeliveryWarpPoint = nil
  310.     local originalTargetBuildingName = nil
  311.     local currentWorkOrderItems = nil
  312.  
  313.     -- 1. Go to Colony to check for work orders
  314.     print("Going to colony to check for work orders...")
  315.     if not warpTo(COLONY_WARP_POINT) then
  316.         print("Failed to reach colony. Will attempt to return home and restart cycle.")
  317.         if not prepareAtHomeBase() then -- Try to recover by going home
  318.             print("CRITICAL: Could not return home after failing to reach colony. Waiting 5 mins...")
  319.             os.sleep(300) -- Long pause before trying the whole loop again
  320.         end
  321.         goto continue_main_loop_v21
  322.     end
  323.  
  324.     -- Now at COLONY_WARP_POINT, access colonyIntegrator
  325.     print("At colony. Checking for work orders...")
  326.     local workOrders = colony.getWorkOrders()
  327.     if not workOrders or #workOrders == 0 then
  328.         print("No active work orders found.")
  329.     else
  330.         for _, wo in ipairs(workOrders) do
  331.             -- (Logic to parse wo, get resources, determine if itemsNeededForThisOrder, needsSomething - from previous script)
  332.             local itemsNeededForThisOrder = {}
  333.             local needsSomething = false
  334.             local resources = colony.getWorkOrderResources(wo.id)
  335.             if resources and #resources > 0 then
  336.                 for _, res in ipairs(resources) do
  337.                      if res.needed > 0 and (res.available == false or (res.status and string.lower(res.status) ~= "met" and string.lower(res.status) ~= "fulfilled")) then
  338.                         table.insert(itemsNeededForThisOrder, {item = res.item, displayName = res.displayName, needed = res.needed, nbt = res.nbt})
  339.                         needsSomething = true
  340.                     end
  341.                 end
  342.             end
  343.  
  344.             if needsSomething then
  345.                 originalTargetBuildingName = wo.buildingName or "Unknown Target"
  346.                 currentWorkOrderItems = itemsNeededForThisOrder
  347.                 if wo.buildingName and not string.match(string.lower(wo.buildingName), "com.minecolonies.building.") and not string.match(string.lower(wo.buildingName), "minecolonies:") then
  348.                     actualDeliveryWarpPoint = wo.buildingName .. NAMED_BUILDING_STORAGE_SUFFIX
  349.                 elseif wo.builder and wo.builder.x ~= nil then
  350.                     actualDeliveryWarpPoint = wo.builder.x .. "," .. wo.builder.y .. "," .. wo.builder.z
  351.                 else
  352.                     actualDeliveryWarpPoint = nil -- Cannot determine warp
  353.                 end
  354.                
  355.                 if actualDeliveryWarpPoint then
  356.                     print("Targeting Work Order for: " .. originalTargetBuildingName .. " (Warp: " .. actualDeliveryWarpPoint .. ")")
  357.                     workOrderFoundAndTargeted = true
  358.                     break -- Found a work order to process
  359.                 else
  360.                     print("Found work order for "..originalTargetBuildingName.." but could not determine valid warp point.")
  361.                 end
  362.             end
  363.         end
  364.     end
  365.  
  366.     -- 2. Decision point: Got a work order?
  367.     if workOrderFoundAndTargeted and actualDeliveryWarpPoint and currentWorkOrderItems then
  368.         print("Work order identified. Returning home to fetch items for: " .. originalTargetBuildingName)
  369.         if not warpTo(HOME_WARP_POINT) then
  370.             print("Failed to warp home to get items. Cycle will restart.")
  371.             -- prepareAtHomeBase() will be called at the start of the next loop iteration
  372.             goto continue_main_loop_v21
  373.         end
  374.  
  375.         -- Now at HOME_WARP_POINT, ensure fuel and get items
  376.         if not ensureFuel() then -- Quick fuel check/top-up
  377.             print("Failed to ensure fuel at home before getting items. Cycle will restart.")
  378.             goto continue_main_loop_v21
  379.         end
  380.  
  381.         local fetchedItems = getItemsFromME(currentWorkOrderItems)
  382.         if not fetchedItems or #fetchedItems == 0 then
  383.             print("No items fetched from ME for " .. originalTargetBuildingName .. ". Cycle will restart.")
  384.             -- Leftover items (if any) will be handled by prepareAtHomeBase on next loop
  385.             goto continue_main_loop_v21
  386.         end
  387.  
  388.         -- 3. Deliver Items
  389.         print("Items fetched. Proceeding to deliver to " .. originalTargetBuildingName .. " via warp " .. actualDeliveryWarpPoint)
  390.         if warpTo(actualDeliveryWarpPoint) then
  391.             deliverItems(actualDeliveryWarpPoint, fetchedItems)
  392.         else
  393.             print("Failed to warp to delivery point " .. actualDeliveryWarpPoint .. ". Items remain in turtle.")
  394.             -- Items will be returned to ME by prepareAtHomeBase() on next loop
  395.         end
  396.         print("Delivery attempt for " .. originalTargetBuildingName .. " complete.")
  397.  
  398.     else
  399.         print("No suitable work orders found this cycle, or failed to target one.")
  400.         -- If not already home, go home before waiting.
  401.         print("Returning home to wait.")
  402.         if not warpTo(HOME_WARP_POINT) then
  403.              print("Failed to return home. Will retry preparation next cycle.")
  404.              -- The prepareAtHomeBase() at the start of the loop will handle this.
  405.         end
  406.     end
  407.  
  408.     print("Cycle finished. Waiting 60 seconds before next cycle.")
  409.     os.sleep(60)
  410.    
  411.     -- Before looping, ensure we are prepared at home base for the next iteration
  412.     if not prepareAtHomeBase() then
  413.         print("Failed home preparation before new cycle. Waiting 5 minutes...")
  414.         os.sleep(300)
  415.         if not prepareAtHomeBase() then
  416.              print("Second attempt at home preparation failed. Exiting script to prevent issues.")
  417.              return -- Hard stop if can't get to a good state
  418.         end
  419.     end
  420.  
  421.     ::continue_main_loop_v21::
  422. end
Add Comment
Please, Sign In to add comment