Advertisement
HandieAndy

schematic-exporter2.lua

Jul 23rd, 2023 (edited)
973
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 13.38 KB | Gaming | 0 0
  1. local g = require("simple-graphics")
  2. local mon = peripheral.wrap("monitor_24")
  3. local W, H = mon.getSize()
  4. local RUNNING = true -- Flag to indicate global program state.
  5.  
  6. -- Export flags
  7. local EXPORTING = false -- Flag to indicate if we're exporting.
  8. local EXPORT_SKIP = false -- Flag to indicate we should skip the current item.
  9. local EXPORT_REPORT = false -- Flag to indicate we should report the current item as invalid.
  10.  
  11. local function startsWith(str, start)
  12.     return str:sub(1, #start) == start
  13. end
  14.  
  15. local function getTotalItemCount(itemList)
  16.     local total = 0
  17.     for name, value in pairs(itemList) do
  18.         if not startsWith(name, "__") then
  19.             total = total + value
  20.         end
  21.     end
  22.     local count = 1
  23.     if itemList.__COUNT__ then count = itemList.__COUNT__ end
  24.     return count * total
  25. end
  26.  
  27. local function findItem(items, name)
  28.     for _, item in pairs(items) do
  29.         if item.name == name then return item end
  30.     end
  31.     return nil
  32. end
  33.  
  34. local function attemptItemExport(name, count)
  35.     local P_NAME = "meBridge_4"
  36.     local p = peripheral.wrap(P_NAME)
  37.     if p == nil then
  38.         return nil, "Missing peripheral "..P_NAME
  39.     end
  40.     local func = function()
  41.         return p.exportItem({name=name, count=count}, "south")
  42.     end
  43.     local success, result = pcall(func)
  44.     if success then
  45.         return result
  46.     else
  47.         return nil, result
  48.     end
  49. end
  50.  
  51. local function playNotes(instrument, pitches, delay)
  52.     local speaker = peripheral.find("speaker")
  53.     if speaker == nil then return end
  54.     delay = delay or 0.25
  55.     for i, pitch in pairs(pitches) do
  56.         speaker.playNote(instrument, 3, pitch)
  57.         if i < #pitches then
  58.             os.sleep(delay)
  59.         end
  60.     end
  61. end
  62.  
  63. local function drawProgress(p)
  64.     local discreteWidth = W - 2
  65.     local filled = p * discreteWidth
  66.     g.drawXLine(mon, 2, W-1, 5, colors.lightGray)
  67.     g.drawXLine(mon, 2, 2+filled-1, 5, colors.green)
  68.     local s = string.format("%.0f%%", p*100)
  69.     for i = 1, #s do
  70.         local x = 2+i
  71.         local c = s:sub(i,i)
  72.         local bg = colors.lightGray
  73.         if x < filled then bg = colors.green end
  74.         g.drawText(mon, x, 5, c, colors.white, bg)
  75.     end
  76. end
  77.  
  78. local function setProgressText(text)
  79.     g.drawXLine(mon, 2, W-1, 6, colors.gray)
  80.     if text ~= nil and #text > 0 then
  81.         g.drawText(mon, 2, 6, text, colors.white, colors.gray)
  82.     end
  83. end
  84.  
  85. local function clearMainPanel()
  86.     g.fillRect(mon, 1, 7, W, H-6, colors.black)
  87. end
  88.  
  89. local function clearExportPanel()
  90.     g.fillRect(mon, 1, 7, W, H-9, colors.black)
  91. end
  92.  
  93. local function promptForUrlInput()
  94.     clearMainPanel()
  95.     drawProgress(0)
  96.     setProgressText(nil)
  97.     g.drawText(mon, 1, 8, "Please enter a schematic URL that", colors.white, colors.black)
  98.     g.drawText(mon, 1, 9, "you've obtained from", colors.white, colors.black)
  99.     g.drawText(mon, 1, 10, "schematics.andrewlalis.com in the", colors.white, colors.black)
  100.     g.drawText(mon, 1, 11, "computer to your right to continue.", colors.white, colors.black)
  101.  
  102.     g.clear(term, colors.black)
  103.     g.drawText(term, 1, 1, "Paste your schematic URL here (CTRL+V): ", colors.white)
  104.     g.drawText(term, 2, 2, "*Press enter without pasting to quit*", colors.gray)
  105.     term.setCursorPos(1, 3)
  106.     term.setTextColor(colors.lightGray)
  107.     local link = io.read()
  108.     if link == nil or #link == 0 then
  109.         g.drawText(term, 1, 8, "No URL entered. Quitting.", colors.white)
  110.         return nil
  111.     else
  112.         g.drawText(term, 1, 8, "URL was pasted. Please continue on the monitor.", colors.white)
  113.         return link
  114.     end
  115. end
  116.  
  117. local function fetchItemLists(url)
  118.     local response = http.get(url)
  119.     if response == nil then
  120.         return nil, "HTTP request failed."
  121.     end
  122.     if response.getResponseCode() ~= 200 then
  123.         return nil, "HTTP code " .. response.getResponseCode()
  124.     end
  125.     local rawText = response.readAll()
  126.     response.close()
  127.     local itemLists, jsonErr = textutils.unserializeJSON(rawText)
  128.     if not itemLists then
  129.         return nil, "Failed to parse JSON: "..jsonErr
  130.     end
  131.     return itemLists
  132. end
  133.  
  134. local function exportItem(name, count)
  135.     clearExportPanel()
  136.     g.drawText(mon, 1, 7, "Exporting "..count.." of", colors.white, colors.black)
  137.     g.drawText(mon, 1, 8, name, colors.lime, colors.black)
  138.     -- Check for flags and do different stuff if so.
  139.     if EXPORT_REPORT then
  140.         -- Report the item issue to the schematic site.
  141.         g.drawText(mon, 1, 10, "Reporting item. Skipping to next one.", colors.yellow, colors.black)
  142.         http.post("https://schematics.andrewlalis.com/item-reports", name)
  143.         g.drawText(mon, 1, 11, "Contact an admin if urgent.", colors.yellow, colors.black)
  144.         os.sleep(3)
  145.         return count
  146.     elseif EXPORT_SKIP then
  147.         -- Skip this item.
  148.         g.drawText(mon, 1, 10, "Skipping this item.", colors.yellow, colors.black)
  149.         os.sleep(2)
  150.         return count
  151.     end
  152.  
  153.     local me = peripheral.find("meBridge")
  154.     if me == nil then
  155.         g.drawText(mon, 1, 10, "Error: No \"meBridge\" peripheral.", colors.red, colors.black)
  156.         g.drawText(mon, 1, 11, "Attach one please.", colors.red, colors.black)
  157.         os.sleep(0.5)
  158.         return 0
  159.     end
  160.  
  161.     local allItems, err = me.listItems()
  162.     if allItems == nil or #allItems < 5 then
  163.         g.drawText(mon, 1, 10, "Error: Couldn't list AE items.", colors.red, colors.black)
  164.         g.drawText(mon, 1, 11, "Msg: " .. err, colors.red, colors.black)
  165.         os.sleep(0.5)
  166.         return 0
  167.     end
  168.  
  169.     local item = findItem(allItems, name)
  170.     if item ~= nil and item.amount > 0 then
  171.         local exported, err = attemptItemExport(name, count)
  172.         if exported ~= nil then
  173.             if exported == 0 then
  174.                 g.drawText(mon, 1, 10, "Exported 0 items. Make sure there is", colors.yellow, colors.black)
  175.                 g.drawText(mon, 1, 11, "space in the output container.", colors.yellow, colors.black)
  176.             else
  177.                 g.drawText(mon, 1, 10, "Exported " .. exported .. " items.", colors.white, colors.black)
  178.             end
  179.             os.sleep(0.5)
  180.             return exported
  181.         end
  182.         g.drawText(mon, 1, 10, "Transfer failed: " .. err, colors.red, colors.black)
  183.         os.sleep(0.5)
  184.         return 0
  185.     else
  186.         g.drawText(mon, 1, 10, "Item isn't present in the AE system.", colors.yellow, colors.black)
  187.         g.drawText(mon, 1, 11, "Please add some, craft, or skip.", colors.yellow, colors.black)
  188.         os.sleep(0.5)
  189.         return 0
  190.     end
  191. end
  192.  
  193. local function exportSchematics(itemLists)
  194.     -- First build a list of instances of schematics, each with a task list.
  195.     local totalItemCount = 0
  196.     local listInstances = {}
  197.     for _, list in pairs(itemLists) do
  198.         totalItemCount = totalItemCount + getTotalItemCount(list)
  199.         for i = 1, list.__COUNT__ do
  200.             local instance = {
  201.                 name = list.__NAME__,
  202.                 instanceNumber = i,
  203.                 countOfThisType = list.__COUNT__,
  204.                 tasks = {}
  205.             }
  206.             for name, amount in pairs(list) do
  207.                 if not startsWith(name, "__") then
  208.                     table.insert(instance.tasks, {name=name, amount=amount})
  209.                 end
  210.             end
  211.             table.insert(listInstances, instance)
  212.         end
  213.     end
  214.     -- Now execute on that task list, quitting if the EXPORTING flag goes false.
  215.     local totalItemsExported = 0
  216.     local instanceIndex = 1
  217.     while instanceIndex <= #listInstances and EXPORTING do
  218.         local listInstance = listInstances[instanceIndex]
  219.         setProgressText(listInstance.instanceNumber.."/"..listInstance.countOfThisType.." "..listInstance.name)
  220.         local taskIndex = 1
  221.         while taskIndex <= #listInstance.tasks and EXPORTING do
  222.             local task = listInstance.tasks[taskIndex]
  223.             local itemsExported = 0
  224.             -- Reset item-specific control flags.
  225.             EXPORT_REPORT = false
  226.             EXPORT_SKIP = false
  227.             while itemsExported < task.amount and EXPORTING do
  228.                 local exportedCount = exportItem(task.name, task.amount - itemsExported)
  229.                 itemsExported = itemsExported + exportedCount
  230.                 totalItemsExported = totalItemsExported + exportedCount
  231.                 drawProgress(totalItemsExported / totalItemCount)
  232.             end
  233.             taskIndex = taskIndex + 1
  234.         end
  235.         instanceIndex = instanceIndex + 1
  236.     end
  237.     -- Done! Show a small message, then set the EXPORTING flag to false.
  238.     EXPORTING = false
  239.     RUNNING = false -- Exit back to the desktop.
  240.     for i = 1, 3 do -- Queue up some no-op touch events make sure the event handler quits.
  241.         os.queueEvent("monitor_touch", "monitor_24", 1, 1)
  242.     end
  243.     clearMainPanel()
  244.     g.drawText(mon, 1, 8, "Export complete!", colors.lime, colors.black)
  245.     g.drawText(mon, 1, 10, totalItemsExported .. " items exported.", colors.white, colors.black)
  246.     playNotes("bell", {8, 12, 16, 20}, 0.5)
  247.     os.sleep(3)
  248. end
  249.  
  250. local function handleExportEvents()
  251.     while EXPORTING do
  252.         local event, monName, x, y = os.pullEvent("monitor_touch")
  253.         if monName == "monitor_24" and y >= H-2 then
  254.             if x >= 27 then
  255.                 EXPORTING = false
  256.                 playNotes("harp", {12, 8})
  257.             elseif x >= 14 then
  258.                 EXPORT_REPORT = true
  259.                 playNotes("hat", {14, 10})
  260.             else
  261.                 EXPORT_SKIP = true
  262.                 playNotes("snare", {12})
  263.             end
  264.         end
  265.     end
  266. end
  267.  
  268. local function handleSchematicUrl(url)
  269.     clearMainPanel()
  270.     if url == nil then
  271.         g.drawText(mon, 1, 8, "No URL was entered. Quitting.", colors.white, colors.black)
  272.         RUNNING = false
  273.         os.sleep(2)
  274.         return
  275.     end
  276.     g.drawText(mon, 1, 7, "Fetching item lists from URL...", colors.lightGray, colors.black)
  277.     local itemLists, err = fetchItemLists(url)
  278.     if not itemLists then
  279.         g.drawText(mon, 1, 8, "Failed to fetch item lists.", colors.red, colors.black)
  280.         g.drawText(mon, 1, 9, err, colors.red, colors.black)
  281.         os.sleep(3)
  282.         return
  283.     end
  284.  
  285.     g.drawText(mon, 1, 8, "Got lists for "..(#itemLists).." schematics:", colors.white, colors.black)
  286.     local y = 9
  287.     for i, itemList in pairs(itemLists) do
  288.         local count = itemList.__COUNT__
  289.         local name = itemList.__NAME__
  290.         g.drawText(mon, 2, y, count.."x "..name, colors.white, colors.black)
  291.         y = y+1
  292.         if y == H-3 and i < #itemLists then
  293.             local numRemaining = #itemLists - i
  294.             g.drawText(mon, 2, y, "... and "..numRemaining.." more.")
  295.             break
  296.         end
  297.     end
  298.     -- Draw continue and cancel buttons and wait for user input.
  299.     g.fillRect(mon, 1, H-2, 18, 3, colors.gray)
  300.     g.drawTextCenter(mon, 9, H-1, "Cancel", colors.white)
  301.     g.fillRect(mon, 19, H-2, 21, 3, colors.green)
  302.     g.drawTextCenter(mon, 29, H-1, "Continue", colors.white)
  303.     local waiting = true
  304.     while waiting do
  305.         local event, monName, x, y = os.pullEvent("monitor_touch")
  306.         if monName == "monitor_24" and y >= H-2 then
  307.             if x <= 18 then
  308.                 -- Canceled, so quit the whole application.
  309.                 playNotes("harp", {12, 8})
  310.                 RUNNING = false
  311.                 return
  312.             else
  313.                 playNotes("bell", {12, 16})
  314.                 waiting = false
  315.             end
  316.         end
  317.     end
  318.  
  319.     -- Write instructions
  320.     clearMainPanel()
  321.     g.drawText(mon, 1, 8, "Export beginning shortly. Please read", colors.white, colors.black)
  322.     g.drawText(mon, 1, 9, "these instructions beforehand:", colors.white, colors.black)
  323.    
  324.     g.drawText(mon, 1, 10, "Press", colors.white, colors.black)
  325.     g.drawText(mon, 7, 10, "Skip", colors.white, colors.blue)
  326.     g.drawText(mon, 13, 10, "to skip an item.", colors.white, colors.black)
  327.    
  328.     g.drawText(mon, 1, 11, "Press", colors.white, colors.black)
  329.     g.drawText(mon, 7, 11, "Report", colors.white, colors.orange)
  330.     g.drawText(mon, 14, 11, "to report an invalid item.", colors.white, colors.black)
  331.  
  332.     g.drawText(mon, 1, 12, "Press", colors.white, colors.black)
  333.     g.drawText(mon, 7, 12, "Quit", colors.white, colors.red)
  334.     g.drawText(mon, 12, 12, "to stop the export.", colors.white, colors.black)
  335.     -- Draw control buttons.
  336.     g.fillRect(mon, 1, H-2, 13, 3, colors.blue)
  337.     g.drawText(mon, 5, H-1, "Skip", colors.white)
  338.     g.fillRect(mon, 14, H-2, 13, 3, colors.orange)
  339.     g.drawText(mon, 17, H-1, "Report", colors.white)
  340.     g.fillRect(mon, 27, H-2, 13, 3, colors.red)
  341.     g.drawText(mon, 31, H-1, "Quit", colors.white)
  342.    
  343.     for i = 1, 5 do
  344.         g.drawText(mon, 1, H-4, "Starting in "..(5-i+1), colors.white, colors.black)
  345.         os.sleep(1)
  346.     end
  347.  
  348.     EXPORTING = true
  349.     local fExport = function() exportSchematics(itemLists) end
  350.     local fHandleEvents = function() handleExportEvents() end
  351.     parallel.waitForAll(fExport, fHandleEvents)
  352. end
  353.  
  354. -- MAIN SCRIPT
  355.  
  356. g.clear(mon, colors.black)
  357. g.fillRect(mon, 1, 1, W, 3, colors.yellow)
  358. g.drawTextCenter(mon, W/2, 2, "Schematic Exporter", colors.black)
  359.  
  360. g.fillRect(mon, 1, 4, W, 3, colors.gray)
  361. g.drawText(mon, 2, 4, "Progress", colors.white)
  362. g.drawXLine(mon, 2, W-1, 5, colors.lightGray)
  363.  
  364. while RUNNING do
  365.     local url = promptForUrlInput()
  366.     handleSchematicUrl(url)
  367. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement