AgentPothead

RFWarehouse.lua

Feb 9th, 2026
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.63 KB | None | 0 0
  1. -- RSWarehouse.lua
  2. -- Author: Chuck Burgess
  3. -- Updated: 2024-01-15
  4.  
  5. local logFile = "RFWarehouse.log"
  6. local time_between_runs = 30
  7.  
  8. -- Initialize Monitor
  9. -- see: https://www.computercraft.info/wiki/Advanced_Monitor
  10. local monitor = peripheral.find("monitor")
  11. if not monitor then error("Monitor not found.") end
  12. monitor.setTextScale(0.5)
  13. monitor.clear()
  14. monitor.setCursorPos(1, 1)
  15. monitor.setCursorBlink(false)
  16. print("Monitor initialized.")
  17.  
  18. -- Initialize ME Bridge
  19. -- see: https://advancedperipherals.madefor.cc/peripherals/rs_bridge/
  20. local bridge = peripheral.find("me_bridge")
  21. if not bridge then error("ME Bridge not found.") end
  22. print("ME Bridge initialized.")
  23.  
  24. -- Initialize Colony Integrator
  25. -- see: https://docs.advanced-peripherals.de/peripherals/colony_integrator/
  26. local colony = peripheral.find("colony_integrator")
  27. if not colony then error("Colony Integrator not found.") end
  28. if not colony.isInColony then error("Colony Integrator is not in a colony.") end
  29. print("Colony Integrator initialized.")
  30.  
  31. -- Establish the direction to transport the items into the Warehouse based on
  32. -- where the entnglement block is sitting. Default to empty string.
  33. local storage = "Right"
  34. if not storage then error("Warehouse storage not found.") end
  35. local direction = "back"
  36. print("Warehouse storage initialized.")
  37.  
  38. ----------------------------------------------------------------------------
  39. -- FUNCTIONS
  40. ----------------------------------------------------------------------------
  41. --[[
  42. Table.Empty
  43. @desc check to see if a table contains any data
  44. @return boolean
  45. ]]
  46. function table.empty (self)
  47. for _, _ in pairs(self) do
  48. return false
  49. end
  50. return true
  51. end
  52.  
  53. --[[
  54. Write To Log
  55. @desc Write the specified `table` to the file surrounded by the `blockTop` and `blockBottom`
  56. @return void
  57. ]]
  58. function writeToLog(data, blockTop, blockBottom)
  59. file.write("\n")
  60. file.write(blockTop)
  61. file.write("\n")
  62. file.write(textutils.serialize(data, { allow_repetitions = true }))
  63. file.write("\n")
  64. file.write(blockBottom)
  65. file.write("\n")
  66. end
  67.  
  68. --[[
  69. Process Work Request Item
  70. @desc Determine if this item can be delivered to the warehouse from the storage
  71. @return boolean
  72. ]]
  73. function processWorkRequestItem(request)
  74. if string.find(request.desc, "Tool of class") then return false end
  75. if string.find(request.name, "Hoe") then return false end
  76. if string.find(request.name, "Axe") then return false end
  77. if string.find(request.name, "Pickaxe") then return false end
  78. if string.find(request.name, "Bow") then return false end
  79. if string.find(request.name, "Sword") then return false end
  80. if string.find(request.name, "Shield") then return false end
  81. if string.find(request.name, "Helmet") then return false end
  82. if string.find(request.name, "Leather Cap") then return false end
  83. if string.find(request.name, "Chestplate") then return false end
  84. if string.find(request.name, "Tunic") then return false end
  85. if string.find(request.name, "Pants") then return false end
  86. if string.find(request.name, "Leggings") then return false end
  87. if string.find(request.name, "Boots") then return false end
  88. if request.name == "Rallying Banner" then return false end --bugged in alpha versions
  89. if request.name == "Crafter" then return false end
  90. if request.name == "Compostable" then return false end
  91. if request.name == "Fertilizer" then return false end
  92. if request.name == "Flowers" then return false end
  93. if request.name == "Food" then return false end
  94. if request.name == "Fuel" then return false end
  95. if request.name == "Smeltable Ore" then return false end
  96. if request.name == "Stack List" then return false end
  97. -- you can add any new items here if they are found
  98. return true
  99. end
  100.  
  101. --[[
  102. Monitor Print Row Justified
  103. @desc Print a line of data to the in-game monitor
  104. @return void
  105. ]]
  106. function mPrintRowJustified(mon, y, pos, text, textcolor)
  107. w, h = mon.getSize()
  108. fg = colors.white
  109. bg = colors.black
  110.  
  111. if pos == "left" then x = 1 end
  112. if pos == "center" then x = math.floor((w - #text) / 2) end
  113. if pos == "right" then x = w - #text end
  114.  
  115. mon.setTextColor(textcolor)
  116. mon.setCursorPos(x, y)
  117. mon.write(text)
  118. mon.setTextColor(fg)
  119. mon.setBackgroundColor(bg)
  120. end
  121.  
  122. --[[
  123. Display Timer
  124. @desc Update the time on the monitor
  125. @return void
  126. ]]
  127. function displayTimer(mon, t)
  128. now = os.time()
  129. cycle = "day"
  130. cycle_color = colors.orange
  131. if now >= 4 and now < 6 then
  132. cycle = "sunrise"
  133. cycle_color = colors.yellow
  134. elseif now >= 6 and now < 18 then
  135. cycle = "day"
  136. cycle_color = colors.lightBlue
  137. elseif now >= 18 and now < 19.5 then
  138. cycle = "sunset"
  139. cycle_color = colors.magenta
  140. elseif now >= 19.5 or now < 5 then
  141. cycle = "night"
  142. cycle_color = colors.red
  143. end
  144.  
  145. timer_color = colors.green
  146. if t < 15 then timer_color = colors.yellow end
  147. if t < 5 then timer_color = colors.orange end
  148.  
  149. mPrintRowJustified(mon, 1, "left", string.format("Time: %s [%s] ", textutils.formatTime(now, false), cycle), cycle_color)
  150. if cycle ~= "night" then
  151. mPrintRowJustified(mon, 1, "right", string.format(" Remaining: %ss", t), timer_color)
  152. else
  153. mPrintRowJustified(mon, 1, "right", " Remaining: PAUSED", colors.red)
  154. end
  155. end
  156.  
  157. --[[
  158. Create Colonist Data
  159. @desc Build a table of Colonist making the request
  160. @return table
  161. ]]
  162. function createColonistData(colonist)
  163. title_words = {}
  164. words_in_name = 0
  165. colonist_job = ""
  166. word_count = 1
  167.  
  168. for word in colonist:gmatch("%S+") do
  169. table.insert(title_words, word)
  170. words_in_name = words_in_name + 1
  171. end
  172.  
  173. if words_in_name >= 3 then colonist_name = title_words[words_in_name-2] .. " " .. title_words[words_in_name]
  174. else colonist_name = colonist end
  175.  
  176. repeat
  177. if colonist_job ~= "" then colonist_job = colonist_job .. " " end
  178. colonist_job = colonist_job .. title_words[word_count]
  179. word_count = word_count + 1
  180. until word_count > words_in_name - 3
  181.  
  182. return { fullName = colonist, titleWords = title_words, job = colonist_job, name = colonist_name, wordsInName = words_in_name }
  183. end
  184.  
  185. --[[
  186. Get Work Request List (from colony)
  187. @desc Build a table of the work request data from the colony
  188. @return table
  189. ]]
  190. function getWorkRequestList(colony)
  191. requestList = {}
  192. workRequests = colony.getRequests()
  193. file = fs.open(logFile, "w")
  194.  
  195. for w in pairs(workRequests) do
  196. writeToLog(workRequests[w], "--- Request start ---", "--- Request end ---");
  197. name = workRequests[w].name -- the name of the count/item being requested
  198. colonist = createColonistData(workRequests[w].target)
  199. desc = workRequests[w].desc -- the request description
  200. item = {}
  201. -- create the filter item for the transfer request through the bridge
  202. if workRequests[w].items and workRequests[w].items[1] then
  203. if not workRequests[w].items[1].nbt or table.empty(workRequests[w].items[1].nbt) then
  204. item = { name = workRequests[w].items[1].name, count = workRequests[w].count, displayName = workRequests[w].items[1].displayName}
  205. else
  206. item = { name = workRequests[w].items[1].name, count = workRequests[w].count, displayName = workRequests[w].items[1].displayName, nbt = workRequests[w].items[1].nbt}
  207. end
  208. end
  209. -- how many items are needed to fulfill this request?
  210. needed = workRequests[w].count
  211.  
  212. local newRecord = {}
  213. newRecord.name = name
  214. newRecord.desc = desc
  215. newRecord.needed = needed
  216. newRecord.item = item
  217. newRecord.colonist = colonist
  218. table.insert(requestList, newRecord)
  219. writeToLog(newRecord, "--- Record start ---", "--- Record end ---");
  220. end
  221. file.close()
  222. return requestList
  223. end
  224.  
  225. --[[
  226. Display List
  227. @desc Update the monitor with the work request items currently in the system
  228. @return void
  229. ]]
  230. function displayList(mon, listName, itemList)
  231. -- show the list header first
  232. mPrintRowJustified(mon, row, "center", listName, colors.white)
  233. row = row + 1
  234. for e in pairs(itemList) do
  235. record = itemList[e]
  236. text = string.format("%d %s", record.provided , record.name)
  237. mPrintRowJustified(mon, row, "left", text, record.color)
  238. mPrintRowJustified(mon, row, "right", " " .. record.colonist, record.color)
  239. row = row + 1
  240. end
  241. -- add a space at the end of the list
  242. row = row + 1
  243. end
  244.  
  245. -- Color References:
  246. -- RED: work order can't be satisfied by Refined Storage (lack of pattern or lack of
  247. -- required crafting ingredients).
  248. -- YELLOW: order partially filled and a crafting job was scheduled for the rest.
  249. -- GREEN: order fully filled.
  250. -- BLUE: the Player needs to manually fill the work order. This includes some equipment as well as generic requests ike Compostables, Fuel, Food, Flowers, etc.
  251. --[[
  252. Scan Work Requests
  253. @desc Manages all of the open work requests in the system and attempts to fulfill them from the inventory
  254. @desc Not called at night (as determined by the server) since requests cannot be fulfilled anyway
  255. @return void
  256. ]]
  257. function scanWorkRequests(mon, bridge, direction)
  258.  
  259. print("\nScan starting at", textutils.formatTime(os.time(), false) .. " (" .. os.time() ..").")
  260. builder_list = {}
  261. nonbuilder_list = {}
  262. equipment_list = {}
  263. requestList = getWorkRequestList(colony)
  264.  
  265. for j, data in ipairs(requestList) do
  266. color = colors.blue
  267. provided = 0
  268.  
  269. if processWorkRequestItem(data) then
  270. provided = bridge.exportItem(data.item, direction)
  271. color = colors.lightGray
  272. if provided >= data.needed then
  273. color = colors.green
  274. end
  275.  
  276. else
  277. nameString = data.name .. " [" .. data.colonist.fullName .. "]"
  278. print("[Skipped]", nameString)
  279. end
  280. -- ---------------------------------------------------------------------
  281. -- Build the newList data
  282. -- ---------------------------------------------------------------------
  283. -- create the target text
  284. expectedList = "Builder"
  285. colonist = data.colonist.name
  286. if not string.find(data.colonist.fullName, "Builder") then
  287. expectedList = ""
  288. colonist = data.colonist.job .. " " .. data.colonist.name
  289. if data.colonist.wordsInName < 3 then
  290. colonist = data.colonist.name
  291. end
  292. end
  293.  
  294. -- create the name
  295. listName = data.name
  296. if string.find(data.desc, "level") then
  297. expectedList = "Equipment"
  298. level = "Any Level"
  299. if string.find(data.desc, "with maximal level: Leather") then level = "Leather" end
  300. if string.find(data.desc, "with maximal level: Gold") then level = "Gold" end
  301. if string.find(data.desc, "with maximal level: Chain") then level = "Chain" end
  302. if string.find(data.desc, "with maximal level: Wood or Gold") then level = "Wood or Gold" end
  303. if string.find(data.desc, "with maximal level: Stone") then level = "Stone" end
  304. if string.find(data.desc, "with maximal level: Iron") then level = "Iron" end
  305. if string.find(data.desc, "with maximal level: Diamond") then level = "Diamond" end
  306. listName = level .. " " .. data.name
  307. if level == "Any Level" then listName = data.name .. " of any level" end
  308. end
  309.  
  310. -- create the new list table defining what is inserted into a specific list
  311. newList = { name=listName, colonist=colonist, needed=data.needed, provided=provided, color=color}
  312.  
  313. if expectedList == "Equipment" then
  314. table.insert(equipment_list, newList)
  315. elseif expectedList == "Builder" then
  316. table.insert(builder_list, newList)
  317. else
  318. table.insert(nonbuilder_list, newList)
  319. end
  320. -- ---------------------------------------------------------------------
  321. end
  322.  
  323. -- Show the various lists on the attached monitor.
  324. mon.clear()
  325. row = 3
  326. if not table.empty(builder_list) then displayList(mon, "Builder Requests", builder_list) end
  327. if not table.empty(nonbuilder_list) then displayList(mon, "Nonbuilder Requests", nonbuilder_list) end
  328. if not table.empty(equipment_list) then displayList(mon, "Equipment", equipment_list) end
  329.  
  330. -- no requests
  331. if row == 3 then
  332. mPrintRowJustified(mon, row, "center", "No Open Requests", colors.white)
  333. end
  334. print("Scan completed at", textutils.formatTime(os.time(), false) .. " (" .. os.time() ..").")
  335. end
  336.  
  337.  
  338. --[[
  339. MAIN
  340. @desc establish the run times and execute the work request management
  341. @return void
  342. ]]
  343. local current_run = time_between_runs
  344. scanWorkRequests(monitor, bridge, direction)
  345. displayTimer(monitor, current_run)
  346. local TIMER = os.startTimer(1)
  347.  
  348. while true do
  349. local e = {os.pullEvent()}
  350. if e[1] == "timer" and e[2] == TIMER then
  351. now = os.time()
  352. if now >= 5 and now < 19.5 then
  353. current_run = current_run - 1
  354. if current_run <= 0 then
  355. scanWorkRequests(monitor, bridge, direction)
  356. current_run = time_between_runs
  357. end
  358. end
  359. displayTimer(monitor, current_run)
  360. TIMER = os.startTimer(1)
  361. elseif e[1] == "monitor_touch" then
  362. os.cancelTimer(TIMER)
  363. scanWorkRequests(monitor, bridge, direction)
  364. current_run = time_between_runs
  365. displayTimer(monitor, current_run)
  366. TIMER = os.startTimer(1)
  367. end
  368. end
Advertisement
Add Comment
Please, Sign In to add comment