Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- +--------------------------------------------------------+
- -- | |
- -- | WorldPorter |
- -- | (Hologram Alpha) |
- -- +--------------------------------------------------------+
- local version = "Version 0.1.0"
- -- By Jeffrey Alexander, aka Bomb Bloke.
- -- Displays WorldPorter build files as RandomPeripherals holograms.
- -- http://www.computercraft.info/forums2/index.php?/topic/20785-mc-1710cc-174-randomperipherals
- ---------------------------------------------
- ------------Variable Declarations------------
- ---------------------------------------------
- local holo = peripheral.find("hologram_projector")
- local xSize, ySize, myEvent = term.getSize()
- local curMenu, subMenu, startDir, cursor = 1, 1, shell.resolve("."), {{">> "," <<"},{"> > "," < <"},{" >> "," << "},{"> > "," < <"}}
- local labelText, labelBack, inputText, inputBack, buttonText, buttonBack = colours.blue, colours.lightGrey, colours.purple, colours.grey, colours.lightGrey, colours.grey
- -- Doors need special handling:
- local doorBlocks = {
- "minecraft:wooden_door","minecraft:iron_door"
- }
- -- These may need solid blocks horizontally besides them in order to be placed:
- local dependantBlocks = {
- "minecraft:torch","minecraft:stone_button","minecraft:wooden_button","minecraft:trapdoor",
- "minecraft:tripwire_hook","minecraft:redstone_torch","minecraft:lever","minecraft:portal",
- "minecraft:wall_sign","minecraft:end_portal","minecraft:ladder","minecraft:vine","minecraft:bed"
- }
- -- These are either liquids, or need to be placed on liquids:
- local fluidBlocks = {
- "minecraft:water","minecraft:flowing_water","minecraft:lava","minecraft:flowing_lava",
- "minecraft:waterlily"
- }
- -- Translations that must always be performed:
- local forcedTranslation = {
- ["minecraft:portal"] = {{1,0},{2,0}}
- }
- -- Used to rotate the blocks in concern (via metadata):
- local rotationTranslation = {
- -- MineCraft 1.7.10:
- ["minecraft:torch"] = {{1,3,2,4}},
- ["minecraft:redstone_torch"] = {{1,3,2,4}},
- ["minecraft:unlit_redstone_torch"] = {{1,3,2,4}},
- ["minecraft:oak_stairs"] = {{3,0,2,1},{7,4,6,5}},
- ["minecraft:stone_stairs"] = {{3,0,2,1},{7,4,6,5}},
- ["minecraft:stone_brick_stairs"] = {{3,0,2,1},{7,4,6,5}},
- ["minecraft:brick_stairs"] = {{3,0,2,1},{7,4,6,5}},
- ["minecraft:sandstone_stairs"] = {{3,0,2,1},{7,4,6,5}},
- ["minecraft:nether_brick_stairs"] = {{3,0,2,1},{7,4,6,5}},
- ["minecraft:spruce_stairs"] = {{3,0,2,1},{7,4,6,5}},
- ["minecraft:birch_stairs"] = {{3,0,2,1},{7,4,6,5}},
- ["minecraft:jungle_stairs"] = {{3,0,2,1},{7,4,6,5}},
- ["minecraft:quartz_stairs"] = {{3,0,2,1},{7,4,6,5}},
- ["minecraft:acacia_stairs"] = {{3,0,2,1},{7,4,6,5}},
- ["minecraft:dark_oak_stairs"] = {{3,0,2,1},{7,4,6,5}},
- ["minecraft:hay_block"] = {{8,4}},
- ["minecraft:log"] = {{8,4},{9,5},{10,6},{11,7}},
- ["minecraft:log2"] = {{8,4},{9,5}},
- ["minecraft:cocoa"] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}},
- ["minecraft:pumpkin"] = {{0,1,2,3}},
- ["minecraft:lit_pumpkin"] = {{0,1,2,3}},
- ["minecraft:quartz_block"] = {{3,4}},
- ["minecraft:chest"] = {{3,4,2,5}},
- ["minecraft:trapped_chest"] = {{3,4,2,5}},
- ["minecraft:ender_chest"] = {{3,4,2,5}},
- ["minecraft:furnace"] = {{3,4,2,5}},
- ["minecraft:lit_furnace"] = {{3,4,2,5}},
- ["minecraft:ladder"] = {{3,4,2,5}},
- ["minecraft:vine"] = {{4,8,1,2},{3,6,12,9},{5,10},{11,7,14,13}},
- ["minecraft:anvil"] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}},
- ["minecraft:standing_sign"] = {{0,4,8,12},{1,5,9,13},{2,6,10,14},{3,7,11,15}},
- ["minecraft:wall_sign"] = {{3,4,2,5}},
- ["minecraft:bed"] = {{2,3,0,1},{10,11,8,9}},
- ["minecraft:skull"] = {{3,4,2,5}},
- ["minecraft:dispenser"] = {{3,4,2,5}},
- ["minecraft:dropper"] = {{3,4,2,5}},
- ["minecraft:hopper"] = {{3,4,2,5}},
- ["minecraft:piston"] = {{3,4,2,5},{11,12,10,13}},
- ["minecraft:sticky_piston"] = {{3,4,2,5},{11,12,10,13}},
- ["minecraft:piston_head"] = {{3,4,2,5},{11,12,10,13}},
- ["minecraft:lever"] = {{6,5},{13,14},{3,2,4,1},{11,10,12,9},{0,7},{15,8}},
- ["minecraft:stone_button"] = {{1,3,2,4},{11,10,12,9}},
- ["minecraft:wooden_button"] = {{1,3,2,4},{11,10,12,9}},
- ["minecraft:trapdoor"] = {{0,3,1,2},{5,6,4,7},{9,10,8,11},{13,14,12,15}},
- ["minecraft:fence_gate"] = {{3,0,1,2},{7,4,5,6}},
- ["minecraft:tripwire_hook"] = {{0,1,2,3},{7,4,5,6},{15,12,13,14}},
- ["minecraft:wooden_door"] = {{3,0,1,2},{7,4,5,6}},
- ["minecraft:iron_door"] = {{3,0,1,2},{7,4,5,6}},
- ["minecraft:unpowered_repeater"] = {{0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15}},
- ["minecraft:powered_repeater"] = {{0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15}},
- ["minecraft:unpowered_comparator"] = {{0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15}},
- ["minecraft:rail"] = {{0,1},{4,2,5,3},{8,9,6,7}},
- ["minecraft:golden_rail"] = {{0,1},{4,2,5,3},{8,9},{12,10,13,11}},
- ["minecraft:detector_rail"] = {{0,1},{4,2,5,3},{8,9},{12,10,13,11}},
- ["minecraft:activator_rail"] = {{0,1},{4,2,5,3},{8,9},{12,10,13,11}},
- ["minecraft:red_mushroom_block"] = {{1,3,9,7},{2,6,8,4}},
- ["minecraft:brown_mushroom_block"] = {{1,3,9,7},{2,6,8,4}},
- ["minecraft:end_portal_frame"] = {{0,1,2,3},{4,5,6,7}},
- -- ComputerCraft 1.72:
- ["ComputerCraft:CC-Computer"] = {{3,4,2,5},{11,12,10,13}},
- ["ComputerCraft:CC-Cable"] = {{3,4,2,5},{10,8,11,9}},
- ["ComputerCraft:CC-Peripheral"] = {{3,4,2,5},{6,9,7,8}},
- ["ComputerCraft:command_computer"] = {{3,4,2,5}},
- -- MoarPeripherals 1.52:
- ["moarperipherals:blockKeyboardMac"] = {{3,4,2,5}},
- ["moarperipherals:blockKeyboardPc"] = {{3,4,2,5}},
- -- MoarPeripherals 1.53:
- ["MoarPeripherals:blockKeyboardMac"] = {{3,4,2,5}},
- ["MoarPeripherals:blockKeyboardPc"] = {{3,4,2,5}}
- }
- local menu = {
- {"What Do?",
- {
- --{["button"] = {["text"] = "Scan", ["x"] = 21, ["y"] = 8, ["length"] = 10}},
- {["button"] = {["text"] = "Build", ["x"] = 21, ["y"] = 11, ["length"] = 10}},
- {["button"] = {["text"] = "Quit", ["x"] = 21, ["y"] = 14, ["length"] = 10}}
- }},
- {
- {"Enter Bounding Co-ordinates",
- {
- {["label"] = {["x"] = 11, ["y"] = 7, ["text"] = "X1"}, ["textbox"] = true, ["x"] = 15, ["y"] = 7, ["length"] = 7, ["number"] = true},
- {["label"] = {["x"] = 11, ["y"] = 10, ["text"] = "Y1"}, ["textbox"] = true, ["x"] = 15, ["y"] = 10, ["length"] = 7, ["number"] = true, ["min"] = 0, ["max"] = 255},
- {["label"] = {["x"] = 11, ["y"] = 13, ["text"] = "Z1"}, ["textbox"] = true, ["x"] = 15, ["y"] = 13, ["length"] = 7, ["number"] = true},
- {["label"] = {["x"] = 31, ["y"] = 7, ["text"] = "X2"}, ["textbox"] = true, ["x"] = 35, ["y"] = 7, ["length"] = 7, ["number"] = true},
- {["label"] = {["x"] = 31, ["y"] = 10, ["text"] = "Y2"}, ["textbox"] = true, ["x"] = 35, ["y"] = 10, ["length"] = 7, ["number"] = true, ["min"] = 0, ["max"] = 255},
- {["label"] = {["x"] = 31, ["y"] = 13, ["text"] = "Z2"}, ["textbox"] = true, ["x"] = 35, ["y"] = 13, ["length"] = 7, ["number"] = true},
- {["button"] = {["text"] = "Ok", ["x"] = xSize - 7, ["y"] = ySize - 4, ["length"] = 6}},
- {["button"] = {["text"] = "Back", ["x"] = 2, ["y"] = ySize - 4, ["length"] = 6, ["ignoreFilters"] = true}}
- }},
- {"Set Output",
- {
- {["label"] = {["x"] = 11, ["y"] = 7, ["text"] = "Filename"}, ["textbox"] = true, ["x"] = 21, ["y"] = 7, ["length"] = 12, ["filter"] = "\\/:*?\"<>"},
- {["button"] = {["text"] = "Ok", ["x"] = xSize - 7, ["y"] = ySize - 4, ["length"] = 6}},
- {["button"] = {["text"] = "Back", ["x"] = 2, ["y"] = ySize - 4, ["length"] = 6, ["ignoreFilters"] = true}}
- }},
- {"File exists; overwrite?",
- {
- {["button"] = {["text"] = "Ok", ["x"] = xSize - 7, ["y"] = ySize - 4, ["length"] = 6}},
- {["button"] = {["text"] = "Back", ["x"] = 2, ["y"] = ySize - 4, ["length"] = 6, ["ignoreFilters"] = true}}
- }}
- },
- {
- {"Choose A File"},
- {"Enter Destination",
- {
- {["label"] = {["x"] = 11, ["y"] = 7, ["text"] = "X"}, ["textbox"] = true, ["x"] = 14, ["y"] = 7, ["length"] = 7, ["number"] = true},
- {["label"] = {["x"] = 11, ["y"] = 10, ["text"] = "Y"}, ["textbox"] = true, ["x"] = 14, ["y"] = 10, ["length"] = 7, ["number"] = true, ["min"] = 0, ["max"] = 255},
- {["label"] = {["x"] = 11, ["y"] = 13, ["text"] = "Z"}, ["textbox"] = true, ["x"] = 14, ["y"] = 13, ["length"] = 7, ["number"] = true},
- {["label"] = {["x"] = 28, ["y"] = 7, ["text"] = "Rotation 0"}, ["radiobox"] = true, ["x"] = 41, ["y"] = 7, ["set"] = "rotate"},
- {["label"] = {["x"] = 28, ["y"] = 9, ["text"] = "Rotation 90"}, ["radiobox"] = true, ["x"] = 41, ["y"] = 9, ["set"] = "rotate"},
- {["label"] = {["x"] = 28, ["y"] = 11, ["text"] = "Rotation 180"}, ["radiobox"] = true, ["x"] = 41, ["y"] = 11, ["set"] = "rotate"},
- {["label"] = {["x"] = 28, ["y"] = 13, ["text"] = "Rotation 270"}, ["radiobox"] = true, ["x"] = 41, ["y"] = 13, ["set"] = "rotate"},
- {["label"] = {["x"] = 15, ["y"] = 15, ["text"] = "Pre-clear build zone?"}, ["checkbox"] = true, ["x"] = 37, ["y"] = 15},
- {["button"] = {["text"] = "Ok", ["x"] = xSize - 7, ["y"] = ySize - 4, ["length"] = 6}},
- {["button"] = {["text"] = "Back", ["x"] = 2, ["y"] = ySize - 4, ["length"] = 6, ["ignoreFilters"] = true}}
- }},
- {"Set Direction",
- {
- {["label"] = {["x"] = 11, ["y"] = 7, ["text"] = "North West"}, ["radiobox"] = true, ["x"] = 23, ["y"] = 7, ["set"] = "horizontalDir"},
- {["label"] = {["x"] = 11, ["y"] = 9, ["text"] = "North East"}, ["radiobox"] = true, ["x"] = 23, ["y"] = 9, ["set"] = "horizontalDir"},
- {["label"] = {["x"] = 11, ["y"] = 11, ["text"] = "South East"}, ["radiobox"] = true, ["x"] = 23, ["y"] = 11, ["set"] = "horizontalDir"},
- {["label"] = {["x"] = 11, ["y"] = 13, ["text"] = "South West"}, ["radiobox"] = true, ["x"] = 23, ["y"] = 13, ["set"] = "horizontalDir"},
- {["label"] = {["x"] = 31, ["y"] = 7, ["text"] = "Upwards"}, ["radiobox"] = true, ["x"] = 41, ["y"] = 7, ["set"] = "verticalDir"},
- {["label"] = {["x"] = 31, ["y"] = 9, ["text"] = "Downwards"}, ["radiobox"] = true, ["x"] = 41, ["y"] = 9, ["set"] = "verticalDir"},
- {["button"] = {["text"] = "Ok", ["x"] = xSize - 7, ["y"] = ySize - 4, ["length"] = 6}},
- {["button"] = {["text"] = "Back", ["x"] = 2, ["y"] = ySize - 4, ["length"] = 6, ["ignoreFilters"] = true}}
- }}
- },
- {
- {3, 7, "Low NW:", 1, 1, 1}, {3, 9, "Low NE:", 2, 1, 1}, {3, 11, "Low SW:", 1, 1, 2}, {3, 13, "Low SE:", 2, 1, 2},
- {28, 7, "Top NW:", 1, 2, 1}, {28, 9, "Top NE:", 2, 2, 1}, {28, 11, "Top SW:", 1, 2, 2}, {28, 13, "Top SE:", 2, 2, 2}
- }
- }
- ---------------------------------------------
- ------------ Misc Functions ------------
- ---------------------------------------------
- local function clear(textCol, backCol)
- if textCol then term.setTextColour(textCol) end
- if backCol then term.setBackgroundColour(backCol) end
- for i = 4, ySize - 3 do
- term.setCursorPos(1, i)
- term.clearLine()
- end
- end
- -- Returns whether a click was performed at a given location.
- -- If one parameter is passed, it checks to see if y is [1].
- -- If two parameters are passed, it checks to see if x is [1] and y is [2].
- -- If three parameters are passed, it checks to see if x is between [1]/[2] (non-inclusive) and y is [3].
- -- If four paramaters are passed, it checks to see if x is between [1]/[2] and y is between [3]/[4] (non-inclusive).
- local function clickedAt(...)
- if myEvent[1] ~= "mouse_click" then return false end
- if #arg == 1 then return (arg[1] == myEvent[4])
- elseif #arg == 2 then return (myEvent[3] == arg[1] and myEvent[4] == arg[2])
- elseif #arg == 3 then return (myEvent[3] > arg[1] and myEvent[3] < arg[2] and myEvent[4] == arg[3])
- else return (myEvent[3] > arg[1] and myEvent[3] < arg[2] and myEvent[4] > arg[3] and myEvent[4] < arg[4]) end
- end
- -- Returns whether one of a given set of keys was pressed.
- local function pressedKey(...)
- if myEvent[1] ~= "key" then return false end
- for i=1,#arg do if arg[i] == myEvent[2] then return true end end
- return false
- end
- ---------------------------------------------
- ------------ Scanning Function ------------
- ---------------------------------------------
- local function doScan(filename, xstart, ystart, zstart, xmax, ymax, zmax)
- clear(colours.black, colours.lightGrey)
- term.setCursorPos(22, 5)
- term.write("Scanning")
- term.setBackgroundColour(colours.grey)
- term.setCursorPos(4, 11)
- term.write(string.rep(" ", 45))
- term.setTextColour(colours.grey)
- term.setBackgroundColour(colours.lightGrey)
- local x, y, z, scan, fileOut, counter, commonBlocks, last, amount, myTimer = 1, 1, 1, {}, fs.open(shell.resolve(filename), "wb"), 0, {}
- local function writeString(text)
- for i = 1, #text do fileOut.write(text:byte(i)) end
- end
- local function writeInt(num)
- fileOut.write(bit.band(num, 255))
- fileOut.write(bit.brshift(num, 8))
- end
- writeString("BLK")
- fileOut.write(0) -- File version.
- fileOut.write(commands.getBlockInfo(commands.getBlockPosition()).metadata) -- Facing of scanning computer.
- fileOut.write(ystart)
- writeInt(xmax)
- fileOut.write(ymax)
- writeInt(zmax)
- local scanfuncs = {function()
- local countmax, lastcount = xmax * ymax * zmax, 0
- repeat
- myTimer = os.startTimer(60)
- repeat event, id = os.pullEvent("timer") until id == myTimer
- term.setBackgroundColour(colours.yellow)
- term.setCursorPos(4, 11)
- term.write(string.rep(" ", math.floor(counter / countmax * 45)))
- term.setBackgroundColour(colours.grey)
- term.write(string.rep(" ", 45 - math.floor(counter / countmax * 45)))
- term.setBackgroundColour(colours.lightGrey)
- term.setCursorPos(4, 7)
- term.clearLine()
- term.write(tostring(counter) .. " / " .. tostring(countmax) .. " blocks" .. (counter < countmax and ", ~" .. tostring(counter - lastcount) .. " per minute." or "."))
- term.setCursorPos(4, 9)
- term.clearLine()
- term.write(counter < countmax and tostring(math.floor(counter / countmax * 100)) .. "%, about " .. tostring(math.ceil((countmax - counter) / (counter - lastcount))) .. " minutes remaining." or "100%")
- lastcount = counter
- until counter == countmax
- end}
- local function checkPos()
- while y < ymax + 1 do
- local myX, myY, myZ = x, y, z
- counter = counter + 1
- x = x + 1
- if x > xmax then
- z = z + 1
- x = 1
- if z > zmax then
- y = y + 1
- z = 1
- end
- end
- if not scan[myY] then scan[myY] = {} end
- if not scan[myY][myZ] then scan[myY][myZ] = {} end
- scan[myY][myZ][myX] = commands.getBlockInfo(myX + xstart - 1, myY + ystart - 1, myZ + zstart - 1)
- end
- os.queueEvent("timer", myTimer)
- end
- for i = 2, maxSeekerFuncs + 1 do scanfuncs[i] = checkPos end
- local function doWrite()
- if type(commonBlocks[last]) == "table" then
- if #commonBlocks > 255 then writeInt(0) else fileOut.write(0) end
- writeString(commonBlocks[last][1])
- fileOut.write(0)
- fileOut.write(commonBlocks[last][2])
- commonBlocks[last] = true
- elseif #commonBlocks > 255 then writeInt(last) else fileOut.write(last) end
- if amount > 255 then
- fileOut.write(0)
- writeInt(amount - 1)
- else fileOut.write(amount) end
- end
- scanfuncs[#scanfuncs + 1] = function()
- for y = 1, ymax do for z = 1, zmax do for x = 1, xmax do
- while not (scan[y] and scan[y][z] and scan[y][z][x]) do os.pullEvent("task_complete") end
- local next = scan[y][z][x]
- scan[y][z][x] = nil
- if not (commonBlocks[next.name] and commonBlocks[next.name][next.metadata]) then
- commonBlocks[#commonBlocks + 1] = {next.name, next.metadata}
- if not commonBlocks[next.name] then commonBlocks[next.name] = {} end
- commonBlocks[next.name][next.metadata] = #commonBlocks
- end
- if commonBlocks[next.name][next.metadata] == last then
- amount = amount + 1
- else
- if last then doWrite() end
- last = commonBlocks[next.name][next.metadata]
- amount = 1
- end
- end scan[y][z] = nil end scan[y] = nil end
- end
- parallel.waitForAll(unpack(scanfuncs))
- doWrite()
- fileOut.close()
- term.setCursorPos(4, 13)
- term.write("Completed write to \"" .. fs.getName(filename) .. "\".")
- term.setCursorPos(4, 15)
- term.write("Press any key to continue...")
- os.pullEvent("key")
- end
- ---------------------------------------------
- ------------ Building Function ------------
- ---------------------------------------------
- local function doBuild(filename, x1, y1, z1, rotate, preclear)
- clear(colours.black, colours.lightGrey)
- term.setCursorPos(22, 5)
- term.write("Building")
- term.setBackgroundColour(colours.grey)
- term.setCursorPos(4, 11)
- term.write(string.rep(" ", 45))
- term.setTextColour(colours.grey)
- term.setBackgroundColour(colours.lightGrey)
- local fileIn, myTimer = fs.open(filename,"rb")
- if not fileIn then error(filename.." does not exist or cannot be opened.") end
- local function readString()
- local result, val = {}
- while true do
- val = fileIn.read()
- if val == 0 then return table.concat(result) end
- result[#result + 1] = string.char(val)
- end
- end
- local function readInt()
- local result = fileIn.read()
- return result + bit.blshift(fileIn.read(), 8)
- end
- do
- local header = 0
- for i = 1, 3 do header = header + fileIn.read() end
- if header ~= 217 then error(filename.." is not a valid WorldPorter data file.") end
- end
- fileIn.read() -- File version.
- local facing = fileIn.read()
- local originalY = fileIn.read()
- local xmax = readInt()
- local ymax = fileIn.read()
- local zmax = readInt()
- local curCommands, counter = 0, 0
- local holoTable = {}
- parallel.waitForAny(
- function()
- local countmax, lastcount = xmax * ymax * zmax, 0
- if preclear then countmax = countmax * 2 end
- repeat
- myTimer = os.startTimer(60)
- repeat local event, id = os.pullEvent("timer") until id == myTimer
- term.setBackgroundColour(colours.yellow)
- term.setCursorPos(4, 11)
- term.write(string.rep(" ", math.floor(counter / countmax * 45)))
- term.setBackgroundColour(colours.grey)
- term.write(string.rep(" ", 45 - math.floor(counter / countmax * 45)))
- term.setBackgroundColour(colours.lightGrey)
- term.setCursorPos(4, 7)
- term.clearLine()
- term.write(tostring(counter) .. " / " .. tostring(countmax) .. " blocks" .. (counter < countmax and ", ~" .. tostring(counter - lastcount) .. " per minute." or "."))
- term.setCursorPos(4, 9)
- term.clearLine()
- term.write(counter < countmax and tostring(math.floor(counter / countmax * 100)) .. "%, about " .. tostring(math.ceil((countmax - counter) / (counter - lastcount))) .. " minutes remaining." or "100%")
- lastcount = counter
- until counter == countmax
- end,
- function()
- local record, commonBlocks, secondPass, thirdPass, fourthPass, doorCache, toCoordsString = {nil, nil, 0}, {}, {}, {}, {}, {}
- toCoordsString = function(x, y, z) return tostring(x).." "..tostring(y).." "..tostring(z) end
- local function doCommand(doThis)
- if doThis[1] > 0 and doThis[1] < 9 and doThis[2] > 0 and doThis[2] < 9 and doThis[3] > 0 and doThis[3] < 9 then
- holoTable[#holoTable + 1] = {["x"] = doThis[1] - 1, ["y"] = doThis[2] - 1, ["z"] = doThis[3] - 1, ["name"] = doThis[4], ["meta"] = doThis[5]}
- end
- counter = counter + 1
- end
- if preclear then for y = ymax, 1, -1 do for z = 1, zmax do for x = 1, xmax do doCommand("setblock " .. toCoordsString(x, y, z) .. " minecraft:air 0") end end end end
- for y = 1, ymax do for z = 1, zmax do for x = 1, xmax do
- if record[3] == 0 then
- local block
- if #commonBlocks > 255 then block = readInt() else block = fileIn.read() end
- if block == 0 then
- block = readString()
- commonBlocks[#commonBlocks + 1] = {block, fileIn.read()}
- block = #commonBlocks
- end
- local amount = fileIn.read()
- record = {commonBlocks[block][1], commonBlocks[block][2], amount == 0 and readInt() or amount - 1}
- if forcedTranslation[record[1]] and forcedTranslation[record[1]][record[2]] then record[2] = forcedTranslation[record[1]][record[2]] end
- --if rotationTranslation[record[1]] and rotationTranslation[record[1]][record[2]] then for i = 0, rotate - 1 do record[2] = rotationTranslation[record[1]][record[2]] end end
- else record[3] = record[3] - 1 end
- local doThis = {x, y, z, record[1], record[2]}
- if preclear and record[1] == "minecraft:air" then
- counter = counter + 1
- elseif doorBlocks[record[1]] then
- if record[2] > 7 then
- secondPass[#secondPass + 1] = doorCache[toCoordsString(x, y, z)]
- secondPass[#secondPass + 1] = doThis
- doorCache[toCoordsString(x, y, z)] = nil
- else doorCache[toCoordsString(x, y + 1, z)] = doThis end
- elseif dependantBlocks[record[1]] then
- thirdPass[#thirdPass + 1] = doThis
- elseif fluidBlocks[record[1]] then
- fourthPass[#fourthPass + 1] = doThis
- else doCommand(doThis) end
- end end end
- fileIn.close()
- for i = 1, #secondPass do doCommand(secondPass[i]) end
- for i = 1, #thirdPass do doCommand(thirdPass[i]) end
- for i = 1, #fourthPass do doCommand(fourthPass[i]) end
- os.queueEvent("timer", myTimer)
- while true do os.pullEvent("stopResumingMe") end
- end
- )
- holo.clear("minecraft:air", 0)
- holo.draw(holoTable)
- term.setCursorPos(4, 13)
- term.write("Completed build of \"" .. fs.getName(filename) .. "\".")
- term.setCursorPos(4, 15)
- term.write("Press any key to continue...")
- os.pullEvent("key")
- end
- ---------------------------------------------
- ------------ GUI Functions ------------
- ---------------------------------------------
- local function fileBrowser()
- local bump = math.floor((xSize - 49) / 2) + 1
- while true do
- local displayList, position, lastPosition, animationTimer, curCount, gapTimer, lastProgress = {}, 1, 0, os.startTimer(0), 1
- if #shell.resolve(".") > 0 then displayList[1] = ".." end
- do
- local fullList = fs.list(shell.resolve("."))
- table.sort(fullList, function (a, b) return string.lower(a) < string.lower(b) end)
- for i = 1, #fullList do if fs.isDir(shell.resolve(fullList[i])) then displayList[#displayList + 1] = fullList[i] end end
- for i = 1, #fullList do if fullList[i]:sub(#fullList[i] - 3):lower() == ".blk" then displayList[#displayList + 1] = fs.getName(fullList[i]) end end
- end
- while true do
- myEvent = {os.pullEvent()}
- -- Track animations (bouncing cursor + scrolling marquee).
- if myEvent[1] == "timer" and myEvent[2] == animationTimer then
- curCount = curCount == 4 and 1 or (curCount + 1)
- animationTimer = os.startTimer(0.5)
- myEvent[1] = "cabbage"
- -- Bail.
- elseif pressedKey(keys.backspace) or (myEvent[1] == "mouse_click" and myEvent[2] == 2) then
- return nil
- -- Move down the list.
- elseif pressedKey(keys.down, keys.s) or (myEvent[1] == "mouse_scroll" and myEvent[2] == 1) then
- position = position == #displayList and 1 or (position + 1)
- -- Move up the list.
- elseif pressedKey(keys.up, keys.w) or (myEvent[1] == "mouse_scroll" and myEvent[2] == -1) then
- position = position == 1 and #displayList or (position - 1)
- -- Select something.
- elseif pressedKey(keys.enter, keys.space) or clickedAt(math.floor(ySize / 2) + 1) then
- if fs.isDir(shell.resolve(displayList[position])) then
- shell.setDir(shell.resolve(displayList[position]))
- break
- else return shell.resolve(displayList[position]) end
- -- User clicked somewhere on the file list; move that entry to the currently-selected position.
- elseif clickedAt(0, xSize + 1, 3, ySize - 2) then
- position = position + myEvent[4] - math.floor(ySize / 2) - 1
- position = position > #displayList and #displayList or position
- position = position < 1 and 1 or position
- end
- -- Update other screen stuff.
- if myEvent[1] ~= "timer" then
- -- File list.
- term.setBackgroundColour(colours.black)
- for y = position == lastPosition and (math.floor(ySize / 2) + 1) or 4, position == lastPosition and (math.floor(ySize / 2) + 1) or (ySize - 3) do
- local thisLine = y + position - math.floor(ySize / 2) - 1
- if displayList[thisLine] then
- local thisString = displayList[thisLine]
- thisString = fs.isDir(shell.resolve(thisString)) and "["..thisString.."]" or thisString:sub(1, #thisString-4)
- if thisLine == position then
- term.setCursorPos(math.floor((xSize - #thisString - 8) / 2) + 1, y)
- term.clearLine()
- term.setTextColour(colours.red)
- term.write(cursor[curCount][1])
- term.setTextColour(colours.orange)
- term.write(thisString)
- term.setTextColour(colours.red)
- term.write(cursor[curCount][2])
- else
- term.setCursorPos(math.floor((xSize - #thisString) / 2) + 1, y)
- term.clearLine()
- if y == 4 or y == ySize - 3 then term.setTextColour(colours.black)
- elseif y == 5 or y == ySize - 4 then term.setTextColour(colours.grey)
- elseif y == 6 or y == ySize - 5 then term.setTextColour(colours.lightGrey)
- else term.setTextColour(colours.white) end
- term.write(thisString)
- end
- else
- term.setCursorPos(1, y)
- term.clearLine()
- end
- end
- lastPosition = position
- end
- end
- end
- end
- local function form(...)
- local radio = {}
- for index, element in ipairs(arg) do
- if element.button then
- term.setTextColour(buttonText)
- term.setBackgroundColour(buttonBack)
- term.setCursorPos(element.button.x, element.button.y)
- term.write(string.rep(" ", math.ceil((element.button.length - #element.button.text) / 2))..element.button.text..string.rep(" ", math.floor((element.button.length - #element.button.text) / 2)))
- else
- term.setTextColour(labelText)
- term.setBackgroundColour(labelBack)
- term.setCursorPos(element.label.x, element.label.y)
- element.label.text = tostring(element.label.text)
- term.write(element.label.text .. (element.textbox and ":" or ""))
- term.setBackgroundColour(inputBack)
- term.setCursorPos(element.x, element.y)
- term.setTextColour(inputText)
- if element.textbox then
- element.content = element.content and tostring(element.content) or ""
- element.curX = #element.content + 1
- element.scroll = math.max(1, #element.content - element.length + 2)
- term.write(element.content:sub(element.scroll, element.scroll + element.length - 1) .. string.rep(" ", math.max(0, element.length - #element.content + element.scroll - 1)))
- elseif element.radiobox then
- if radio[element.set] then
- radio[element.set][#radio[element.set] + 1] = index
- term.write(" ")
- else
- radio[element.set] = {index, ["set"] = 1}
- term.write("O")
- end
- elseif element.checkbox then
- if type(element.content) == "nil" then element.content = false end
- term.write(element.content and "X" or " ")
- end
- end
- end
- term.setTextColour(inputText)
- local curElement = arg[1]
- if curElement.textbox then
- term.setCursorPos(curElement.x + curElement.curX - curElement.scroll, curElement.y)
- term.setCursorBlink(true)
- elseif curElement.button then
- term.setCursorBlink(false)
- term.setTextColour(buttonText)
- term.setBackgroundColour(buttonBack)
- term.setCursorPos(curElement.button.x, curElement.button.y)
- term.write("["..string.rep(" ", math.ceil((curElement.button.length - #curElement.button.text) / 2) - 1)..curElement.button.text..string.rep(" ", math.floor((curElement.button.length - #curElement.button.text) / 2) - 1).."]")
- else
- term.setCursorPos(curElement.x, curElement.y)
- term.setCursorBlink(true)
- end
- while true do
- local myEvent, oldElement, finished = {os.pullEvent()}, curElement, false
- if (myEvent[1] == "key" and (myEvent[2] == keys.tab or myEvent[2] == keys.down)) or (myEvent[1] == "mouse_scroll" and myEvent[2] == 1) then
- for i = 1, #arg do if arg[i] == curElement then
- curElement = arg[i == #arg and 1 or i + 1]
- break
- end end
- elseif (myEvent[1] == "key" and myEvent[2] == keys.up) or (myEvent[1] == "mouse_scroll" and myEvent[2] == -1) then
- for i = 1, #arg do if arg[i] == curElement then
- curElement = arg[i == 1 and #arg or i - 1]
- break
- end end
- elseif myEvent[1] == "mouse_click" and myEvent[2] == 1 then
- for index, element in ipairs(arg) do
- if element.textbox and myEvent[3] >= element.x and myEvent[3] < element.x + element.length and myEvent[4] == element.y then
- curElement = element
- curElement.curX = math.max(1, math.min(myEvent[3] - curElement.x + curElement.scroll, #curElement.content + 1))
- term.setCursorPos(curElement.x + curElement.curX - curElement.scroll, curElement.y)
- break
- elseif element.radiobox and myEvent[3] == element.x and myEvent[4] == element.y then
- for i = 1, #radio[element.set] do
- term.setCursorPos(arg[radio[element.set][i]].x, arg[radio[element.set][i]].y)
- if radio[element.set][i] == index then
- radio[element.set].set = i
- term.write("O")
- else term.write(" ") end
- end
- curElement = element
- term.setCursorPos(curElement.x, curElement.y)
- break
- elseif element.checkbox and myEvent[3] == element.x and myEvent[4] == element.y then
- curElement = element
- element.content = not element.content
- term.setCursorPos(curElement.x, curElement.y)
- term.write(element.content and "X" or " ")
- term.setCursorPos(curElement.x, curElement.y)
- break
- elseif element.button and myEvent[3] >= element.button.x and myEvent[3] < element.button.x + element.button.length and myEvent[4] == element.button.y then
- finished = true
- curElement = element
- break
- end
- end
- elseif myEvent[1] == "paste" and curElement.textbox then
- for i = 1, #myEvent[2] do os.queueEvent("char", myEvent[2]:sub(i, i)) end
- elseif myEvent[1] == "char" and curElement.textbox then
- curElement.content = curElement.content:sub(1, curElement.curX - 1) .. myEvent[2] .. curElement.content:sub(curElement.curX, #curElement.content)
- curElement.curX = curElement.curX + 1
- if curElement.curX - curElement.scroll + 1 > curElement.length then curElement.scroll = curElement.scroll + 1 end
- term.setCursorPos(curElement.x, curElement.y)
- term.write(curElement.content:sub(curElement.scroll, curElement.scroll + curElement.length - 1))
- term.setCursorPos(curElement.x + curElement.curX - curElement.scroll, curElement.y)
- elseif myEvent[1] == "key" then
- if myEvent[2] == keys.enter then
- for i = 1, #arg do
- if curElement.button then break end
- if arg[i] == curElement then curElement = arg[i == #arg and 1 or i + 1] end
- end
- finished = true
- elseif curElement.textbox then
- if myEvent[2] == keys.left and curElement.curX > 1 then
- curElement.curX = curElement.curX - 1
- if curElement.curX < curElement.scroll then curElement.scroll = curElement.curX end
- elseif myEvent[2] == keys.right and curElement.curX < #curElement.content + 1 then
- curElement.curX = curElement.curX + 1
- if curElement.curX > curElement.scroll + curElement.length - 1 then curElement.scroll = curElement.scroll + 1 end
- elseif myEvent[2] == keys.backspace and curElement.curX > 1 then
- curElement.content = curElement.content:sub(1, curElement.curX - 2) .. curElement.content:sub(curElement.curX, #curElement.content)
- curElement.curX = curElement.curX - 1
- if curElement.curX < curElement.scroll then curElement.scroll = curElement.curX end
- elseif myEvent[2] == keys.delete and curElement.curX <= #curElement.content then
- curElement.content = curElement.content:sub(1, curElement.curX - 1) .. curElement.content:sub(curElement.curX + 1, #curElement.content)
- end
- term.setCursorPos(curElement.x, curElement.y)
- term.write(curElement.content:sub(curElement.scroll, curElement.scroll + curElement.length - 1) .. string.rep(" ", math.max(0, curElement.length - #curElement.content + curElement.scroll - 1)))
- term.setCursorPos(curElement.x + curElement.curX - curElement.scroll, curElement.y)
- elseif curElement.radiobox and myEvent[2] == keys.space and arg[radio[curElement.set][radio[curElement.set].set]] ~= curElement then
- local set = radio[curElement.set]
- for i = 1, #set do
- term.setCursorPos(arg[set[i]].x, arg[set[i]].y)
- if arg[set[i]] == curElement then
- set.set = i
- term.write("O")
- else term.write(" ") end
- end
- term.setCursorPos(curElement.x, curElement.y)
- elseif curElement.checkbox and myEvent[2] == keys.space then
- curElement.content = not curElement.content
- term.write(curElement.content and "X" or " ")
- term.setCursorPos(curElement.x, curElement.y)
- elseif curElement.button and myEvent[2] == keys.space then
- finished = true
- os.pullEvent("char")
- end
- end
- if oldElement ~= curElement then
- if oldElement.button then
- term.setTextColour(buttonText)
- term.setBackgroundColour(buttonBack)
- term.setCursorPos(oldElement.button.x, oldElement.button.y)
- term.write(string.rep(" ", math.ceil((oldElement.button.length - #oldElement.button.text) / 2))..oldElement.button.text..string.rep(" ", math.floor((oldElement.button.length - #oldElement.button.text) / 2)))
- end
- if curElement.button then
- term.setCursorBlink(false)
- term.setTextColour(buttonText)
- term.setBackgroundColour(buttonBack)
- term.setCursorPos(curElement.button.x, curElement.button.y)
- term.write("["..string.rep(" ", math.ceil((curElement.button.length - #curElement.button.text) / 2) - 1)..curElement.button.text..string.rep(" ", math.floor((curElement.button.length - #curElement.button.text) / 2) - 1).."]")
- else
- term.setTextColour(inputText)
- term.setBackgroundColour(inputBack)
- if curElement.textbox then
- term.setCursorPos(curElement.x + curElement.curX - curElement.scroll, curElement.y)
- else
- term.setCursorPos(curElement.x, curElement.y)
- end
- term.setCursorBlink(true)
- end
- end
- if finished then
- local results, flash = {curElement.button.text}, {}
- for index, element in ipairs(arg) do
- if element.textbox then
- if element.number then
- results[element.label.text] = tonumber(element.content)
- if results[element.label.text] then
- if element.min and results[element.label.text] < element.min then
- results[element.label.text] = nil
- elseif element.max and results[element.label.text] > element.max then
- results[element.label.text] = nil
- end
- end
- elseif element.filter then
- local ok = true
- for i = 1, #element.filter do if element.content:find(element.filter:sub(i,i)) then
- ok = false
- break
- end end
- if ok and #element.content > 0 then results[element.label.text] = element.content end
- else results[element.label.text] = element.content end
- if not results[element.label.text] then
- flash[#flash + 1] = index
- results[element.label.text] = element.content
- end
- elseif element.checkbox then
- results[element.label.text] = element.content
- end
- end
- for key, element in pairs(radio) do results[key] = element.set end
- if #flash > 0 and not curElement.button.ignoreFilters then
- term.setTextColour(colours.brown)
- term.setBackgroundColour(colors.red)
- for i = 1, #flash do
- local element = arg[flash[i]]
- term.setCursorPos(element.x, element.y)
- term.write(element.content:sub(element.scroll, element.scroll + element.length - 1) .. string.rep(" ", math.max(0, element.length - #element.content + element.scroll - 1)))
- end
- sleep(0.25)
- term.setTextColour(inputText)
- term.setBackgroundColour(inputBack)
- for i = 1, #flash do
- local element = arg[flash[i]]
- term.setCursorPos(element.x, element.y)
- term.write(element.content:sub(element.scroll, element.scroll + element.length - 1) .. string.rep(" ", math.max(0, element.length - #element.content + element.scroll - 1)))
- end
- else return results end
- end
- end
- end
- ---------------------------------------------
- ------------ Init ------------
- ---------------------------------------------
- do
- local temp = {}
- for i = 1, #dependantBlocks do temp[dependantBlocks[i]] = i end
- dependantBlocks = temp
- temp = {}
- for i = 1, #doorBlocks do temp[doorBlocks[i]] = i end
- doorBlocks = temp
- temp = {}
- for i = 1, #fluidBlocks do temp[fluidBlocks[i]] = i end
- fluidBlocks = temp
- end
- for key, value in pairs(rotationTranslation) do
- local temp = {}
- for i = 1, #value do
- for j = 1, #value[i] - 1 do temp[value[i][j]] = value[i][j + 1] end
- temp[value[i][#value[i]]] = value[i][1]
- end
- rotationTranslation[key] = temp
- end
- for key, value in pairs(forcedTranslation) do
- local temp = {}
- for i = 1, #value do temp[value[i][1]] = value[i][2] end
- forcedTranslation[key] = temp
- end
- term.setTextColour(colours.black)
- term.setBackgroundColour(colours.yellow)
- for j = 0, 1 do for i = 1, 3 do
- term.setCursorPos(1, i + (j * (ySize - 3)))
- term.clearLine()
- end end
- term.setCursorPos(5, 2)
- term.write("WorldPorter")
- term.setCursorPos(2, ySize - 1)
- --term.write("This system is facing "..({"unknown", "north", "south", "west", "east"})[commands.getBlockInfo(commands.getBlockPosition()).metadata]..".")
- paintutils.drawPixel(1, 1, colours.blue)
- paintutils.drawPixel(2, 1, colours.green)
- paintutils.drawPixel(3, 1, colours.yellow)
- paintutils.drawPixel(1, 2, colours.grey)
- paintutils.drawPixel(2, 2, colours.white)
- paintutils.drawPixel(3, 2, colours.lightBlue)
- paintutils.drawPixel(1, 3, colours.orange)
- paintutils.drawPixel(2, 3, colours.lime)
- paintutils.drawPixel(3, 3, colours.red)
- ---------------------------------------------
- ------------ Main Program Loop ------------
- ---------------------------------------------
- while true do
- local menuInfo = menu[curMenu]
- if curMenu > 1 then menuInfo = menuInfo[subMenu] end
- if curMenu == 3 and subMenu == 1 then
- menu[3][1] = {fileBrowser()}
- if menu[3][1][1] then
- local fileIn = fs.open(menu[3][1][1],"rb")
- for i = 1, 3 do fileIn.read() end
- if fileIn.read() > 0 then error("Requires a later version of WorldPorter; suggest updating with shell commands:\nrm worldporter\npastebin get pXjdQDf6 worldporter") end
- fileIn.close()
- doBuild(menu[3][1][1])
- curMenu, subMenu = 1, 1
- else curMenu = 1 end
- elseif curMenu == 2 and subMenu == 3 then
- if fs.exists(shell.resolve(menu[2][2][3].Filename)) then
- term.setTextColour(labelText)
- term.setBackgroundColour(labelBack)
- term.setCursorPos(11, 9)
- term.write(menuInfo[1])
- subMenu = form(unpack(menuInfo[2]))[1] == "Ok" and 4 or 2
- else subMenu = 4 end
- elseif subMenu == 4 then
- local bounds, func, params = {{},{},{}}
- if curMenu == 2 then
- bounds[1][1] = menu[2][1][3].X1
- bounds[1][2] = menu[2][1][3].X2
- bounds[2][1] = menu[2][1][3].Y1
- bounds[2][2] = menu[2][1][3].Y2
- bounds[3][1] = menu[2][1][3].Z1
- bounds[3][2] = menu[2][1][3].Z2
- table.sort(bounds[1])
- table.sort(bounds[2])
- table.sort(bounds[3])
- func = doScan
- params = {menu[2][2][3].Filename, bounds[1][1], bounds[2][1], bounds[3][1], bounds[1][2] - bounds[1][1] + 1, bounds[2][2] - bounds[2][1] + 1, bounds[3][2] - bounds[3][1] + 1}
- else
- bounds[1][1] = menu[3][2][3].X
- bounds[1][2] = menu[3][2][3].X + (((menu[3][2][3].rotate == 1 or menu[3][2][3].rotate == 3) and menu[3][1][3] or menu[3][1][5]) - 1) * ((menu[3][3][3].horizontalDir == 2 or menu[3][3][3].horizontalDir == 3) and 1 or -1)
- bounds[2][1] = menu[3][2][3].Y
- bounds[2][2] = menu[3][2][3].Y + (menu[3][1][4] - 1) * (menu[3][3][3].verticalDir == 1 and 1 or -1)
- bounds[3][1] = menu[3][2][3].Z
- bounds[3][2] = menu[3][2][3].Z + (((menu[3][2][3].rotate == 1 or menu[3][2][3].rotate == 3) and menu[3][1][5] or menu[3][1][3]) - 1) * (menu[3][3][3].horizontalDir > 2 and 1 or -1)
- table.sort(bounds[1])
- table.sort(bounds[2])
- table.sort(bounds[3])
- func = doBuild
- params = {menu[3][1][1], bounds[1][1] - 1, bounds[2][1] - 1, bounds[3][1] - 1, menu[3][2][3].rotate - 1, menu[3][2][3]["Pre-clear build zone?"]}
- end
- clear(colours.black, colours.lightGrey)
- term.setCursorPos(13, 5)
- term.write("Proceed With These Bounds?")
- for _, value in pairs(menu[4]) do
- term.setTextColour(labelText)
- term.setCursorPos(value[1], value[2])
- term.write(value[3])
- local pos = tostring(bounds[1][value[4]])..","..tostring(bounds[2][value[5]])..","..tostring(bounds[3][value[6]])
- term.setTextColour(colours.grey)
- term.setCursorPos(value[1] - #pos + 22, value[2])
- term.write(pos)
- end
- if form(unpack(menu[2][3][2]))[1] == "Ok" then
- func(unpack(params))
- curMenu, subMenu = 1, 1
- else subMenu = curMenu == 2 and 2 or 3 end
- else
- clear(colours.black, colours.lightGrey)
- term.setCursorPos((xSize - #menuInfo[1]) / 2 + 1, 5)
- term.write(menuInfo[1])
- menuInfo[3] = form(unpack(menuInfo[2]))
- for i = 1, #menuInfo[2] do if menuInfo[2].textbox then menuInfo[2].content = menuInfo[3][menuInfo[2].label.text] end end
- if curMenu == 1 then
- if menuInfo[3][1] == "Scan" then
- curMenu = 2
- elseif menuInfo[3][1] == "Build" then
- curMenu = 3
- elseif menuInfo[3][1] == "Quit" then
- term.setTextColour(colours.white)
- term.setBackgroundColour(colours.black)
- term.clear()
- term.setCursorPos(1, 1)
- print("Thanks for using WorldPorter!\n")
- shell.setDir(startDir)
- error()
- end
- else
- if menuInfo[3][1] == "Ok" then
- if curMenu == 2 and subMenu == 2 and menuInfo[3].Filename:sub(-4):lower() ~= ".blk" then menuInfo[3].Filename = menuInfo[3].Filename .. ".blk" end
- for key, value in pairs(menuInfo[3]) do if type(value) == number then menuInfo[3][key] = math.floor(value) end end
- subMenu = subMenu + 1
- else
- subMenu = subMenu - 1
- if subMenu < 1 or (curMenu == 3 and subMenu < 2) then
- subMenu = 1
- curMenu = 1
- end
- end
- end
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement