Advertisement
aodminecraft

Arc OS - Worldedit - programs/WE_Clipboard

Aug 1st, 2015
17
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 14.66 KB | None | 0 0
  1. --The filesizes will scare me...
  2.  
  3. --Immibis's NBT api for the next 140 lines...
  4.  
  5. local function nbtToTable(typ,val)
  6.   if typ=="compound" then
  7.     local rv={}
  8.     for _,key in ipairs(val.getKeys()) do
  9.       local typ2,val2=val.getValue(key)
  10.       rv[key]=nbtToTable(typ2,val2)
  11.     end
  12.     return {type="compound",value=rv}
  13.   elseif typ=="list" then
  14.     local n=val.getSize()
  15.     local rv={}
  16.     for k=0,n-1 do
  17.       local typ2,val2=val.get(k)
  18.       rv[k+1]=nbtToTable(typ2,val2)
  19.     end
  20.     return {type="list",value=rv}
  21.   elseif typ=="string" or typ=="double" or typ=="float" or typ=="byte" or typ=="short" or typ=="int" or typ=="long" then
  22.     return {type=typ,value=val}
  23.   elseif typ=="intArray" or typ=="byteArray" then
  24.     local rv={}
  25.     for k=0,val.getLength()-1 do
  26.       rv[k+1]=val.get(k)
  27.     end
  28.     return {type=typ,value=rv}
  29.   else
  30.     error("unimplemented tag type: "..typ)
  31.   end
  32. end
  33.      
  34. local function tableToNbt(typ,tag,tbl)
  35.   assert(type(tag)=="table" and tbl.type==typ and tag.getType()==typ)
  36.   if typ=="compound" then
  37.     for _,key in ipairs(tag.getKeys()) do
  38.       if not tbl.value[key] then
  39.         tag.remove(key)
  40.       end
  41.     end
  42.     for key,value in pairs(tbl.value) do
  43.       if value.type=="compound" or value.type=="list" then
  44.         tag.setValue(key,value.type)
  45.         tableToNbt(value.type,select(2,tag.getValue(key)),value)
  46.       elseif value.type=="intArray" or value.type=="byteArray" then
  47.         tag.setValue(key,value.type,#value.value)
  48.         tableToNbt(value.type,select(2,tag.getValue(key)),value)
  49.       elseif value.type=="string" or value.type=="double" or value.type=="float" or value.type=="byte" or value.type=="short" or value.type=="int" then
  50.         tag.setValue(key,value.type,value.value)
  51.       elseif value.type=="long" then
  52.         tag.setValue(key,value.type,value.value[1],value.value[2])
  53.       else
  54.         error("unimplemented tag type: "..value.type)
  55.       end
  56.     end
  57.   elseif typ=="list" then
  58.     while tag.getSize()>0 do
  59.       tag.remove(0)
  60.     end
  61.     for _,value in ipairs(tbl.value) do
  62.       if value.type=="compound" or value.type=="list" then
  63.         tag.add(tag.getSize(),value.type)
  64.         tableToNbt(value.type,select(2,tag.get(tag.getSize()-1)),value)
  65.       elseif value.type=="intArray" or value.type=="byteArray" then
  66.         tag.add(tag.getSize(),value.type,#value.value)
  67.         tableToNbt(value.type,select(2,tag.get(tag.getSize()-1)),value)
  68.       elseif value.type=="string" or value.type=="double" or value.type=="float" or value.type=="byte" or value.type=="short" or value.type=="int" then
  69.         tag.add(tag.getSize(),value.type,value.value)
  70.       elseif value.type=="long" then
  71.         tag.add(tag.getSize(),value.type,value.value[1],value.value[2])
  72.       else
  73.         error("unimplemented tag type: "..value.type)
  74.       end
  75.     end
  76.   elseif typ=="intArray" or typ=="byteArray" then
  77.     for k=0,tag.getLength()-1 do
  78.       tag.set(k,tbl.value[k+1])
  79.     end
  80.   else
  81.     error("unimplemented tag type: "..typ)
  82.   end
  83. end
  84.  
  85. local function readTileNBT(te)
  86.   te.readNBT()
  87.   return nbtToTable("compound",te.getNBT())
  88. end
  89.      
  90. local function writeTileNBT(te,nbt)
  91.   te.readNBT() --This is the only line of code I changed. I added this line and changed the spacing to two spaces instead of four.
  92.   --Without this line, the function does not work as intended.
  93.   tableToNbt("compound",te.getNBT(),nbt)
  94.   te.writeNBT()
  95. end
  96.  
  97. --And here begins my code!
  98.  
  99. local f=fs.open("rom/help/changelog","r")
  100. local str=f.readAll()
  101. f.close()
  102. f=nil
  103. local useNBT=str:find("ComputerCraft 1.64")==nil --or str:find("ComputerCraft 1.XX")~=nil --if it's ever fixed.
  104. clipboard={} --Holds the functions, clipboard.copy, clipboard.paste, etc.
  105. Clipboard=Clipboard or {} --The clipboard which holds the blocks
  106. Clipboard[1]=Clipboard[1] or {}
  107. local directions={"down","up","north","south","east","west","self"}
  108. function clipboard.copy(NoOutput,beingReused) --http://wiki.sk89q.com/wiki/WorldEdit/Clipboard#Copying_and_cutting
  109.   if not NoOutput then
  110.     sendChat("Copying...")
  111.   end
  112.   if not beingReused then
  113.     px,py,pz=getPlayerPos(username)
  114.     px,py,pz=math.floor(px,py,pz)
  115.   end
  116.   Clipboard.ox=px --Original coords of the player at the time of the copying
  117.   Clipboard.oy=py
  118.   Clipboard.oz=pz
  119.   if #Selection>0 then
  120.     for i=1,#Selection do --Go through all of the blocks in the selection...
  121.       if not Clipboard[i] then
  122.         Clipboard[i]={}
  123.       end
  124.       Clipboard[i].x=Selection[i].x --Integers play much nicer.
  125.       Clipboard[i].y=Selection[i].y
  126.       Clipboard[i].z=Selection[i].z
  127.       Clipboard[i].ID=getBlockID(Clipboard[i].x,Clipboard[i].y,Clipboard[i].z)
  128.       Clipboard[i].Meta=getMetadata(Clipboard[i].x,Clipboard[i].y,Clipboard[i].z)
  129.       if useNBT and w.getTileEntity(Clipboard[i].x,Clipboard[i].y,Clipboard[i].z) then --If there is any NBT, store it.
  130.         Clipboard[i].NBT=readTileNBT(w.getTileEntity(Clipboard[i].x,Clipboard[i].y,Clipboard[i].z))
  131.       end
  132.     end
  133.   end
  134.   local ClipboardDir="WE/Clipboard"
  135.   if fs.exists(ClipboardDir) then
  136.     fs.delete(ClipboardDir)
  137.   end
  138.   local f=fs.open(ClipboardDir,"w")
  139.   f.write(textutils.serialize(Clipboard))
  140.   f.close()
  141.   if not NoOutput then
  142.     sendChat("Area copied.")
  143.   end
  144. end
  145.  
  146. --http://wiki.sk89q.com/wiki/WorldEdit/Clipboard#Pasting
  147. function clipboard.paste(beingReused)
  148.   local count=0
  149.   local count2=0
  150.   local iterations=0
  151.   local Num=0
  152.   local flags={none=0,a=1,ao=2,both=3} --a means without pasting air blocks, ao means At Origin, at the origin of the paste (Where it was copied from).
  153.   if not beingReused then
  154.     if #stringx.split(message," ")>2 then
  155.         sendChat("Syntax: paste [-a] [-ao]")
  156.         return false
  157.     end
  158.     if message:gsub("-ao","")==message then
  159.       if message:gsub("-ao",""):gsub("-a","")==message then
  160.         Num=flags.none
  161.       else
  162.         Num=flags.a
  163.       end
  164.       px,py,pz=getPlayerPos(username)
  165.     else
  166.       if message:gsub("-ao",""):gsub("-a","")==message:gsub("-ao","") then
  167.         Num=flags.ao
  168.       else
  169.         Num=flags.both
  170.       end
  171.     end
  172.   else
  173.     Num=flags.none
  174.   end
  175.   if Clipboard and Clipboard[1].x then
  176.     sendChat("Pasting...")
  177.     for i=1,#Clipboard do
  178.       count=count+1
  179.       if count>=25000 then
  180.         count=0
  181.         sleep(0.05)
  182.         count2=count2+1
  183.       elseif count2>=6 then
  184.         count2=0
  185.         sleep(0.05)
  186.       end
  187.       local currentX,currentY,currentZ
  188.       if Num==flags.none then
  189.         currentX,currentY,currentZ=px+Clipboard[i].x-Clipboard.ox,py+Clipboard[i].y-Clipboard.oy,pz+Clipboard[i].z-Clipboard.oz --Coords relative to the player
  190.         if not hasChatBox then
  191.           blockChanged=BlockHasChanged(currentX,currentY,currentZ,Clipboard[i].ID,Clipboard[i].Meta)
  192.           setBlock(currentX,currentY,currentZ,Clipboard[i].ID,Clipboard[i].Meta)
  193.         elseif hasChatBox then
  194.           blockChanged=setBlock(currentX,currentY,currentZ,Clipboard[i].ID,Clipboard[i].Meta)
  195.         end
  196.         iterations=iterations+((blockChanged and 1) or 0)
  197.       elseif Num==flags.a then
  198.         if Clipboard[i].ID~=0 then --If the block in the clipboard isn't air...
  199.           currentX,currentY,currentZ=px+Clipboard[i].x-Clipboard.ox,py+Clipboard[i].y-Clipboard.oy,pz+Clipboard[i].z-Clipboard.oz --Coords relative to the player
  200.           if not hasChatBox then
  201.             blockChanged=BlockHasChanged(currentX,currentY,currentZ,Clipboard[i].ID,Clipboard[i].Meta)
  202.             setBlock(currentX,currentY,currentZ,Clipboard[i].ID,Clipboard[i].Meta)
  203.           elseif hasChatBox then
  204.             blockChanged=setBlock(currentX,currentY,currentZ,Clipboard[i].ID,Clipboard[i].Meta)
  205.           end
  206.           iterations=iterations+((blockChanged and 1) or 0)
  207.         end
  208.       elseif Num==flags.ao then
  209.         currentX,currentY,currentZ=(Clipboard[i].x-Clipboard.ox)+Clipboard.ox,(Clipboard[i].y-Clipboard.oy)+Clipboard.oy,(Clipboard[i].z-Clipboard.oz)+Clipboard.oz --Original coords from the clipboard
  210.         if not hasChatBox then
  211.           blockChanged=BlockHasChanged(currentX,currentY,currentZ,Clipboard[i].ID,Clipboard[i].Meta)
  212.           setBlock(currentX,currentY,currentZ,Clipboard[i].ID,Clipboard[i].Meta)
  213.         elseif hasChatBox then
  214.           blockChanged=setBlock(currentX,currentY,currentZ,Clipboard[i].ID,Clipboard[i].Meta)
  215.         end
  216.         iterations=iterations+((blockChanged and 1) or 0)
  217.       elseif Num==flags.both then
  218.         if Clipboard[i].ID~=0 then --If the block in the clipboard isn't air...
  219.           currentX,currentY,currentZ=(Clipboard[i].x-Clipboard.ox)+Clipboard.ox,(Clipboard[i].y-Clipboard.oy)+Clipboard.oy,(Clipboard[i].z-Clipboard.oz)+Clipboard.oz --Original coords from the clipboard
  220.           if not hasChatBox then
  221.             blockChanged=BlockHasChanged(currentX,currentY,currentZ,Clipboard[i].ID,Clipboard[i].Meta)
  222.             setBlock(currentX,currentY,currentZ,Clipboard[i].ID,Clipboard[i].Meta)
  223.           elseif hasChatBox then
  224.             blockChanged=setBlock(currentX,currentY,currentZ,Clipboard[i].ID,Clipboard[i].Meta)
  225.           end
  226.           iterations=iterations+((blockChanged and 1) or 0)
  227.         end
  228.       end
  229.       if useNBT and Clipboard[i].NBT then --If the block in the clipboard has NBT data and NBT support works
  230.         for k,v in pairs(Clipboard[i]) do
  231.           if k=="NBT" then
  232.             v.value.x.value,v.value.y.value,v.value.z.value=math.floor(currentX,currentY,currentZ) --Change the coords in the NBT data to the new coordinates
  233.           end
  234.         end
  235.         writeTileNBT(w.getTileEntity(currentX,currentY,currentZ),Clipboard[i].NBT) --Write the NBT to the block it's supposed to be on.
  236.       end
  237.     end
  238.   else
  239.     sendChat("Copy something first!")
  240.     return false
  241.   end
  242.   sendChat(iterations.." blocks changed in "..getSleepTime(count,count2).." seconds.")
  243.   return true
  244. end
  245.  
  246. --http://wiki.sk89q.com/wiki/WorldEdit/Features#History
  247.  
  248. function clipboard.cut(NoOutput) --http://wiki.sk89q.com/wiki/WorldEdit/Clipboard#Copying_and_cutting
  249.   clipboard.copy(false,true) --Reusing functions makes this much easier. Set it so it won't say "Area Copied", but will say everything else.
  250.   Blocks2={0}
  251.   Meta2={0} --Make sure it's ONLY setting air, and nothing else.
  252.   Percentages={100}
  253.   TotalPercent=0 --Tell it there are no percentages.
  254.   sel.set(true)
  255.   if not NoOutput then
  256.     sendChat("Area Cut.")
  257.   end
  258. end
  259.  
  260. function clipboard.move() --http://wiki.sk89q.com/wiki/WorldEdit/Region_operations#Moving
  261.   local args=message:sub(5)
  262.   sendChat("Don't move.")
  263.   px,py,pz=getPlayerPos(username)
  264.   for i=1,#directions do
  265.     if args:gsub(directions[i],"")~=args then
  266.         Direction=directions[i]
  267.         args=args:gsub(directions[i],"")
  268.         break
  269.     end
  270.   end
  271.   if not Direction or Direction=="" or Direction=="self" then
  272.     Direction=getDirection(true)
  273.     if not Direction then return end
  274.   end
  275.   local tmpClipboard={}
  276.   if Direction then
  277.     local tx,ty,tz=px,py,pz --temporary storage for the player location
  278.     tmpClipboard=table.copy(Clipboard)
  279.     clipboard.cut(true) --Reusing functions makes this much easier. Set it so it won't say "Area Cut", but will say everything else.
  280.     if Direction=="east" then
  281.       px=px+tonumber(args)
  282.     elseif Direction=="west" then
  283.       px=px-tonumber(args)
  284.     elseif Direction=="north" then
  285.       pz=pz-tonumber(args)
  286.     elseif Direction=="south" then
  287.       pz=pz+tonumber(args)
  288.     elseif Direction=="up" then
  289.       py=py+tonumber(args)
  290.     elseif Direction=="down" then
  291.       py=py-tonumber(args)
  292.     else
  293.       error("I screwed up the direction function. Tell me how you made this bug happen on the forum thread!")
  294.     end
  295.   end
  296.   clipboard.paste(true)
  297.   Clipboard=tmpClipboard
  298.   tmpClipboard=nil
  299.   px,py,pz=tx,ty,tz
  300.   tx,ty,tz=nil,nil,nil
  301.   Direction=nil
  302.   sendChat("Selection moved.")
  303. end
  304.  
  305.  
  306. function clipboard.stack() --http://wiki.sk89q.com/wiki/WorldEdit/Region_operations#Stacking
  307.   local tmpClipboard={}
  308.   sendChat("Don't move.")
  309.   tmpClipboard=table.copy(Clipboard)
  310.   px,py,pz=getPlayerPos(username)
  311.   clipboard.copy(false,true)
  312.   local args=message:sub(6)
  313.   for i=1,#directions do
  314.     if args:gsub(directions[i],"")~=args then
  315.         Direction=directions[i]
  316.         args=args:gsub(directions[i],"")
  317.         break
  318.     end
  319.   end
  320.   if not Direction or Direction=="" or Direction=="self" then
  321.     Direction=getDirection(true)
  322.     if not Direction then return end
  323.   end
  324.   if Direction then
  325.     local tx,ty,tz=px,py,pz --temporary storage for the player location
  326.     for i=1,tonumber(args) do
  327.       if Direction=="east" then
  328.         px=px+(math.max(x1,x2)-math.min(x1,x2)+1) --The equation gets the size of the selection in that dimension then moves the area operated upon accordingly (since it uses the player's position, that is edited, but the original is restored after the command finishes)
  329.       elseif Direction=="west" then
  330.         px=px-(math.max(x1,x2)-math.min(x1,x2)+1)
  331.       elseif Direction=="north" then
  332.         pz=pz-(math.max(z1,z2)-math.min(z1,z2)+1)
  333.       elseif Direction=="south" then
  334.         pz=pz+(math.max(z1,z2)-math.min(z1,z2)+1)
  335.       elseif Direction=="up" then
  336.         py=py+(math.max(y1,y2)-math.min(y1,y2)+1)
  337.       elseif Direction=="down" then
  338.         py=py-(math.max(y1,y2)-math.min(y1,y2)+1)
  339.       else
  340.         error("I screwed up the direction function. Tell me how you made this bug happen on the forum thread!")
  341.       end
  342.       clipboard.paste(true)
  343.     end
  344.   end
  345.   Clipboard=tmpClipboard
  346.   tmpClipboard=nil
  347.   Direction=nil
  348.   px,py,pz=tx,ty,tz
  349.   sendChat("Selection stacked.")
  350. end
  351.  
  352. function clipboard.save()
  353.   Name=OriginalMessage:sub(6):gsub(" ","_")
  354.   local allowOverwriting=false
  355.   if Name:gsub("-o","")~=Name then
  356.     allowOverwriting=true
  357.   end
  358.   if Clipboard and #Clipboard>0 then
  359.     if not fs.exists("WE/Schematics/"..Name) or allowOverwriting then
  360.       local f=fs.open("WE/Schematics/"..Name,"w")
  361.       f.write(textutils.serialize(Clipboard))
  362.       f.close()
  363.     else
  364.       sendChat("That name is already used. Run with the -o flag to allow overwriting.")
  365.       return false
  366.     end
  367.   else
  368.     sendChat("You need to have something in your clipboard first!")
  369.     return false
  370.   end
  371.   sendChat("Build Saved.")
  372.   return true
  373. end
  374.  
  375. function clipboard.load()
  376.   local dir=message:sub(6)
  377.   local default=false
  378.   if dir==nil or dir=="" then
  379.     dir="WE/Clipboard"
  380.     default=true
  381.   end
  382.   if (fs.exists(dir) and default) or fs.exists("WE/Schematics/"..dir) then
  383.     local f
  384.     if not default then
  385.       f=fs.open("WE/Schematics/"..dir,"r")
  386.     else
  387.       f=fs.open(dir,"r")
  388.     end
  389.     Clipboard=textutils.unserialize(f.readAll())
  390.     f.close()
  391.     sendChat("Clipboard loaded.")
  392.     return true
  393.   else
  394.     sendChat("That clipboard does not exist!")
  395.     return false
  396.   end
  397. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement