Advertisement
Walhfort

RSWarhouse Minecolonies

Aug 5th, 2024
241
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 19.60 KB | Gaming | 0 0
  1. -- RSWarehouse.lua
  2. -- Author: Scott Adkins <[email protected]> (Zucanthor)
  3. -- Published: 2021-09-21
  4. -- Greene5300: i am new to programming in general, i love this script but would still like to allow for
  5. -- userinput to decide for .nbt items and the like without needing to edit the code directly.
  6. --
  7. --
  8. -- This program monitors work requests for the Minecolonies Warehouse and
  9. -- tries to fulfill requests from the Refined Storage network. If the
  10. -- RS network doesn't have enough items and a crafting pattern exists, a
  11. -- crafting job is scheduled to restock the items in order to fulfill the
  12. -- work request.  The script will continuously loop, monitoring for new
  13. -- requests and checking on crafting jobs to fulfill previous requests.
  14. -- The following is required for setup:
  15. --   * 1 ComputerCraft Computer
  16. --   * 1 or more ComputerCraft Monitors (recommend 3x3 monitors)
  17. --   * 1 Advanced Peripheral Colony Integrator
  18. --   * 1 Advanced Peripheral RS Bridge
  19. --   * 1 Chest or other storage container
  20. -- Attach an RS Cable from the RS network to the RS Bridge. Connect the
  21. -- storage container to the Minecolonies Warehouse Hut block. One idea is
  22. -- to set up a second RS network attached to the Warehouse Hut using an
  23. -- External Storage connector and then attach an Importer for that network
  24. -- to the storage container.
  25. -- THINGS YOU CAN CUSTOMIZE IN THIS PROGRAM:
  26. -- Line 59: Specify the side storage container is at.
  27. -- Line 66: Name of log file for storing JSON data of all open requests.
  28. -- Lines 231+: Any items you find that should be manually provided.
  29. -- Line 373: Time in seconds between work order scans.
  30. ----------------------------------------------------------------------------
  31. -- INITIALIZATION
  32. ----------------------------------------------------------------------------
  33. -- Initialize Monitor
  34. -- A future update may allow for multiple monitors. This would allow one
  35. -- monitor to be used for logging and another to be used for work requests.
  36. local monitor = peripheral.find("monitor")
  37. if not monitor then error("Monitor not found.") end
  38. monitor.setTextScale(0.5)
  39. monitor.clear()
  40. monitor.setCursorPos(1, 1)
  41. monitor.setCursorBlink(false)
  42. print("Monitor initialized.")
  43.  
  44. -- Initialize RS Bridge
  45. local bridge = peripheral.find("rsBridge")
  46. if not bridge then error("RS Bridge not found.") end
  47. print("RS Bridge initialized.")
  48.  
  49. -- Initialize Colony Integrator
  50. local colony = peripheral.find("colonyIntegrator")
  51. if not colony then error("Colony Integrator not found.") end
  52. if not colony.isInColony then error("Colony Integrator is not in a colony.") end
  53. print("Colony Integrator initialized.")
  54.  
  55. -- Point to location of chest or storage container
  56. -- A future update may autodetect where the storage container is and error
  57. -- out if no storage container is found.
  58. local storage = "left"
  59. print("Storage initialized.")
  60.  
  61. -- Name of log file to capture JSON data from the open requests.  The log can
  62. -- be too big to edit within CC, which may require a "pastebin put" if you want
  63. -- to look at it.  Logging could be improved to only capture Skipped items,
  64. -- which in turn will make log files smaller and edittable in CC directly.
  65.  
  66. -- Greene5300 start of madnesss If you are reading this mess tell me how to optimize this I'm new
  67.  
  68. local logFile = "RSWarehouse.log"
  69. local useNBT = false
  70. print("Do you want to use NBT items? This includes armor,tools, and enchantments. Answer true or false")
  71. useNBT = read()
  72.     -- list all item variables found on 230ih set to 1
  73.  
  74.     -- list all variables convert to 1 or 0
  75.  
  76.     ----------------------------------------------------------------------------
  77.     -- FUNCTIONS----------------------------------------------------------------------------
  78.  
  79.     -- Prints to the screen one row after another, scrolling the screen when
  80.     -- reaching the bottom. Acts as a normal display where text is printed in
  81.     -- a standard way. Long lines are not wrapped and newlines are printed as
  82.     -- spaces, both to be addressed in a future update.
  83.     -- NOTE: No longer used in this program.
  84.     function mPrintScrollable(mon, ...)
  85.         w, h = mon.getSize()
  86.         x, y = mon.getCursorPos()
  87.  
  88.         -- Blink the cursor like a normal display.
  89.         mon.setCursorBlink(true)
  90.  
  91.         -- For multiple strings, append them with a space between each.
  92.         for i = 2, #arg do t = t .. " " .. arg[i] end
  93.         mon.write(arg[1])
  94.         if y >= h then
  95.             mon.scroll(1)
  96.             mon.setCursorPos(1, y)
  97.         else
  98.             mon.setCursorPos(1, y + 1)
  99.         end
  100.     end
  101.  
  102.     -- Prints strings left, centered, or right justified at a specific row and
  103.     -- specific foreground/background color.
  104.     function mPrintRowJustified(mon, y, pos, text, ...)
  105.         w, h = mon.getSize()
  106.         fg = mon.getTextColor()
  107.         bg = mon.getBackgroundColor()
  108.  
  109.         if pos == "left" then x = 1 end
  110.         if pos == "center" then x = math.floor((w - #text) / 2) end
  111.         if pos == "right" then x = w - #text end
  112.  
  113.         if #arg > 0 then mon.setTextColor(arg[1]) end
  114.         if #arg > 1 then mon.setBackgroundColor(arg[2]) end
  115.         mon.setCursorPos(x, y)
  116.         mon.write(text)
  117.         mon.setTextColor(fg)
  118.         mon.setBackgroundColor(bg)
  119.     end
  120.  
  121.     -- Utility function that returns true if the provided character is a digit.
  122.     -- Yes, this is a hack and there are better ways to do this.  Clearly.
  123.     function isdigit(c)
  124.         if c == "0" then return true end
  125.         if c == "1" then return true end
  126.         if c == "2" then return true end
  127.         if c == "3" then return true end
  128.         if c == "4" then return true end
  129.         if c == "5" then return true end
  130.         if c == "6" then return true end
  131.         if c == "7" then return true end
  132.         if c == "8" then return true end
  133.         if c == "9" then return true end
  134.         return false
  135.     end
  136.  
  137.     -- Utility function that displays current time and remaining time on timer.
  138.     -- For time of day, yellow is day, orange is sunset/sunrise, and red is night.
  139.     -- The countdown timer is orange over 15s, yellow under 15s, and red under 5s.
  140.     -- At night, the countdown timer is red and shows PAUSED insted of a time.
  141.     function displayTimer(mon, t)
  142.         now = os.time()
  143.  
  144.         cycle = "day"
  145.         cycle_color = colors.orange
  146.         if now >= 4 and now < 6 then
  147.             cycle = "sunrise"
  148.             cycle_color = colors.orange
  149.         elseif now >= 6 and now < 18 then
  150.             cycle = "day"
  151.             cycle_color = colors.yellow
  152.         elseif now >= 18 and now < 19.5 then
  153.             cycle = "sunset"
  154.             cycle_color = colors.orange
  155.         elseif now >= 19.5 or now < 5 then
  156.             cycle = "night"
  157.             cycle_color = colors.red
  158.         end
  159.  
  160.         timer_color = colors.orange
  161.         if t < 15 then timer_color = colors.yellow end
  162.         if t < 5 then timer_color = colors.red end
  163.  
  164.         mPrintRowJustified(mon, 1, "left", string.format("Time: %s [%s]    ", textutils.formatTime(now, false), cycle), cycle_color)
  165.         if cycle ~= "night" then
  166.             mPrintRowJustified(mon, 1, "right", string.format("    Remaining: %ss", t), timer_color)
  167.         else
  168.             mPrintRowJustified(mon, 1, "right", "    Remaining: PAUSED", colors.red)
  169.         end
  170.     end
  171.  
  172.     -- Scan all open work requests from the Warehouse and attempt to satisfy those
  173.     -- requests.  Display all activity on the monitor, including time of day and the
  174.     -- countdown timer before next scan.  This function is not called at night to
  175.     -- save on some ticks, as the colonists are in bed anyways.  Items in red mean
  176.     -- work order can't be satisfied by Refined Storage (lack of pattern or lack of
  177.     -- required crafting ingredients).  Yellow means order partially filled and a
  178.     -- crafting job was scheduled for the rest.  Green means order fully filled.
  179.     -- Blue means the Player needs to manually fill the work order.  This includes
  180.     -- equipment (Tools of Class), NBT items like armor, weapons and tools, as well
  181.     -- as generic requests ike Compostables, Fuel, Food, Flowers, etc.
  182.     function scanWorkRequests(mon, rs, chest)
  183.         -- Before we do anything, prep the log file for this scan.
  184.         -- The log file is truncated each time this function is called.
  185.         file = fs.open(logFile, "w")
  186.         print("\nScan starting at", textutils.formatTime(os.time(), false) .. " (" .. os.time() .. ").")
  187.  
  188.         -- We want to keep three different lists so that they can be
  189.         -- displayed on the monitor in a more intelligent way.  The first
  190.         -- list is for the Builder requests.  The second list is for the
  191.         -- non-Builder requests.  The third list is for any armor, tools
  192.         -- and weapons requested by the colonists.
  193.         builder_list = {}
  194.         nonbuilder_list = {}
  195.         equipment_list = {}
  196.  
  197.         -- Scan RS for all items in its network. Ignore items with NBT data.
  198.         -- If a Builder needs any items with NBT data, this function will need
  199.         -- to be updated to not ignore those items.
  200.         items = rs.listItems()
  201.         print(os.time().."after listItems")
  202.         item_array = {}
  203.  
  204.         for index, item in ipairs(items) do
  205.             if useNBT == 1 or not item.nbt
  206.             then item_array[item.name] = item.amount
  207.             end
  208.         end
  209.         print(os.time().."after item array creation")
  210.         -- Scan the Warehouse for all open work requests. For each item, try to
  211.         -- provide as much as possible from RS, then craft whatever is needed
  212.         -- after that. Green means item was provided entirely. Yellow means item
  213.         -- is being crafted. Red means item is missing crafting recipe.
  214.         workRequests = colony.getRequests()
  215.         file.write(textutils.serialize(workRequests))
  216.         for w in pairs(workRequests) do
  217.             name = workRequests[w].name
  218.             item = workRequests[w].items[1].name
  219.             target = workRequests[w].target
  220.             desc = workRequests[w].desc
  221.             needed = workRequests[w].count
  222.             provided = 0
  223.  
  224.             print(os.time().."looping on"..name)
  225.  
  226.             target_words = {}
  227.             target_length = 0
  228.             for word in target:gmatch("%S+") do
  229.                 table.insert(target_words, word)
  230.                 target_length = target_length + 1
  231.             end
  232.  
  233.             if target_length >= 3 then
  234.                 target_name = target_words[target_length - 2] .. " " .. target_words[target_length]
  235.             else
  236.                 target_name = target
  237.             end
  238.  
  239.             target_type = ""
  240.             target_count = 1
  241.             repeat
  242.                 if target_type ~= "" then target_type = target_type .. " " end
  243.                 target_type = target_type .. target_words[target_count]
  244.                 target_count = target_count + 1
  245.             until target_count > target_length - 3
  246.             list = {hoe, shovel, axe, pickaxe, bow, sword, shield, helmet, leatherCap, chestplate, tunic, pants, leggings, boots, rallyingBanner, allowAutoCraft, compostable, fertilizer, flowers, food, fuel, smeltableOre}
  247.             useRS = 1
  248.             if string.find(name, "Hoe") then useRS = list.hoe end
  249.             if string.find(name, "Shovel") then useRS = list.shovel end
  250.             if string.find(name, "Axe") then useRS = list.axe end
  251.             if string.find(name, "Pickaxe") then useRS = list.pickaxe end
  252.             if string.find(name, "Bow") then useRS = list.bow end
  253.             if string.find(name, "Sword") then useRS = list.sword end
  254.             if string.find(name, "Shield") then useRS = list.shield end
  255.             if string.find(name, "Helmet") then useRS = list.helmet end
  256.             if string.find(name, "Leather Cap") then useRS = list.leatherCap end
  257.             if string.find(name, "Chestplate") then useRS = list.chestplate end
  258.             if string.find(name, "Tunic") then useRS = list.tunic end
  259.             if string.find(name, "Pants") then useRS = list.pants end
  260.             if string.find(name, "Leggings") then useRS = list.leggings end
  261.             if string.find(name, "Boots") then useRS = list.boots end
  262.             if name == "Rallying Banner" then useRS = list.rallyingBanner end -- bugged in alpha versions
  263.             if name == "Crafter" then useRS = list.allowAutoCraft end
  264.             if name == "Compostable" then useRS = list.compostable end
  265.             if name == "Fertilizer" then useRS = list.fertilizer end
  266.             if name == "Flowers" then useRS = list.flowers end
  267.             if name == "Food" then useRS = list.food end
  268.             if name == "Fuel" then useRS = list.fuel end
  269.             if name == "Smeltable Ore" then useRS = list.smeltableOre end
  270.             if name == "Stack List" then useRS = 1 end
  271.  
  272.             color = colors.blue
  273.             if useRS == 1 then
  274.                 if item_array[item] then
  275.                     provided = rs.exportItemToPeripheral({ name = item, count = needed }, chest)
  276.                 end
  277.  
  278.                 color = colors.green
  279.                 if provided < needed then
  280.                     if rs.isItemCrafting(item) then
  281.                         color = colors.yellow
  282.                         print("[Crafting]", item)
  283.                     else
  284.                         if rs.craftItem({
  285.                             name = item,
  286.                             count = needed
  287.                         }) then
  288.                             color = colors.yellow
  289.                             print("[Scheduled]", needed, "x", item)
  290.                         else
  291.                             color = colors.red
  292.                             print("[Failed]", item)
  293.                         end
  294.                     end
  295.                 end
  296.             else
  297.                 nameString = name .. " [" .. target .. "]"
  298.                 print("[Skipped]", nameString)
  299.             end
  300.  
  301.             if string.find(desc, "of class") then
  302.                 level = "Any Level"
  303.                 if string.find(desc, "with maximal level:Leather") then level = "Leather" end
  304.                 if string.find(desc, "with maximal level:Gold") then level = "Gold" end
  305.                 if string.find(desc, "with maximal level:Chain") then level = "Chain" end
  306.                 if string.find(desc, "with maximal level:Wood or Gold") then level = "Wood or Gold" end
  307.                 if string.find(desc, "with maximal level:Stone") then level = "Stone" end
  308.                 if string.find(desc, "with maximal level:Iron") then level = "Iron" end
  309.                 if string.find(desc, "with maximal level:Diamond") then level = "Diamond" end
  310.                 new_name = level .. " " .. name
  311.                 if level == "Any Level" then new_name = name .. " of any level" end
  312.                 new_target = target_type .. " " .. target_name
  313.                 equipment = {
  314.                     name = new_name,
  315.                     target = new_target,
  316.                     needed = needed,
  317.                     provided = provided,
  318.                     color = color
  319.                 }
  320.                 table.insert(equipment_list, equipment)
  321.             elseif string.find(target, "Builder") then
  322.                 builder = {
  323.                     name = name,
  324.                     item = item,
  325.                     target = target_name,
  326.                     needed = needed,
  327.                     provided = provided,
  328.                     color = color
  329.                 }
  330.                 table.insert(builder_list, builder)
  331.             else
  332.                 new_target = target_type .. " " .. target_name
  333.                 if target_length < 3 then new_target = target end
  334.                 nonbuilder = {
  335.                     name = name,
  336.                     target = new_target,
  337.                     needed = needed,
  338.                     provided = provided,
  339.                     color = color
  340.                 }
  341.                 table.insert(nonbuilder_list, nonbuilder)
  342.             end
  343.         end
  344.  
  345.         print(os.time().."starting do render")
  346.         -- Show the various lists on the attached monitor.
  347.         row = 3
  348.         mon.clear()
  349.  
  350.         header_shown = 0
  351.         for e in pairs(equipment_list) do
  352.             equipment = equipment_list[e]
  353.             if header_shown == 0 then
  354.                 mPrintRowJustified(mon, row, "center", "Equipment")
  355.                 header_shown = 1
  356.                 row = row + 1
  357.             end
  358.             text = string.format("%d %s", equipment.needed, equipment.name)
  359.             mPrintRowJustified(mon, row, "left", text, equipment.color)
  360.             mPrintRowJustified(mon, row, "right", " " .. equipment.target, equipment.color)
  361.             row = row + 1
  362.         end
  363.  
  364.         header_shown = 0
  365.         for b in pairs(builder_list) do
  366.             builder = builder_list[b]
  367.             if header_shown == 0 then
  368.                 if row > 1 then row = row + 1 end
  369.                 mPrintRowJustified(mon, row, "center", "Builder Requests")
  370.                 header_shown = 1
  371.                 row = row + 1
  372.             end
  373.             text = string.format("%d/%s", builder.provided, builder.name)
  374.             mPrintRowJustified(mon, row, "left", text, builder.color)
  375.             mPrintRowJustified(mon, row, "right", " " .. builder.target, builder.color)
  376.             row = row + 1
  377.         end
  378.  
  379.         header_shown = 0
  380.         for n in pairs(nonbuilder_list) do
  381.             nonbuilder = nonbuilder_list[n]
  382.             if header_shown == 0 then
  383.                 if row > 1 then row = row + 1 end
  384.                 mPrintRowJustified(mon, row, "center", "Nonbuilder Requests")
  385.                 header_shown = 1
  386.                 row = row + 1
  387.             end
  388.             text = string.format("%d %s", nonbuilder.needed, nonbuilder.name)
  389.             if isdigit(nonbuilder.name:sub(1, 1)) then text = string.format("%d/%s", nonbuilder.provided, nonbuilder.name) end
  390.             mPrintRowJustified(mon, row, "left", text, nonbuilder.color)
  391.             mPrintRowJustified(mon, row, "right", " " .. nonbuilder.target, nonbuilder.color)
  392.             row = row + 1
  393.         end
  394.  
  395.         if row == 3 then mPrintRowJustified(mon, row, "center", "No Open Requests") end
  396.         print("Scan completed at", textutils.formatTime(os.time(), false) .. " (" .. os.time() .. ").")
  397.         file.close()
  398.     end
  399.  
  400.     ----------------------------------------------------------------------------
  401.     -- MAIN
  402.     ----------------------------------------------------------------------------
  403.  
  404.     -- Scan for requests periodically. This will catch any updates that were
  405.     -- triggered from the previous scan. Right-clicking on the monitor will
  406.     -- trigger an immediate scan and reset the timer. Unfortunately, there is
  407.     -- no way to capture left-clicks on the monitor.
  408.     local time_between_runs = 30
  409.     local current_run = time_between_runs
  410.     scanWorkRequests(monitor, bridge, storage)
  411.     displayTimer(monitor, current_run)
  412.     local TIMER = os.startTimer(1)
  413.  
  414.     while true do
  415.         local e = {os.pullEvent()}
  416.         if e[1] == "timer" and e[2] == TIMER then
  417.             now = os.time()
  418.             if now >= 5 and now < 19.5 then
  419.                 current_run = current_run - 1
  420.                 if current_run <= 0 then
  421.                     scanWorkRequests(monitor, bridge, storage)
  422.                     current_run = time_between_runs
  423.                 end
  424.             end
  425.             displayTimer(monitor, current_run)
  426.             TIMER = os.startTimer(1)
  427.         elseif e[1] == "monitor_touch" then
  428.             os.cancelTimer(TIMER)
  429.             scanWorkRequests(monitor, bridge, storage)
  430.             current_run = time_between_runs
  431.             displayTimer(monitor, current_run)
  432.             TIMER = os.startTimer(1)
  433.         end
  434.     end
  435.  
  436.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement