Advertisement
Necrotico

Computercraft Logistics Drone

Sep 8th, 2021 (edited)
668
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 18.97 KB | None | 0 0
  1. -- Logistics Drone
  2.  
  3. -- DESCRIPTION:
  4. --  When the user has created a suitable storage setup, this program will provide an interface for storage of as many types of items as allowed by the capacity of that storage setup.
  5. --  Once items are stored, the user can define templates that the logistics drone turtle (assuming it is equipped with a crafting table) can use to craft the desired items, with no user intervention.
  6. --  Crafting is likely going to be slower with this program than dedicated crafting machines provided by other mods, but the upside of the program is that it requires much less brain power than mod crafting machines to set up.
  7.  
  8. -- IMPORTANT NOTE:
  9. --  To anyone stumbling on this program, it isn't anywhere near complete yet. If you're interested in this program, check it out later, I might create a detailed guide on how to use it when it's done.
  10.  
  11. -- pastebin get CC2ey4Gi LDrone
  12.  
  13. local argv = {...}
  14.  
  15. local LOGISTICS_DATA = "logistics_data"
  16. local ITEM_MANIFEST = "manifest"
  17. local TEMPLATES_DATA = "templates"
  18.  
  19. local RED_WOOL = "minecraft:wool"
  20. local YELLOW_WOOL = "minecraft:wool"
  21.  
  22. local mode_arg = argv[1] -- "map" or "store" or "get" or "template" or "craft"
  23.  
  24. local drone_level = 1
  25. local drone_column = 0
  26. local drone_row = 0
  27.  
  28. local function parse_row_contents(rowFilePath)
  29.     local rfh = fs.open(rowFilePath, "r")
  30.     local rtn = {}
  31.     rtn[1] = {}
  32.     rtn[1]["name"] = rfh.readLine()
  33.     rtn[1]["count"] = rfh.readLine()
  34.     rtn[2] = {}
  35.     rtn[2]["name"] = rfh.readLine()
  36.     rtn[2]["count"] = rfh.readLine()
  37.     rfh.close()
  38.     return rtn
  39. end
  40.  
  41. local function new_location(level, column, row, chest)
  42.     local rtn = {}
  43.     rtn["level"] = tonumber(level)
  44.     rtn["column"] = tonumber(column)
  45.     rtn["row"] = tonumber(row)
  46.     rtn["chest"] = tonumber(chest)
  47.     return rtn
  48. end
  49.  
  50. local function get_next_free_storage()
  51.     local levels = fs.list(LOGISTICS_DATA)
  52.     for _, level_num in ipairs(levels) do
  53.         local columns = fs.list(LOGISTICS_DATA .. "/" .. level_num)
  54.         for _, column_num in ipairs(columns) do
  55.             local rows = fs.list(LOGISTICS_DATA .. "/" .. level_num .. "/" .. column_num)
  56.             for _, row_file in ipairs(rows) do
  57.                 local row_contents = parse_row_contents(LOGISTICS_DATA .. "/" .. level_num .. "/" .. column_num .. "/" .. row_file)
  58.                 for c=1, 2 do
  59.                     if row_contents[c]["name"] == "none" then
  60.                         return new_location(level_num, column_num, row_file, c)
  61.                     end
  62.                 end
  63.             end
  64.         end
  65.     end
  66.     return false
  67. end
  68. local function get_storage(location)
  69.     return parse_row_contents(LOGISTICS_DATA .. "/" .. location["level"] .. "/" .. location["column"] .. "/" .. location["row"])
  70. end
  71. local function update_storage(location, new_amount, new_item)
  72.     local row_contents = parse_row_contents(LOGISTICS_DATA .. "/" .. location["level"] .. "/" .. location["column"] .. "/" .. location["row"])
  73.     local row_handle = fs.open(LOGISTICS_DATA .. "/" .. location["level"] .. "/" .. location["column"] .. "/" .. location["row"], "w")
  74.     if new_item then
  75.         row_contents[location["chest"]]["name"] = new_item
  76.     end
  77.     row_contents[location["chest"]]["count"] = new_amount
  78.     for c=1, 2 do
  79.         row_handle.writeLine(row_contents[c]["name"])
  80.         row_handle.writeLine(row_contents[c]["count"])
  81.     end
  82.     row_handle.close()
  83. end
  84.  
  85. local function check_manifest(for_item, itemIsFile)
  86.     local m_file = ITEM_MANIFEST .. "/" .. for_item .. ".txt"
  87.     if itemIsFile then
  88.         m_file = for_item
  89.     end
  90.     if fs.exists(m_file) then
  91.         local m_handle = fs.open(m_file, "r")
  92.         local rtn = new_location(m_handle.readLine(), m_handle.readLine(), m_handle.readLine(), m_handle.readLine())
  93.         m_handle.close()
  94.         return rtn
  95.     else
  96.         return false
  97.     end
  98. end
  99. local function new_manifest_item(new_item)
  100.     local m_file = ITEM_MANIFEST .. "/" .. new_item .. ".txt"
  101.     if fs.exists(m_file) then
  102.         fs.delete(m_file)
  103.     end
  104.     local m_handle = fs.open(m_file, "w")
  105.     local nfs = get_next_free_storage()
  106.     m_handle.writeLine(tostring(nfs["level"]))
  107.     m_handle.writeLine(tostring(nfs["column"]))
  108.     m_handle.writeLine(tostring(nfs["row"]))
  109.     m_handle.writeLine(tostring(nfs["chest"]))
  110.     m_handle.close()
  111.     update_storage(nfs, 0, new_item)
  112.     return check_manifest(new_item)
  113. end
  114.  
  115. local function check_fuel()
  116.     if turtle.getFuelLevel() < 80 then
  117.         turtle.select(1)
  118.         turtle.refuel(1)
  119.     end
  120. end
  121.  
  122. local function enter_storage()
  123.     while true do
  124.         check_fuel()
  125.         if not turtle.forward() then
  126.             break
  127.         end
  128.     end
  129. end
  130.  
  131. local function detect_below(item_name)
  132.     if turtle.detectDown() then
  133.         local success, data = turtle.inspectDown()
  134.         return data.name == item_name
  135.     end
  136.     return false
  137. end
  138. local function detect_forward(item_name)
  139.     local sucess, data = turtle.inspect()
  140.     local forwardBlock = data.name
  141.     return forwardBlock == item_name
  142. end
  143.  
  144. local function level_folder(level)
  145.     return LOGISTICS_DATA .. "/" .. tostring(level)
  146. end
  147. local function column_folder(level, column)
  148.     return level_folder(level) .. "/" .. tostring(column)
  149. end
  150. local function row_file(level, column, row)
  151.     return column_folder(level, column) .. "/" .. tostring(row)
  152. end
  153. local function create_level(level)
  154.     fs.makeDir(level_folder(level))
  155. end
  156. local function create_column(level, column)
  157.     fs.makeDir(column_folder(level, column))
  158. end
  159. local function create_row(level, column, row)
  160.     local new_row = "none\n0\nnone\n0"
  161.     local new_row_file = fs.open(row_file(level, column, row), "w")
  162.     new_row_file.write(new_row)
  163.     new_row_file.close()
  164. end
  165. local function map_rows()
  166.     create_column(drone_level, drone_column)
  167.     drone_row = 0
  168.     local dist = 1
  169.     check_fuel()
  170.     while turtle.forward() do
  171.         check_fuel()
  172.         dist = dist + 1
  173.         if dist % 2 == 0 then
  174.             drone_row = drone_row + 1
  175.             create_row(drone_level, drone_column, drone_row)
  176.         end
  177.     end
  178.     while dist > 1 do
  179.         check_fuel()
  180.         turtle.back()
  181.         dist = dist - 1
  182.     end
  183.     turtle.turnRight()
  184.     turtle.forward()
  185. end
  186. local function map_columns()
  187.     create_level(drone_level)
  188.     drone_column = 0
  189.     check_fuel()
  190.     turtle.turnRight()
  191.     while not turtle.detect() do
  192.         while not detect_below(YELLOW_WOOL) do
  193.             check_fuel()
  194.             turtle.forward()
  195.         end
  196.         drone_column = drone_column + 1
  197.         check_fuel()
  198.         turtle.turnLeft()
  199.         map_rows()
  200.     end
  201.     check_fuel()
  202.     turtle.turnLeft()
  203.     turtle.turnLeft()
  204.     while not turtle.detect() do
  205.         check_fuel()
  206.         turtle.forward()
  207.     end
  208.     turtle.turnRight()
  209. end
  210. local function do_map()
  211.     if fs.exists(LOGISTICS_DATA) then
  212.         fs.delete(LOGISTICS_DATA)
  213.         fs.makeDir(LOGISTICS_DATA)
  214.     end
  215.     enter_storage()
  216.     map_columns()
  217.     check_fuel()
  218.     while turtle.up() do
  219.         check_fuel()
  220.         if turtle.detect() then
  221.             if detect_forward(RED_WOOL) then
  222.                 drone_level = drone_level + 1
  223.                 map_columns()
  224.             end
  225.         end
  226.     end
  227.     while true do
  228.         check_fuel()
  229.         if not turtle.down() then
  230.             break
  231.         end
  232.     end
  233.     while true do
  234.         check_fuel()
  235.         if not turtle.back() then
  236.             break
  237.         end
  238.     end
  239. end
  240.  
  241. local function navigate_to_location(location)
  242.     enter_storage()
  243.  
  244.     while drone_level < location["level"] do
  245.         check_fuel()
  246.         turtle.up()
  247.         if detect_forward(RED_WOOL) then
  248.             drone_level = drone_level + 1
  249.         end
  250.     end
  251.     turtle.turnRight()
  252.  
  253.     while drone_column < location["column"] do
  254.         check_fuel()
  255.         turtle.forward()
  256.         if detect_below(YELLOW_WOOL) then
  257.             drone_column = drone_column + 1
  258.         end
  259.     end
  260.     turtle.turnLeft()
  261.  
  262.     local dist = 1
  263.     while drone_row < location["row"] do
  264.         check_fuel()
  265.         turtle.forward()
  266.         dist = dist + 1
  267.         if dist % 2 == 0 then
  268.             drone_row = drone_row + 1
  269.         end
  270.     end
  271.  
  272.     if location["chest"] == 1 then
  273.         turtle.turnLeft()
  274.     else
  275.         turtle.turnRight()
  276.     end
  277. end
  278.  
  279. local function navigate_within_storage(from_location, to_new_location)
  280.     if from_location["chest"] == 1 then
  281.         turtle.turnRight()
  282.     else
  283.         turtle.turnLeft()
  284.     end
  285.  
  286.     local dist = from_location["row"] * 2
  287.     while dist > 1 do
  288.         check_fuel()
  289.         turtle.back()
  290.         dist = dist - 1
  291.     end
  292.     drone_row = 0
  293.  
  294.     if not (drone_level == to_new_location["level"]) then
  295.         turtle.turnLeft()
  296.         repeat
  297.             check_fuel()
  298.         until not turtle.forward()
  299.         drone_column = 0
  300.         turtle.turnRight()
  301.         while not (drone_level == to_new_location["level"]) do
  302.             local less_than = drone_level < to_new_location["level"]
  303.             check_fuel()
  304.             if less_than then
  305.                 turtle.up()
  306.             else
  307.                 turtle.down()
  308.             end
  309.             if detect_forward(RED_WOOL) then
  310.                 if less_than then
  311.                     drone_level = drone_level + 1
  312.                 else
  313.                     drone_level = drone_level - 1
  314.                 end
  315.             end
  316.         end
  317.     end
  318.     turtle.turnRight()
  319.  
  320.     while drone_column < to_new_location["column"] do
  321.         check_fuel()
  322.         turtle.forward()
  323.         if detect_below(YELLOW_WOOL) then
  324.             drone_column = drone_column + 1
  325.         end
  326.     end
  327.     while drone_column > to_new_location["column"] do
  328.         check_fuel()
  329.         turtle.back()
  330.         if detect_below(YELLOW_WOOL) then
  331.             drone_column = drone_column - 1
  332.         end
  333.     end
  334.     turtle.turnLeft()
  335.  
  336.     dist = 1
  337.     while drone_row < to_new_location["row"] do
  338.         check_fuel()
  339.         turtle.forward()
  340.         dist = dist + 1
  341.         if dist % 2 == 0 then
  342.             drone_row = drone_row + 1
  343.         end
  344.     end
  345.  
  346.     if to_new_location["chest"] == 1 then
  347.         turtle.turnLeft()
  348.     else
  349.         turtle.turnRight()
  350.     end
  351. end
  352.  
  353. local function navigate_to_start(from_location)
  354.     if from_location["chest"] == 1 then
  355.         turtle.turnRight()
  356.     else
  357.         turtle.turnLeft()
  358.     end
  359.  
  360.     local dist = from_location["row"] * 2
  361.     while dist > 1 do
  362.         check_fuel()
  363.         turtle.back()
  364.         dist = dist - 1
  365.     end
  366.     turtle.turnLeft()
  367.  
  368.     while true do
  369.         check_fuel()
  370.         if not turtle.forward() then
  371.             break
  372.         end
  373.     end
  374.     turtle.turnRight()
  375.  
  376.     while true do
  377.         check_fuel()
  378.         if not turtle.down() then
  379.             break
  380.         end
  381.     end
  382.  
  383.     while true do
  384.         check_fuel()
  385.         if not turtle.back() then
  386.             break
  387.         end
  388.     end
  389. end
  390.  
  391. local function store_next_item()
  392.     drone_level = 1
  393.     drone_column = 0
  394.     drone_row = 0
  395.     check_fuel()
  396.     turtle.turnLeft()
  397.     turtle.turnLeft()
  398.     turtle.select(2)
  399.     if not turtle.suck() then
  400.         turtle.turnLeft()
  401.         turtle.turnLeft()
  402.         return false
  403.     end
  404.  
  405.     local itemData = turtle.getItemDetail()
  406.     local m_data = check_manifest(itemData.name)
  407.     if not m_data then
  408.         m_data = new_manifest_item(itemData.name)
  409.     end
  410.  
  411.     turtle.turnLeft()
  412.     turtle.turnLeft()
  413.     navigate_to_location(m_data)
  414.     update_storage(m_data, get_storage(m_data)[m_data["chest"]]["count"] + itemData.count)
  415.     turtle.drop()
  416.     navigate_to_start(m_data)
  417.  
  418.     return true
  419. end
  420. local function do_store()
  421.     while true do
  422.         if not store_next_item() then
  423.             break
  424.         end
  425.     end
  426. end
  427.  
  428. local function do_get()
  429.     local get_amount = tonumber(argv[2])
  430.     local items_array = {}
  431.     local manifest_files = fs.list(ITEM_MANIFEST)
  432.     for _, mf in ipairs(manifest_files) do
  433.         items_array[#items_array+1] = mf
  434.     end
  435.     local o = 1
  436.     while true do
  437.         term.clear()
  438.         term.setCursorPos(1, 1)
  439.         for i=1, #items_array do
  440.             if i == o then
  441.                 print("> " .. items_array[i])
  442.             else
  443.                 print(items_array[i])
  444.             end
  445.         end
  446.         local _, key = os.pullEvent("key")
  447.         if key == keys.up and o > 1 then
  448.             o = o - 1
  449.         elseif key == keys.down and o < #items_array then
  450.             o = o + 1
  451.         elseif key == keys.enter then
  452.             break
  453.         end
  454.     end
  455.     term.clear()
  456.  
  457.     local retrieved_items = 0
  458.     local item_location = check_manifest(ITEM_MANIFEST .. "/" .. items_array[o], true)
  459.  
  460.     while true do
  461.         drone_level = 1
  462.         drone_column = 0
  463.         drone_row = 0
  464.         enter_storage()
  465.         navigate_to_location(item_location)
  466.         turtle.select(2)
  467.         if turtle.suck() then
  468.             local sucked_items = turtle.getItemCount()
  469.             local desired_sucked_items = get_amount - retrieved_items
  470.             retrieved_items = retrieved_items + sucked_items
  471.             if retrieved_items > get_amount then
  472.                 turtle.drop(retrieved_items - get_amount)
  473.                 sucked_items = desired_sucked_items
  474.             end
  475.             update_storage(item_location, get_storage(item_location)[item_location["chest"]]["count"] - sucked_items)
  476.             navigate_to_start(item_location)
  477.             turtle.turnLeft()
  478.             turtle.turnLeft()
  479.             turtle.select(2)
  480.             turtle.drop()
  481.             turtle.turnRight()
  482.             turtle.turnRight()
  483.         else
  484.             navigate_to_start(item_location)
  485.             break
  486.         end
  487.         if retrieved_items >= get_amount then
  488.             break
  489.         end
  490.     end
  491. end
  492.  
  493. local function template_creator()
  494.     local template_name = argv[2]
  495.     local items_array = {"none"}
  496.     local manifest_files = fs.list(ITEM_MANIFEST)
  497.     for _, mf in ipairs(manifest_files) do
  498.         items_array[#items_array+1] = mf
  499.     end
  500.     local template_raw = ""
  501.     local o = 1
  502.     local curr_space = 1
  503.     while curr_space <= 9 do
  504.         term.clear()
  505.         term.setCursorPos(1, 1)
  506.         for i=1, #items_array do
  507.             if i == o then
  508.                 print("> " .. items_array[i])
  509.             elseif math.abs(i - o) < 3 then
  510.                 print(items_array[i])
  511.             elseif math.abs(i - o) == 3 then
  512.                 print("...")
  513.             end
  514.         end
  515.         print("")
  516.         for g=0, 2 do
  517.             local grid_line = ""
  518.             for gs=1, 3 do
  519.                 local actual_space = (g * 3) + gs
  520.                 if actual_space == curr_space then
  521.                     grid_line = grid_line .. "X"
  522.                 elseif actual_space < curr_space then
  523.                     grid_line = grid_line .. "0"
  524.                 else
  525.                     grid_line = grid_line .. "O"
  526.                 end
  527.             end
  528.             print(grid_line)
  529.         end
  530.         local _, key = os.pullEvent("key")
  531.         if key == keys.up and o > 1 then
  532.             o = o - 1
  533.         elseif key == keys.down and o < #items_array then
  534.             o = o + 1
  535.         elseif key == keys.enter then
  536.             template_raw = template_raw .. items_array[o] .. "\n"
  537.             curr_space = curr_space + 1
  538.         end
  539.     end
  540.     term.clear()
  541.     local th = fs.open(TEMPLATES_DATA .. "/" .. template_name, "w")
  542.     th.write(template_raw)
  543.     th.close()
  544.     print("Crafting Template " .. template_name .. " successfully created!")
  545. end
  546.  
  547. local function select_craft_slot(craft_slot)
  548.     if craft_slot <= 3 then
  549.         turtle.select(craft_slot + 5)
  550.     elseif craft_slot <= 6 then
  551.         turtle.select(craft_slot + 6)
  552.     elseif craft_slot <= 9 then
  553.         turtle.select(craft_slot + 7)
  554.     end
  555. end
  556. local function do_craft()
  557.     local craft_amount = tonumber(argv[2])
  558.     local templates_array = {}
  559.     local template_files = fs.list(TEMPLATES_DATA)
  560.     for _, tf in ipairs(template_files) do
  561.         templates_array[#templates_array+1] = tf
  562.     end
  563.     local o = 1
  564.     while true do
  565.         term.clear()
  566.         term.setCursorPos(1, 1)
  567.         for i=1, #templates_array do
  568.             if i == o then
  569.                 print("> " .. templates_array[i])
  570.             else
  571.                 print(templates_array[i])
  572.             end
  573.         end
  574.         local _, key = os.pullEvent("key")
  575.         if key == keys.up and o > 1 then
  576.             o = o - 1
  577.         elseif key == keys.down and o < #templates_array then
  578.             o = o + 1
  579.         elseif key == keys.enter then
  580.             break
  581.         end
  582.     end
  583.     term.clear()
  584.  
  585.     local template_items = {}
  586.     local individual_items = {}
  587.     local individual_items_map = {}
  588.     local template_h = fs.open(TEMPLATES_DATA .. "/" .. template_files[o], "r")
  589.     for s=1, 9 do
  590.         local item_file = template_h.readLine()
  591.         template_items[s] = item_file
  592.         if not individual_items_map[item_file] then
  593.             individual_items[#individual_items+1] = item_file
  594.             individual_items_map[item_file] = true
  595.         end
  596.     end
  597.     template_h.close()
  598.  
  599.     local last_item_location = nil
  600.  
  601.     local current_item = 1
  602.     while current_item <= #individual_items do
  603.         if not (individual_items[current_item] == "none") then
  604.             local item_location = check_manifest(ITEM_MANIFEST .. "/" .. individual_items[current_item], true)
  605.  
  606.             if not last_item_location then
  607.                 drone_level = 1
  608.                 drone_column = 0
  609.                 drone_row = 0
  610.  
  611.                 enter_storage()
  612.                 navigate_to_location(item_location)
  613.             else
  614.                 navigate_within_storage(last_item_location, item_location)
  615.             end
  616.             for s=1, 9 do
  617.                 if template_items[s] == individual_items[current_item] then
  618.                     select_craft_slot(s)
  619.                     turtle.suck(craft_amount)
  620.                     update_storage(item_location, get_storage(item_location)[item_location["chest"]]["count"] - turtle.getItemCount())
  621.                 end
  622.             end
  623.             if current_item == #individual_items then
  624.                 navigate_to_start(item_location)
  625.             end
  626.             last_item_location = item_location
  627.         end
  628.  
  629.         current_item = current_item + 1
  630.     end
  631.  
  632.     turtle.turnLeft()
  633.     turtle.turnLeft()
  634.     turtle.select(1)
  635.     turtle.dropUp()
  636.     local current_crafted_items = 0
  637.     while current_crafted_items < craft_amount do
  638.         turtle.craft()
  639.         current_crafted_items = current_crafted_items + turtle.getItemCount()
  640.         turtle.drop()
  641.     end
  642.     turtle.suckUp()
  643.     turtle.turnRight()
  644.     turtle.turnRight()
  645. end
  646.  
  647. if mode_arg == "map" then
  648.     do_map()
  649. elseif mode_arg == "store" then
  650.     do_store()
  651. elseif mode_arg == "get" then
  652.     do_get()
  653. elseif mode_arg == "template" then
  654.     template_creator()
  655. elseif mode_arg == "craft" then
  656.     do_craft()
  657. end
  658.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement