Necrotico

OC Logistics Robot MK1

Sep 12th, 2021 (edited)
778
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.65 KB | None | 0 0
  1.  
  2. local component = require("component")
  3. local robot = require("robot")
  4. local inventory_controller = component.inventory_controller
  5. local crafting = component.crafting
  6. local fs = require("filesystem")
  7. local os = require("os")
  8.  
  9. local LABELS_FILE = "/home/labels.txt"
  10. local TEMPLATES_FOLDER = "/home/templates"
  11.  
  12. local function mysplit (inputstr, sep)
  13.     if sep == nil then
  14.             sep = "%s"
  15.     end
  16.     local t={}
  17.     for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
  18.             table.insert(t, str)
  19.     end
  20.     return t
  21. end
  22.  
  23. local function readFile(path)
  24.     if not fs.exists(path) then
  25.         return false
  26.     else
  27.         local f_h = fs.open(path, "r")
  28.         local rtn = f_h:read(fs.size(path))
  29.         f_h:close()
  30.         return rtn
  31.     end
  32. end
  33. local function readFileLines(path)
  34.     if not fs.exists(path) then
  35.         return false
  36.     end
  37.     local rtn = {}
  38.     local f_h = fs.open(path, "r")
  39.     local curr_char = f_h:read(1)
  40.     local curr_line_contents = ""
  41.     while curr_char do
  42.         if curr_char == "\n" then
  43.             rtn[#rtn+1] = curr_line_contents
  44.             curr_line_contents = ""
  45.         else
  46.             curr_line_contents = curr_line_contents .. curr_char
  47.         end
  48.         curr_char = f_h:read(1)
  49.     end
  50.     rtn[#rtn+1] = curr_line_contents
  51.     curr_line_contents = ""
  52.     f_h:close()
  53.     return rtn
  54. end
  55. local function writeFile(path, data_string)
  56.     local f_h = fs.open(path, "w")
  57.     f_h:write(data_string)
  58.     f_h:close()
  59. end
  60.  
  61. local function getInventorySize()
  62.     return inventory_controller.getInventorySize(3)
  63. end
  64. local function getStackInSlot(slot)
  65.     return inventory_controller.getStackInSlot(3, slot)
  66. end
  67. local function getStackInInternalSlot(slot)
  68.     return inventory_controller.getStackInInternalSlot(slot)
  69. end
  70. local function suckFromSlot(slot, amount)
  71.     return inventory_controller.suckFromSlot(3, slot, amount)
  72. end
  73.  
  74. local function searchChestForItem(item_label, complex)
  75.     for s=1, 54 do
  76.         local stack_info = getStackInSlot(s)
  77.         if stack_info then
  78.             if stack_info["label"] == item_label then
  79.                 if complex then
  80.                     local rtn = {}
  81.                     rtn["slot"] = s
  82.                     rtn["amount"] = stack_info["size"]
  83.                     return rtn
  84.                 else
  85.                     return s
  86.                 end
  87.             end
  88.         end
  89.         if (s % 5 == 0) then
  90.             os.sleep(0.1)
  91.         end
  92.     end
  93.     return false
  94. end
  95. local function chestContainsItemAmount(item_label, amount)
  96.     local current_amount = 0
  97.     for s=1, 54 do
  98.         local stack_info = getStackInSlot(s)
  99.         if stack_info then
  100.             if stack_info["label"] == item_label then
  101.                 current_amount = current_amount + stack_info["size"]
  102.             end
  103.         end
  104.         if current_amount >= amount then
  105.             return true
  106.         end
  107.         if (s % 5 == 0) then
  108.             os.sleep(0.1)
  109.         end
  110.     end
  111.     return false
  112. end
  113.  
  114. local function getCraftingSlot(slot)
  115.     if slot <= 3 then
  116.         return slot
  117.     elseif slot <= 6 then
  118.         return slot + 1
  119.     else
  120.         return slot + 2
  121.     end
  122. end
  123.  
  124. local item_labels = {}
  125. local function loadItemLabels()
  126.     item_labels = {}
  127.     if not fs.exists(LABELS_FILE) then
  128.         writeFile(LABELS_FILE, "")
  129.         return
  130.     end
  131.     local label_lines = readFileLines(LABELS_FILE)
  132.     for l=1, #label_lines do
  133.         item_labels[l] = label_lines[l]
  134.     end
  135. end
  136. local function getIdByLabel(label)
  137.     for l=1, #item_labels do
  138.         if item_labels[l] == label then
  139.             return l
  140.         end
  141.     end
  142.     local labels_raw = readFile(LABELS_FILE)
  143.     if not labels_raw then
  144.         labels_raw = ""
  145.     end
  146.     if not (labels_raw == "") then
  147.         labels_raw = labels_raw .. "\n"
  148.     end
  149.     labels_raw = labels_raw .. label
  150.     writeFile(LABELS_FILE, labels_raw)
  151.     item_labels[#item_labels+1] = label
  152.     return #item_labels
  153. end
  154.  
  155. local CRAFT_TEMPLATE_SLOTS = {1, 2, 3, 10, 11, 12, 19, 20, 21}
  156. local CRAFT_TEMPLATE_RESULT_SLOT = 4
  157. local function getTemplateSlotItems()
  158.     local rtn = {}
  159.     for i=1, #CRAFT_TEMPLATE_SLOTS do
  160.         if CRAFT_TEMPLATE_SLOTS[i] then
  161.             local stack_info = getStackInSlot(CRAFT_TEMPLATE_SLOTS[i])
  162.             if stack_info then
  163.                 rtn[i] = getIdByLabel(stack_info["label"])
  164.             else
  165.                 rtn[i] = getIdByLabel("none")
  166.             end
  167.         end
  168.     end
  169.     return rtn
  170. end
  171. local function saveCraftTemplate(result_label_arg)
  172.     if not fs.exists(TEMPLATES_FOLDER) then
  173.         fs.makeDirectory(TEMPLATES_FOLDER)
  174.     end
  175.     local result_label = result_label_arg
  176.     if not result_label_arg then
  177.         result_label = getStackInSlot(CRAFT_TEMPLATE_RESULT_SLOT)["label"]
  178.     end
  179.     local result_item = getIdByLabel(result_label)
  180.     local template_file = TEMPLATES_FOLDER .. "/" .. tostring(result_item) .. ".txt"
  181.     if fs.exists(template_file) then
  182.         print("ERROR: Template with name " .. result_label .. " (" .. tostring(result_item) .. ") already exists!")
  183.         return
  184.     end
  185.     local slot_items = getTemplateSlotItems()
  186.     local template_raw = ""
  187.     for s=1, 9 do
  188.         template_raw = template_raw .. tostring(slot_items[s]) .. "\n"
  189.     end
  190.     writeFile(template_file, template_raw)
  191. end
  192.  
  193. local pending_craft_templates = {}
  194.  
  195. local function templateExists(item_id)
  196.     return fs.exists(TEMPLATES_FOLDER .. "/" .. tostring(item_id) .. ".txt")
  197. end
  198. local function getTemplateItemTotals(template_id)
  199.     local rtn = {}
  200.     local rtn_map = {}
  201.     local template_lines = readFileLines(TEMPLATES_FOLDER .. "/" .. tostring(template_id) .. ".txt")
  202.     local noneId = getIdByLabel("none")
  203.     for s=1, 9 do
  204.         if not (tonumber(template_lines[s]) == noneId) then
  205.             local item_id_str = "id:" .. template_lines[s]
  206.             if rtn_map[item_id_str] then
  207.                 rtn[rtn_map[item_id_str]]["total"] = rtn[rtn_map[item_id_str]]["total"] + 1
  208.                 rtn[rtn_map[item_id_str]]["slots"][#rtn[rtn_map[item_id_str]]["slots"]+1] = s
  209.             else
  210.                 local new_obj = {}
  211.                 new_obj["id"] = tonumber(template_lines[s])
  212.                 new_obj["slots"] = {s}
  213.                 new_obj["total"] = 1
  214.                 rtn[#rtn+1] = new_obj
  215.                 rtn_map[item_id_str] = #rtn
  216.             end
  217.         end
  218.     end
  219.     return rtn
  220. end
  221. local function collectItemFromChest(item_label, amount)
  222.     robot.select(16)
  223.     local collected_amount = 0
  224.     while collected_amount < amount do
  225.         local item_slot = searchChestForItem(item_label)
  226.         if item_slot then
  227.             suckFromSlot(item_slot, amount)
  228.         else
  229.             if robot.count(16) > 0 then
  230.                 robot.drop()
  231.             end
  232.             return false
  233.         end
  234.         collected_amount = robot.count(16)
  235.     end
  236.     return true
  237. end
  238. local function requiredTemplateItems(template_id)
  239.     local template_items = getTemplateItemTotals(template_id)
  240.     local rtn = {}
  241.     for i=1, #template_items do
  242.         local chest_contains_items = chestContainsItemAmount(item_labels[template_items[i]["id"]], template_items[i]["total"])
  243.         if not chest_contains_items then
  244.             rtn[#rtn+1] = template_items[i]
  245.         end
  246.     end
  247.     return rtn
  248. end
  249. local function craftItem(item_id)
  250.     if not templateExists(item_id) then
  251.         print("ERROR: Not enough un-craftable " .. item_labels[item_id] .. " for operation!")
  252.         os.exit()
  253.     end
  254.     local required_items = requiredTemplateItems(item_id)
  255.     while #required_items > 0 do
  256.         for r=1, #required_items do
  257.             -- local pending_id = "id:" .. tostring(required_items[r]["id"])
  258.             -- if not pending_craft_templates[pending_id] then
  259.             craftItem(required_items[r]["id"])
  260.             --     pending_craft_templates[pending_id] = true
  261.             -- end
  262.         end
  263.         required_items = requiredTemplateItems(item_id)
  264.     end
  265.     robot.select(16)
  266.     local template_items = getTemplateItemTotals(item_id)
  267.     for i=1, #template_items do
  268.         collectItemFromChest(item_labels[template_items[i]["id"]], template_items[i]["total"])
  269.         for s=1, #template_items[i]["slots"] do
  270.             robot.transferTo(getCraftingSlot(template_items[i]["slots"][s]), 1)
  271.         end
  272.     end
  273.     crafting.craft()
  274.     robot.drop()
  275.     -- if pending_craft_templates["id:" .. tostring(item_id)] then
  276.     --     pending_craft_templates["id:" .. tostring(item_id)] = false
  277.     -- end
  278. end
  279.  
  280. loadItemLabels()
  281.  
  282. local argv = {...}
  283.  
  284. local mode = argv[1] -- "template" or "craft" or "search"
  285.  
  286. if mode == "template" then -- "template" to get the result from the chest, "template result_label" to manually set the label.
  287.     saveCraftTemplate(argv[2])
  288. elseif mode == "craft" then -- "craft template_id amount_number"
  289.     robot.turnLeft()
  290.     argv[3] = argv[3] or 1
  291.     for i=1, tonumber(argv[3]) do
  292.         craftItem(tonumber(argv[2]))
  293.     end
  294.     robot.turnRight()
  295. elseif mode == "search" then -- "search search_string_here"
  296.     if not argv[2] then
  297.         print("ERROR: Invalid search string!")
  298.     else
  299.         local search_results = ""
  300.         for i=1, #item_labels do
  301.             if string.find(item_labels[i]:lower(), argv[2]:lower()) then
  302.                 search_results = search_results .. "[" .. tostring(i) .. "] " .. item_labels[i] .. "\n"
  303.             end
  304.         end
  305.         if search_results == "" then
  306.             print("No templates matched item " .. argv[2])
  307.         else
  308.             print(search_results)
  309.         end
  310.     end
  311. elseif mode then
  312.     print("ERROR: Mode " .. mode .. " is invalid!")
  313. end
  314.  
Add Comment
Please, Sign In to add comment