367 lines
13 KiB
Lua
367 lines
13 KiB
Lua
local g = require("simple-graphics")
|
|
local mon = peripheral.wrap("monitor_24")
|
|
local W, H = mon.getSize()
|
|
local RUNNING = true -- Flag to indicate global program state.
|
|
|
|
-- Export flags
|
|
local EXPORTING = false -- Flag to indicate if we're exporting.
|
|
local EXPORT_SKIP = false -- Flag to indicate we should skip the current item.
|
|
local EXPORT_REPORT = false -- Flag to indicate we should report the current item as invalid.
|
|
|
|
local function startsWith(str, start)
|
|
return str:sub(1, #start) == start
|
|
end
|
|
|
|
local function getTotalItemCount(itemList)
|
|
local total = 0
|
|
for name, value in pairs(itemList) do
|
|
if not startsWith(name, "__") then
|
|
total = total + value
|
|
end
|
|
end
|
|
local count = 1
|
|
if itemList.__COUNT__ then count = itemList.__COUNT__ end
|
|
return count * total
|
|
end
|
|
|
|
local function findItem(items, name)
|
|
for _, item in pairs(items) do
|
|
if item.name == name then return item end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local function attemptItemExport(name, count)
|
|
local P_NAME = "meBridge_4"
|
|
local p = peripheral.wrap(P_NAME)
|
|
if p == nil then
|
|
return nil, "Missing peripheral "..P_NAME
|
|
end
|
|
local func = function()
|
|
return p.exportItem({name=name, count=count}, "south")
|
|
end
|
|
local success, result = pcall(func)
|
|
if success then
|
|
return result
|
|
else
|
|
return nil, result
|
|
end
|
|
end
|
|
|
|
local function playNotes(instrument, pitches, delay)
|
|
local speaker = peripheral.find("speaker")
|
|
if speaker == nil then return end
|
|
delay = delay or 0.25
|
|
for i, pitch in pairs(pitches) do
|
|
speaker.playNote(instrument, 3, pitch)
|
|
if i < #pitches then
|
|
os.sleep(delay)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function drawProgress(p)
|
|
local discreteWidth = W - 2
|
|
local filled = p * discreteWidth
|
|
g.drawXLine(mon, 2, W-1, 5, colors.lightGray)
|
|
g.drawXLine(mon, 2, 2+filled-1, 5, colors.green)
|
|
local s = string.format("%.0f%%", p*100)
|
|
for i = 1, #s do
|
|
local x = 2+i
|
|
local c = s:sub(i,i)
|
|
local bg = colors.lightGray
|
|
if x < filled then bg = colors.green end
|
|
g.drawText(mon, x, 5, c, colors.white, bg)
|
|
end
|
|
end
|
|
|
|
local function setProgressText(text)
|
|
g.drawXLine(mon, 2, W-1, 6, colors.gray)
|
|
if text ~= nil and #text > 0 then
|
|
g.drawText(mon, 2, 6, text, colors.white, colors.gray)
|
|
end
|
|
end
|
|
|
|
local function clearMainPanel()
|
|
g.fillRect(mon, 1, 7, W, H-6, colors.black)
|
|
end
|
|
|
|
local function clearExportPanel()
|
|
g.fillRect(mon, 1, 7, W, H-9, colors.black)
|
|
end
|
|
|
|
local function promptForUrlInput()
|
|
clearMainPanel()
|
|
drawProgress(0)
|
|
setProgressText(nil)
|
|
g.drawText(mon, 1, 8, "Please enter a schematic URL that", colors.white, colors.black)
|
|
g.drawText(mon, 1, 9, "you've obtained from", colors.white, colors.black)
|
|
g.drawText(mon, 1, 10, "schematics.andrewlalis.com in the", colors.white, colors.black)
|
|
g.drawText(mon, 1, 11, "computer to your right to continue.", colors.white, colors.black)
|
|
|
|
g.clear(term, colors.black)
|
|
g.drawText(term, 1, 1, "Paste your schematic URL here (CTRL+V): ", colors.white)
|
|
g.drawText(term, 2, 2, "*Press enter without pasting to quit*", colors.gray)
|
|
term.setCursorPos(1, 3)
|
|
term.setTextColor(colors.lightGray)
|
|
local link = io.read()
|
|
if link == nil or #link == 0 then
|
|
g.drawText(term, 1, 8, "No URL entered. Quitting.", colors.white)
|
|
return nil
|
|
else
|
|
g.drawText(term, 1, 8, "URL was pasted. Please continue on the monitor.", colors.white)
|
|
return link
|
|
end
|
|
end
|
|
|
|
local function fetchItemLists(url)
|
|
local response = http.get(url)
|
|
if response == nil then
|
|
return nil, "HTTP request failed."
|
|
end
|
|
if response.getResponseCode() ~= 200 then
|
|
return nil, "HTTP code " .. response.getResponseCode()
|
|
end
|
|
local rawText = response.readAll()
|
|
response.close()
|
|
local itemLists, jsonErr = textutils.unserializeJSON(rawText)
|
|
if not itemLists then
|
|
return nil, "Failed to parse JSON: "..jsonErr
|
|
end
|
|
return itemLists
|
|
end
|
|
|
|
local function exportItem(name, count)
|
|
clearExportPanel()
|
|
g.drawText(mon, 1, 7, "Exporting "..count.." of", colors.white, colors.black)
|
|
g.drawText(mon, 1, 8, name, colors.lime, colors.black)
|
|
-- Check for flags and do different stuff if so.
|
|
if EXPORT_REPORT then
|
|
-- Report the item issue to the schematic site.
|
|
g.drawText(mon, 1, 10, "Reporting item. Skipping to next one.", colors.yellow, colors.black)
|
|
http.post("https://schematics.andrewlalis.com/item-reports", name)
|
|
g.drawText(mon, 1, 11, "Contact an admin if urgent.", colors.yellow, colors.black)
|
|
os.sleep(3)
|
|
return count
|
|
elseif EXPORT_SKIP then
|
|
-- Skip this item.
|
|
g.drawText(mon, 1, 10, "Skipping this item.", colors.yellow, colors.black)
|
|
os.sleep(2)
|
|
return count
|
|
end
|
|
|
|
local me = peripheral.find("meBridge")
|
|
if me == nil then
|
|
g.drawText(mon, 1, 10, "Error: No \"meBridge\" peripheral.", colors.red, colors.black)
|
|
g.drawText(mon, 1, 11, "Attach one please.", colors.red, colors.black)
|
|
os.sleep(0.5)
|
|
return 0
|
|
end
|
|
|
|
local allItems, err = me.listItems()
|
|
if allItems == nil or #allItems < 5 then
|
|
g.drawText(mon, 1, 10, "Error: Couldn't list AE items.", colors.red, colors.black)
|
|
g.drawText(mon, 1, 11, "Msg: " .. err, colors.red, colors.black)
|
|
os.sleep(0.5)
|
|
return 0
|
|
end
|
|
|
|
local item = findItem(allItems, name)
|
|
if item ~= nil and item.amount > 0 then
|
|
local exported, err = attemptItemExport(name, count)
|
|
if exported ~= nil then
|
|
if exported == 0 then
|
|
g.drawText(mon, 1, 10, "Exported 0 items. Make sure there is", colors.yellow, colors.black)
|
|
g.drawText(mon, 1, 11, "space in the output container.", colors.yellow, colors.black)
|
|
else
|
|
g.drawText(mon, 1, 10, "Exported " .. exported .. " items.", colors.white, colors.black)
|
|
end
|
|
os.sleep(0.5)
|
|
return exported
|
|
end
|
|
g.drawText(mon, 1, 10, "Transfer failed: " .. err, colors.red, colors.black)
|
|
os.sleep(0.5)
|
|
return 0
|
|
else
|
|
g.drawText(mon, 1, 10, "Item isn't present in the AE system.", colors.yellow, colors.black)
|
|
g.drawText(mon, 1, 11, "Please add some, craft, or skip.", colors.yellow, colors.black)
|
|
os.sleep(0.5)
|
|
return 0
|
|
end
|
|
end
|
|
|
|
local function exportSchematics(itemLists)
|
|
-- First build a list of instances of schematics, each with a task list.
|
|
local totalItemCount = 0
|
|
local listInstances = {}
|
|
for _, list in pairs(itemLists) do
|
|
totalItemCount = totalItemCount + getTotalItemCount(list)
|
|
for i = 1, list.__COUNT__ do
|
|
local instance = {
|
|
name = list.__NAME__,
|
|
instanceNumber = i,
|
|
countOfThisType = list.__COUNT__,
|
|
tasks = {}
|
|
}
|
|
for name, amount in pairs(list) do
|
|
if not startsWith(name, "__") then
|
|
table.insert(instance.tasks, {name=name, amount=amount})
|
|
end
|
|
end
|
|
table.insert(listInstances, instance)
|
|
end
|
|
end
|
|
-- Now execute on that task list, quitting if the EXPORTING flag goes false.
|
|
local totalItemsExported = 0
|
|
local instanceIndex = 1
|
|
while instanceIndex <= #listInstances and EXPORTING do
|
|
local listInstance = listInstances[instanceIndex]
|
|
setProgressText(listInstance.instanceNumber.."/"..listInstance.countOfThisType.." "..listInstance.name)
|
|
local taskIndex = 1
|
|
while taskIndex <= #listInstance.tasks and EXPORTING do
|
|
local task = listInstance.tasks[taskIndex]
|
|
local itemsExported = 0
|
|
-- Reset item-specific control flags.
|
|
EXPORT_REPORT = false
|
|
EXPORT_SKIP = false
|
|
while itemsExported < task.amount and EXPORTING do
|
|
local exportedCount = exportItem(task.name, task.amount - itemsExported)
|
|
itemsExported = itemsExported + exportedCount
|
|
totalItemsExported = totalItemsExported + exportedCount
|
|
drawProgress(totalItemsExported / totalItemCount)
|
|
end
|
|
taskIndex = taskIndex + 1
|
|
end
|
|
instanceIndex = instanceIndex + 1
|
|
end
|
|
-- Done! Show a small message, then set the EXPORTING flag to false.
|
|
EXPORTING = false
|
|
RUNNING = false -- Exit back to the desktop.
|
|
for i = 1, 3 do -- Queue up some no-op touch events make sure the event handler quits.
|
|
os.queueEvent("monitor_touch", "monitor_24", 1, 1)
|
|
end
|
|
clearMainPanel()
|
|
g.drawText(mon, 1, 8, "Export complete!", colors.lime, colors.black)
|
|
g.drawText(mon, 1, 10, totalItemsExported .. " items exported.", colors.white, colors.black)
|
|
playNotes("bell", {8, 12, 16, 20}, 0.5)
|
|
os.sleep(3)
|
|
end
|
|
|
|
local function handleExportEvents()
|
|
while EXPORTING do
|
|
local event, monName, x, y = os.pullEvent("monitor_touch")
|
|
if monName == "monitor_24" and y >= H-2 then
|
|
if x >= 27 then
|
|
EXPORTING = false
|
|
playNotes("harp", {12, 8})
|
|
elseif x >= 14 then
|
|
EXPORT_REPORT = true
|
|
playNotes("hat", {14, 10})
|
|
else
|
|
EXPORT_SKIP = true
|
|
playNotes("snare", {12})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function handleSchematicUrl(url)
|
|
clearMainPanel()
|
|
if url == nil then
|
|
g.drawText(mon, 1, 8, "No URL was entered. Quitting.", colors.white, colors.black)
|
|
RUNNING = false
|
|
os.sleep(2)
|
|
return
|
|
end
|
|
g.drawText(mon, 1, 7, "Fetching item lists from URL...", colors.lightGray, colors.black)
|
|
local itemLists, err = fetchItemLists(url)
|
|
if not itemLists then
|
|
g.drawText(mon, 1, 8, "Failed to fetch item lists.", colors.red, colors.black)
|
|
g.drawText(mon, 1, 9, err, colors.red, colors.black)
|
|
os.sleep(3)
|
|
return
|
|
end
|
|
|
|
g.drawText(mon, 1, 8, "Got lists for "..(#itemLists).." schematics:", colors.white, colors.black)
|
|
local y = 9
|
|
for i, itemList in pairs(itemLists) do
|
|
local count = itemList.__COUNT__
|
|
local name = itemList.__NAME__
|
|
g.drawText(mon, 2, y, count.."x "..name, colors.white, colors.black)
|
|
y = y+1
|
|
if y == H-3 and i < #itemLists then
|
|
local numRemaining = #itemLists - i
|
|
g.drawText(mon, 2, y, "... and "..numRemaining.." more.")
|
|
break
|
|
end
|
|
end
|
|
-- Draw continue and cancel buttons and wait for user input.
|
|
g.fillRect(mon, 1, H-2, 18, 3, colors.gray)
|
|
g.drawTextCenter(mon, 9, H-1, "Cancel", colors.white)
|
|
g.fillRect(mon, 19, H-2, 21, 3, colors.green)
|
|
g.drawTextCenter(mon, 29, H-1, "Continue", colors.white)
|
|
local waiting = true
|
|
while waiting do
|
|
local event, monName, x, y = os.pullEvent("monitor_touch")
|
|
if monName == "monitor_24" and y >= H-2 then
|
|
if x <= 18 then
|
|
-- Canceled, so quit the whole application.
|
|
playNotes("harp", {12, 8})
|
|
RUNNING = false
|
|
return
|
|
else
|
|
playNotes("bell", {12, 16})
|
|
waiting = false
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Write instructions
|
|
clearMainPanel()
|
|
g.drawText(mon, 1, 8, "Export beginning shortly. Please read", colors.white, colors.black)
|
|
g.drawText(mon, 1, 9, "these instructions beforehand:", colors.white, colors.black)
|
|
|
|
g.drawText(mon, 1, 10, "Press", colors.white, colors.black)
|
|
g.drawText(mon, 7, 10, "Skip", colors.white, colors.blue)
|
|
g.drawText(mon, 13, 10, "to skip an item.", colors.white, colors.black)
|
|
|
|
g.drawText(mon, 1, 11, "Press", colors.white, colors.black)
|
|
g.drawText(mon, 7, 11, "Report", colors.white, colors.orange)
|
|
g.drawText(mon, 14, 11, "to report an invalid item.", colors.white, colors.black)
|
|
|
|
g.drawText(mon, 1, 12, "Press", colors.white, colors.black)
|
|
g.drawText(mon, 7, 12, "Quit", colors.white, colors.red)
|
|
g.drawText(mon, 12, 12, "to stop the export.", colors.white, colors.black)
|
|
-- Draw control buttons.
|
|
g.fillRect(mon, 1, H-2, 13, 3, colors.blue)
|
|
g.drawText(mon, 5, H-1, "Skip", colors.white)
|
|
g.fillRect(mon, 14, H-2, 13, 3, colors.orange)
|
|
g.drawText(mon, 17, H-1, "Report", colors.white)
|
|
g.fillRect(mon, 27, H-2, 13, 3, colors.red)
|
|
g.drawText(mon, 31, H-1, "Quit", colors.white)
|
|
|
|
for i = 1, 5 do
|
|
g.drawText(mon, 1, H-4, "Starting in "..(5-i+1), colors.white, colors.black)
|
|
os.sleep(1)
|
|
end
|
|
|
|
EXPORTING = true
|
|
local fExport = function() exportSchematics(itemLists) end
|
|
local fHandleEvents = function() handleExportEvents() end
|
|
parallel.waitForAll(fExport, fHandleEvents)
|
|
end
|
|
|
|
-- MAIN SCRIPT
|
|
|
|
g.clear(mon, colors.black)
|
|
g.fillRect(mon, 1, 1, W, 3, colors.yellow)
|
|
g.drawTextCenter(mon, W/2, 2, "Schematic Exporter", colors.black)
|
|
|
|
g.fillRect(mon, 1, 4, W, 3, colors.gray)
|
|
g.drawText(mon, 2, 4, "Progress", colors.white)
|
|
g.drawXLine(mon, 2, W-1, 5, colors.lightGray)
|
|
|
|
while RUNNING do
|
|
local url = promptForUrlInput()
|
|
handleSchematicUrl(url)
|
|
end |