create-schematic-gen-site/schematic-exporter2.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