Advertisement
Cool_Banana

Applied Energistics 2 Minecolonies warehouse integration

May 7th, 2025 (edited)
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 11.35 KB | Source Code | 0 0
  1. -- Original author: Scott Adkins <[email protected]> (Zucanthor)
  2. -- Heavy modifications: Zygmut
  3. --
  4. -- This program monitors work requests for the Minecolonies Warehouse and
  5. -- tries to fulfill requests from the Applied Energistics 2 network. If the
  6. -- AE2 network doesn't have enough items and a crafting pattern exists, a
  7. -- crafting job is scheduled to restock the items in order to fulfill the
  8. -- work request.  The script will continuously loop, monitoring for new
  9. -- requests and checking on crafting jobs to fulfill previous requests.
  10. --
  11. -- The following is required for setup:
  12. --   * 1 ComputerCraft Computer
  13. --   * 1 or more ComputerCraft Monitors (recommend 3x3 advanced monitors)
  14. --   * 1 Advanced Peripheral Colony Integrator
  15. --   * 1 Advanced Peripheral AE2 Bridge
  16. --   * 1 Chest or other storage container
  17. -- Attach an AE2 Cable from the AE2 network to the AE2 Bridge. Connect the
  18. -- storage container to the Minecolonies Warehouse Hut block directly or
  19. -- to an ender chest and then pipe ender chest contents out to the warehouse
  20. -- racks. Latter makes it easier to upgrade warehouse.
  21.  
  22. -- Prints strings left, centered, or right justified at a specific row and
  23. -- specific foreground/background color.
  24. function MonPrintRow(monitor, y, position, text, textColor, bgColor)
  25.     local w = select(1, monitor.getSize())
  26.     local fg = monitor.getTextColor()
  27.     local bg = monitor.getBackgroundColor()
  28.  
  29.     local positions = {
  30.         left   = 1,
  31.         center = math.floor((w - #text) / 2),
  32.         right  = w - #text,
  33.     }
  34.  
  35.     local x = positions[position] or 1
  36.  
  37.     if textColor then monitor.setTextColor(textColor) end
  38.     if bgColor then monitor.setBackgroundColor(bgColor) end
  39.  
  40.     monitor.setCursorPos(x, y)
  41.     monitor.write(text)
  42.     monitor.setTextColor(fg)
  43.     monitor.setBackgroundColor(bg)
  44.  
  45.     return y + 1
  46. end
  47.  
  48. -- Utility function that displays current time and remaining time on timer.
  49. -- For time of day, yellow is day, orange is sunset/sunrise, and red is night.
  50. -- The countdown timer is orange over 15s, yellow under 15s, and red under 5s.
  51. -- At night, the countdown timer is red and shows PAUSED insted of a time.
  52. function DisplayTimer(monitor, time)
  53.     local now = os.time()
  54.     local cycle = "day"
  55.     local cycle_color = colors.orange
  56.  
  57.     if now >= 4 and now < 6 then
  58.         cycle = "sunrise"
  59.         cycle_color = colors.orange
  60.     elseif now >= 6 and now < 18 then
  61.         cycle = "day"
  62.         cycle_color = colors.yellow
  63.     elseif now >= 18 and now < 19.5 then
  64.         cycle = "sunset"
  65.         cycle_color = colors.orange
  66.     elseif now >= 19.5 or now < 5 then
  67.         cycle = "night"
  68.         cycle_color = colors.red
  69.     end
  70.  
  71.     MonPrintRow(monitor, 1, "left", string.format("Time: %s [%s]", textutils.formatTime(now, false), cycle), cycle_color)
  72.  
  73.     if cycle ~= "night" then
  74.         MonPrintRow(monitor, 1, "right", string.format("Remaining: %ss", time), colors.blue)
  75.     else
  76.         MonPrintRow(monitor, 1, "right", "Remaining: PAUSED", colors.red)
  77.     end
  78.  
  79.     return cycle
  80. end
  81.  
  82. -- Scan all open work requests from the Warehouse and attempt to satisfy those
  83. -- requests. This function is not called at night to save on some ticks, as the
  84. -- colonists are in bed anyways. Item colors go as follow:
  85. --   - Red: Work order can't be satisfied
  86. --          (lack of pattern or lack of required crafting ingredients).
  87. --   - Yellow: Order partially filled and a crafting job was scheduled for the
  88. --              rest.
  89. --   - Green: Order fully filled.
  90. function ScanWorkRequests(monitor, bridge, storage, colony)
  91.     local requests = {}
  92.  
  93.     for _, request in pairs(colony.getRequests()) do
  94.         local name = request.name
  95.         local item = request.items[1].name
  96.         local target = request.target
  97.         local desc = request.desc
  98.         local needed = request.count
  99.  
  100.         local target_words = {}
  101.         local target_length = 0
  102.         local target_name
  103.         for word in target:gmatch("%S+") do
  104.             table.insert(target_words, word)
  105.             target_length = target_length + 1
  106.         end
  107.  
  108.         if target_length >= 3 then target_name = target_words[target_length-2] .. " " .. target_words[target_length]
  109.         else target_name = target end
  110.  
  111.         local target_type = ""
  112.         local target_count = 1
  113.         repeat
  114.             if target_type ~= "" then target_type = target_type .. " " end
  115.             target_type = target_type .. target_words[target_count]
  116.             target_count = target_count + 1
  117.         until target_count > target_length - 3
  118.  
  119.         -- Items like armor or weapons are not strictly bound to one possible
  120.         -- request. For example, a Tier 2 Guard Tower will ask you to provide
  121.         -- a Stone Sword, but a Wooden one will also work.
  122.         -- Ideally, we want to provide the best item for the given tier and
  123.         -- if not possible, give it the next "worst" option
  124.         -- It works by checking from the worst item and saving the one that
  125.         -- either yyou ahve in storage or can craft until the tier that the
  126.         -- guard asked. That is not even the "best" solution, as you can give
  127.         -- better items that are not said within the GUI but can be explored
  128.         -- through the request system. so it's a nice balance
  129.         local display_name
  130.         if string.find(desc, "with") then
  131.             local level = "Any Level"
  132.             if string.find(desc, "with maximal level: Leather") then level = "Leather" end
  133.             if string.find(desc, "with maximal level: Gold") then level = "Gold" end
  134.             if string.find(desc, "with maximal level: Chain") then level = "Chain" end
  135.             if string.find(desc, "with maximal level: Wood or Gold") then level = "Wood or Gold" end
  136.             if string.find(desc, "with maximal level: Stone") then level = "Stone" end
  137.             if string.find(desc, "with maximal level: Iron") then level = "Iron" end
  138.             if string.find(desc, "with maximal level: Diamond") then level = "Diamond" end
  139.  
  140.             local max_item
  141.             local last_item
  142.  
  143.             for _, item in pairs(request.items) do
  144.                 if (bridge.getItem({name=item.name}) or {count = 0}).count > 0 then
  145.                     max_item = item
  146.                 end
  147.  
  148.                 if bridge.isItemCraftable({name=item.name}) then
  149.                     max_item = item
  150.                 end
  151.  
  152.                 last_item = item
  153.  
  154.                 if string.find(item.displayName, level) then
  155.                     break
  156.                 end
  157.             end
  158.  
  159.  
  160.             local best_item
  161.  
  162.             if max_item ~= nil then
  163.                 best_item = max_item
  164.             else
  165.                 best_item = last_item
  166.             end
  167.             display_name = string.gsub(best_item.displayName, "[%[%]]", "")
  168.             item = best_item.name
  169.  
  170.         end
  171.  
  172.         local color
  173.  
  174.         local provided = (bridge.getItem({name=item}) or {count = 0}).count
  175.  
  176.         if provided >= needed then
  177.             color = colors.green
  178.             provided = bridge.exportItem({name=item, count=needed}, storage)
  179.         elseif bridge.isItemCrafting({name=item}) then
  180.             color = colors.yellow
  181.         elseif bridge.isItemCraftable({name=item}) and bridge.craftItem({name=item, count=needed}) then
  182.             color = colors.orange
  183.         else
  184.             color = colors.red
  185.         end
  186.  
  187.         if string.find(desc, "with") then
  188.             table.insert(requests, {
  189.                 name     = needed .. " " .. display_name,
  190.                 target   = target_type .. " " .. target_name,
  191.                 needed   = needed,
  192.                 provided = provided,
  193.                 color    = color
  194.             })
  195.  
  196.         elseif string.find(target, "Builder") then
  197.             table.insert(requests, {
  198.                 name     = string.gsub(name, "^%d%-", ""),
  199.                 item     = item,
  200.                 target   = target_name,
  201.                 needed   = needed,
  202.                 provided = provided,
  203.                 color    = color
  204.             })
  205.  
  206.         else
  207.             local new_target = target_type .. " " .. target_name
  208.             if target_length < 3 then
  209.                 new_target = target
  210.             end
  211.  
  212.             table.insert(requests, {
  213.                 name     = string.gsub(name, "^%d%-", ""),
  214.                 target   = new_target,
  215.                 needed   = needed,
  216.                 provided = provided,
  217.                 color    = color
  218.             })
  219.         end
  220.     end
  221.  
  222.     table.sort(requests, function(left, right)
  223.         return left.target < right.target
  224.     end)
  225.  
  226.     monitor.clear()
  227.  
  228.     local row = 3
  229.     if #requests == 0 then
  230.         MonPrintRow(monitor, row, "center", "No Open Requests")
  231.     else
  232.         row = MonPrintRow(monitor, row, "center", "REQUESTS")
  233.  
  234.         local padding = 0
  235.  
  236.         for _, line in pairs(requests) do
  237.             local number = string.match(line.needed, "^%d+")
  238.             if number and #number > padding then
  239.                 padding = #number
  240.             end
  241.         end
  242.  
  243.         for _, request in pairs(requests) do
  244.             local number, rest = string.match(request.name, "^(%d+)%s+(.*)")
  245.             number = number or ""
  246.             MonPrintRow(monitor, row, "left", string.format("%d" .. string.rep(" ", padding - #number ) .. " %s", number, rest), request.color)
  247.             MonPrintRow(monitor, row, "right", " " .. request.target, request.color)
  248.             row = row + 1
  249.         end
  250.     end
  251. end
  252. function Main()
  253.  
  254.     local monitor = peripheral.find("monitor")
  255.     if not monitor then error("Monitor not found.") end
  256.     monitor.setTextScale(0.5)
  257.     monitor.clear()
  258.     monitor.setTextColor(colors.white)
  259.     monitor.setCursorPos(1, 1)
  260.     monitor.setCursorBlink(false)
  261.     print("Monitor initialized.")
  262.  
  263.     local bridge = peripheral.find("meBridge")
  264.     if not bridge then error("ME Bridge not found.") end
  265.     print("ME Bridge initialized.")
  266.  
  267.     local colony = peripheral.find("colonyIntegrator")
  268.     if not colony then error("Colony Integrator not found.") end
  269.     if not colony.isInColony then error("Colony Integrator is not in a colony.") end
  270.     print("Colony Integrator initialized.")
  271.  
  272.     -- This can be changed to suit your needs. Remember that this will position
  273.     -- will be relative to the ME bridge
  274.     local storage = "down"
  275.     print("Storage initialized.")
  276.  
  277.     local time_between_runs = 1
  278.     local current_run = time_between_runs
  279.     ScanWorkRequests(monitor, bridge, storage, colony)
  280.     DisplayTimer(monitor, current_run)
  281.     local TIMER = os.startTimer(1)
  282.  
  283.     while true do
  284.         local e = {os.pullEvent()}
  285.         if e[1] == "timer" and e[2] == TIMER then
  286.             local now = os.time()
  287.             if now >= 5 and now < 19.5 then
  288.                 current_run = current_run - 1
  289.                 if current_run <= 0 then
  290.                     ScanWorkRequests(monitor, bridge, storage, colony)
  291.                     current_run = time_between_runs
  292.                 end
  293.             end
  294.             DisplayTimer(monitor, current_run)
  295.             TIMER = os.startTimer(1)
  296.         elseif e[1] == "monitor_touch" then
  297.             os.cancelTimer(TIMER)
  298.             ScanWorkRequests(monitor, bridge, storage, colony)
  299.             current_run = time_between_runs
  300.             DisplayTimer(monitor, current_run)
  301.             TIMER = os.startTimer(1)
  302.         end
  303.     end
  304.  
  305. end
  306.  
  307. Main()
  308.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement