Wassaa

Stock

Jul 5th, 2016
149
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- ********************************************************************************** --
  2. -- **                                                                              ** --
  3. -- **   Minecraft AE2 Auto-Stocker by RandomBlue (E.J. Wilburn)                    ** --
  4. -- **   ----------------------------------------------------                       ** --
  5. -- **                                                                              ** --
  6. -- **   This program automatically crafts items necessary to maintain a minimum    ** --
  7. -- **   stock level of specific items.  The items are configured in a file on      ** --
  8. -- **   a computercraft computer named stock_list.txt in the stocker directory.    ** --
  9. -- **   Examine that file for example formatting and details.                      ** --
  10. -- **                                                                              ** --
  11. -- **   Minimum stock levels and crafting batch sizes are configurable per item.   ** --
  12. -- **                                                                              ** --
  13. -- **   The computer must be placed adjacent to a full block ME Interface attached ** --
  14. -- **   to an ME Network where both the items are stored and the crafting CPUs are ** --
  15. -- **   located.  Each item you wish to maintain a stock level for must have       ** --
  16. -- **   autocrafting enabled for it.                                               ** --
  17. -- **                                                                              ** --
  18. -- **   Arguments                                                                  ** --
  19. -- **   ----------------------------------------------------                       ** --
  20. -- **   checkFrequency (optional) - How often inventory levels are checked in      ** --
  21. -- **                               seconds.                                       ** --
  22. -- **   attachSide (optional)     - Side the computer is attached to the           ** --
  23. -- **                               ME Interface (full block version).             ** --
  24. -- **   stockFileName (optional)  - Full path to the file containing stocking      ** --
  25. -- **                               requirements.                                  ** --
  26. -- **                                                                              ** --
  27. -- **  Change Log:                                                                 ** --
  28. -- **    8th Sep 2015:  [v0.1]  Initial Release                                    ** --
  29. -- **    11th Sep 2015: [v0.11] Minor bug fix - attempting to crafting 0 items     ** --
  30. -- **                           when current quantity equals minQuantity           ** --
  31. -- **                                                                              ** --
  32. -- **  TODO:                                                                       ** --
  33. -- **    1) Save command line parameters to startup script.                        ** --
  34. -- **                                                                              ** --
  35. -- ********************************************************************************** --
  36.  
  37. -- Parameters with default values.
  38. local checkFrequency = 15 -- How often inventory levels are checked in seconds.  Overridden by passing as the first argument.
  39. local attachSide = "bottom" -- Side the computer is attached to the ME Interface (full block version).
  40.                             -- Overridden by passing as the second argument.
  41. local stockFileName = "stocker/stock_list.txt" -- Change this if you want the file somewhere else.  Can be
  42.                                                -- overridden via a parameter.
  43. local recraftDelay = 300 -- Delay, in seconds, before allowing an item to be crafted again.  If them item in question exceeds
  44.                          -- its min quantity before the delay expires, the delay is reset as it's assumed the job
  45.                          -- completed.  300 seconds = 5 minutes
  46. local delayedItems = {} -- List of delayed items by id:variant with delay time in seconds.  Decremented each loop by
  47.                         -- checkFrequency ammount.  When the delay hits 0 or lower then the item is removed from
  48.                         -- the list.
  49.  
  50. local DEBUG = false
  51.  
  52. -- Process the input arguments - storing them to global variables
  53. local args = { ... }
  54.  
  55. function main(args)
  56.     processArgs(args)
  57.     local ae2 = attachToAe2(attachSide)
  58.     local stocks = loadStockFile(stockFileName)
  59.     displayStockingInfo(stocks)
  60.     enableAutoRestart()
  61.  
  62.     while (true) do
  63.         print("[" .. getDisplayTime() .. "] Checking inventory.")
  64.         updateDelayedItems(delayedItems)
  65.         local allItems = getAllItems(ae2)
  66.         for i=1, #allItems do
  67.             if (allItems[i].is_craftable == true) then
  68.                 stockItem(allItems[i], stocks, ae2)
  69.             end
  70.         end
  71.         os.sleep(checkFrequency)
  72.     end
  73. end
  74.  
  75. function isValidSide(side)
  76.     if (side == "left" or side == "right" or side == "top" or side == "bottom" or side == "front" or side == "back") then
  77.         return true
  78.     else
  79.         return false
  80.     end
  81. end
  82.  
  83. function processArgs(args)
  84.     if (#args >= 1) then
  85.         assert(type(args[1]) == "number", "The first parameter (checkFrequency) must be a number.")
  86.         checkFrequency = args[1]
  87.     end
  88.  
  89.     if (#args > 1) then
  90.         assert(type(args[2]) == "string", "The second parameter (attachSide) must be a string.")
  91.         attachSide = args[2]:lower()
  92.     end
  93.     assert(isValidSide(attachSide), "The attachSide parameter must be a valid side: left, right, front, back, top, bottom")
  94.  
  95.     if (#args > 2) then
  96.         assert(type(args[3]) == "string", "The third parameter (stockFileName) must be a string.")
  97.         stockFileName = args[3]
  98.     end
  99.     assert(fs.exists(stockFileName), "The stock file does not exist: " .. stockFileName)
  100. end
  101.  
  102. function attachToAe2(attachSide)
  103.     -- Make sure the attached device is actually an ME Interface.
  104.     assert(peripheral.getType(attachSide) == "tileinterface", "The computer must be attached to a full block " ..
  105.         "ME Inteface on the specified side.")
  106.     return peripheral.wrap(attachSide)
  107. end
  108.  
  109. function loadStockFile(stockFileName)
  110.     local stockFile = fs.open(stockFileName, "r")
  111.     local stockFileContents = stockFile.readAll();
  112.     stockFile.close();
  113.     local outputStocks = textutils.unserialize(stockFileContents)
  114.  
  115.     if (DEBUG) then
  116.         print("Stock file: ")
  117.         print(stockFileContents)
  118.         print("Output stocks length: " .. #outputStocks)
  119.         print("Output stocks: ")
  120.         for i=1, #outputStocks do
  121.             print("itemId: " .. outputStocks[i].itemId)
  122.             print("variant: " .. outputStocks[i].variant)
  123.             print("minQuantity: " .. outputStocks[i].minQuantity)
  124.             print("batchSize: " .. outputStocks[i].batchSize)
  125.         end
  126.     end
  127.  
  128.     assert(#outputStocks > 0, "There are no entries in the " .. stockFileName .. " file.")
  129.     return outputStocks
  130. end
  131.  
  132. function displayStockingInfo(stocks)
  133.     print("Stocking info:")
  134.     for i=1, #stocks do
  135.         print(" itemId: " .. stocks[i].itemId .. ":" .. stocks[i].variant .. " minQuantity: " .. stocks[i].minQuantity ..
  136.             " batchSize: " .. stocks[i].batchSize)
  137.     end
  138. end
  139.  
  140. function getAllItems(ae2)
  141.     local outputAllItems = ae2.getAvailableItems()
  142.     assert(outputAllItems ~= nil, "No craftable items found in this AE2 network.")
  143.     assert(#outputAllItems > 0, "No craftable items found in this AE2 network.")
  144.     return outputAllItems
  145. end
  146.  
  147. function isCpuAvailable(ae2)
  148.     local cpus = ae2.getCraftingCPUs()
  149.     for i=1, #cpus do
  150.         if (cpus[i].busy == false) then return true end
  151.     end
  152.     return false
  153. end
  154.  
  155. function findStockSetting(fingerprint, stocks)
  156.     for i=1, #stocks do
  157.         if (stocks[i].itemId == fingerprint.id and stocks[i].variant == fingerprint.dmg) then
  158.             return stocks[i]
  159.         end
  160.     end
  161.     return nil
  162. end
  163.  
  164. function stockItem(currItem, stocks, ae2)
  165.     local stockSetting = findStockSetting(currItem.fingerprint, stocks)
  166.  
  167.     if (stockSetting == nil or currItem.size >= stockSetting.minQuantity or isDelayed(currItem.fingerprint, delayedItems)
  168.         or isCpuAvailable(ae2) == false) then return end
  169.  
  170.     local neededAmount = math.ceil((stockSetting.minQuantity - currItem.size) / stockSetting.batchSize) * stockSetting.batchSize
  171.  
  172.     ae2.requestCrafting(currItem.fingerprint, neededAmount)
  173.     delayItem(currItem.fingerprint, delayedItems)
  174.     print("[" .. getDisplayTime() .. "] Item " .. stockSetting.displayName ..
  175.         " is below its min stock level of " .. stockSetting.minQuantity .. ".  Crafting " .. neededAmount .. " more.")
  176. end
  177.  
  178. function getDisplayTime()
  179.     return textutils.formatTime(os.time(), false)
  180. end
  181.  
  182. function delayItem(fingerprint, delayedItems)
  183.     local fullItemName = fingerprintToFullName(fingerprint)
  184.    
  185.     if(delayedItems == nil) then
  186.         delayedItems = {}
  187.     end
  188.  
  189.     for i=1, #delayedItems do
  190.         if (delayedItems[i].fullName == fullItemName) then
  191.             delayedItems[i].delay = recraftDelay
  192.             return
  193.         end
  194.     end
  195.  
  196.     local delayedItem = {fullName = fullItemName, delay = recraftDelay}
  197.     delayedItems[#delayedItems+1] = delayedItem
  198. end
  199.  
  200. function updateDelayedItems(delayedItems)
  201.     if (delayedItems == nil or #delayedItems < 1) then return end
  202.  
  203.     local removeIndexes = {}
  204.     for i=1, #delayedItems do
  205.         currItem = delayedItems[i]
  206.         currItem.delay = currItem.delay - checkFrequency
  207.         if (currItem.delay < 0) then
  208.             table.insert(removeIndexes, i)
  209.         end
  210.     end
  211.  
  212.     -- This should remove items from the end of the list towards the beginning
  213.     -- so the list being reordered won't matter.
  214.     for i=1, #removeIndexes do
  215.         table.remove(delayedItems, removeIndexes[i])
  216.     end
  217. end
  218.  
  219. function fingerprintToFullName(fingerprint)
  220.     return fingerprint.id .. ":" .. fingerprint.dmg
  221. end
  222.  
  223. function isDelayed(fingerprint, delayedItems)
  224.     if (delayedItems == nil or #delayedItems < 1) then return false end
  225.  
  226.     local fullItemName = fingerprintToFullName(fingerprint)
  227.     for i=1, #delayedItems do
  228.         if (delayedItems[i].fullName == fullItemName and delayedItems[i].delay > 0) then
  229.             return true
  230.         end
  231.     end
  232.  
  233.     return false
  234. end
  235.  
  236. function enableAutoRestart()
  237.     -- Skip this if any startup file already exists.
  238.     -- Let the user manaully delete or edit the startup file at that point.
  239.     -- Notify the user.
  240.     if (fs.exists("startup") == true) then
  241.         print("Startup file already exists.")
  242.         return
  243.     end
  244.  
  245.     outputFile = fs.open("startup", "w")
  246.  
  247.     -- Write an info message so that people know how to get out of auto-resume
  248.     outputFile.write("\nprint(\"Running auto-restart...\")\n")
  249.     outputFile.write("print(\"If you want to stop auto-resume and restore original state:\")\n")
  250.     outputFile.write("print(\"1) Hold Ctrl-T until the program terminates\")\n")
  251.     outputFile.write("print(\"2) Type \\\"rm startup\\\" (without quotes) and hit Enter\")\n")
  252.     outputFile.write("print(\"\")\n\n")
  253.  
  254.     -- Write the code required to restart the turtle
  255.     outputFile.write("shell.run(\"")
  256.     outputFile.write(shell.getRunningProgram())
  257.     outputFile.write("\")\n")
  258.     outputFile.close()
  259. end
  260.  
  261. -- Start the actual program
  262. main(args)
Add Comment
Please, Sign In to add comment