sc3-rom-dump/rom/programs/print3d.lua

231 lines
5.7 KiB
Lua

local startColor = term.getTextColor()
local function printUsage()
local programName = arg[0] or fs.getName(shell.getRunningProgram())
print("Usage: ")
print(programName .. " <file.3dj or url> [count]")
print(programName .. " stop")
end
local function warn3dm()
printError("This does not look like a 3dj file. If this is an OpenComputers 3dm file, please convert it to 3dj.\n")
term.setTextColor(colors.white)
term.write("Online converter: ")
term.setTextColor(colors.blue)
term.write("https://3dj.lem.sh")
term.setTextColor(startColor)
end
-- Find a 3d printer
local printer = peripheral.find("3d_printer")
if not printer then
error("No 3D printer found", 0)
end
-- Validate arguments
local args = { ... }
if #args < 1 or #args > 2 then
printUsage()
return
end
-- Stop the 3d printer by running `print3d stop`
if args[1] == "stop" then
print("Stopping 3d printer...")
printer.stop()
return
end
local count = 1
if #args == 2 then
count = tonumber(args[2])
if not count or math.floor(count) < 1 then
printUsage()
return
end
count = math.floor(count)
end
-- Load the 3dj file
local filename = args[1]
if filename:match(".3dm$") then
warn3dm()
return
end
local function load3djFile(name)
local f
if http and name:match("^https?://") then
print("Downloading...")
f = http.get{ url = name, binary = true }
else
name = shell.resolve(name)
if not fs.exists(name) then
-- Try to find a .3dj file if the user didn't specify the extension
if not filename:match(".3dj$") then
local newName = name .. ".3dj"
if fs.exists(newName) then
return load3djFile(newName)
end
end
error("File not found: " .. name, 0)
end
f = fs.open(name, "r")
end
if not f then
error("Could not open " .. name, 0)
end
local data = f.readAll()
f.close()
local data, err = textutils.unserialiseJSON(data)
if data == nil then
warn3dm()
error("\n\nCould not parse " .. name .. ": " .. err, 0)
end
return data
end
local printData = load3djFile(filename)
if not printData.shapesOff or not printData.shapesOn then
error("Invalid print data - missing shapesOff and shapesOn")
end
-- Output some basic print metadata (models often have credit in tooltips)
term.write("Printing: ")
term.setTextColor(colors.lightGray)
print(printData.label or filename)
if printData.tooltip then
term.write(printData.tooltip)
end
print("")
local function parseTint(tint)
if type(tint) == "string" then
return tonumber(tint, 16)
elseif type(tint) == "number" then
return tint
else
return 0xFFFFFF
end
end
local function addShape(shapes, shape, state)
table.insert(shapes, {
shape.bounds[1], shape.bounds[2], shape.bounds[3],
shape.bounds[4], shape.bounds[5], shape.bounds[6],
state = state,
texture = shape.texture,
tint = parseTint(shape.tint)
})
end
local function commitPrint(data)
printer.reset()
if data.label then printer.setLabel(data.label) end
if data.tooltip then printer.setTooltip(data.tooltip) end
printer.setButtonMode(data.isButton or false)
printer.setCollidable(data.collideWhenOff ~= false, data.collideWhenOn ~= false)
printer.setRedstoneLevel(data.redstoneLevel or 0)
printer.setLightLevel(data.lightLevel or 0)
local shapes = {}
for _, shape in ipairs(data.shapesOff) do
addShape(shapes, shape, false)
end
for _, shape in ipairs(data.shapesOn) do
addShape(shapes, shape, true)
end
printer.addShapes(shapes)
printer.commit(count)
end
local function percent(n, m)
return math.ceil(n / m * 100)
end
local function writePercent(label, n, m)
local level = percent(n, m)
term.setTextColor(colors.yellow)
term.write(label)
term.setTextColor(level >= 10 and colors.white or colors.red)
term.write(level .. "% ")
end
local remaining = count
local function showPrintStatus()
local _, y = term.getCursorPos()
local chamelium, maxChamelium = printer.getChameliumLevel()
local ink, maxInk = printer.getInkLevel()
term.setCursorPos(1, y - 1)
term.clearLine()
writePercent("Chamelium: ", chamelium, maxChamelium)
writePercent("Ink: ", ink, maxInk)
term.setCursorPos(1, y)
term.clearLine()
term.setTextColor(colors.yellow)
term.write("Printing... ")
term.setTextColor(colors.white)
term.write(math.min((count - remaining) + 1, count) .. " / " .. count)
term.setCursorPos(1, y)
end
-- Begin printing
local status = printer.status()
if status == "busy" then
error("Printer is busy", 0)
end
commitPrint(printData)
term.setTextColor(colors.yellow)
print("\nHold Ctrl+T to stop\n")
showPrintStatus()
while true do
local e, p1 = os.pullEventRaw()
local n = math.min(math.max((count - remaining) + 1, 1), count)
if e == "3d_printer_complete" or e == "3d_printer_state" then
remaining = p1
showPrintStatus()
if remaining <= 0 then
-- Printing complete, print the count we managed to print
local _, y = term.getCursorPos()
term.setCursorPos(1, y)
term.clearLine()
term.setTextColor(colors.green)
print("Printed " .. n .. " item" .. (n ~= 1 and "s" or ""))
break
end
elseif e == "terminate" then
-- Halt printing and print the count we managed to print
printer.stop()
local _, y = term.getCursorPos()
term.setCursorPos(1, y)
term.clearLine()
term.setTextColor(colors.red)
print("Printing terminated. Printed " .. n .. " item" ..
(n ~= 1 and "s" or "") .. " out of " .. count)
break
end
end
term.setTextColor(startColor)