--
-- CuboidPlus Plugin by Omencraft Plugin Team (Luthrandel, Kwen)
-- Original Cuboid Plugin by BenPhelps
-- for MCServer r181+
--

local CuboidPlusPlugin = {}

CuboidPlusPlugin.__index = CuboidPlusPlugin

--defines the max copy size
copyLimit = 200000

--The default range of brushes
defaultBRange = 100

-- tables to hold player points, lets more than one player use the plugin at a time
pointCset = {}
points = {}
userBlock = {}
userCopy = {}
colors = {}
metas = {}
superaxe = {}
colorOn = {}
cuboidOn = {}
userBrush = {}
paintOn = {}
cuboidHistory = {}
cuboidRedo = {}
cuboidSave = {}

-- colors in the proper order
-- roy g biv
colors[1] = 14 -- red
colors[2] = 1 -- orange
colors[3] = 4 -- yellow
colors[4] = 5 -- lime
colors[5] = 13 -- green
colors[6] = 9 -- cyan
colors[7] = 3 -- light blue
colors[8] = 11 -- blue
colors[9] = 10 -- purple
colors[10] = 2 -- magenta
colors[11] = 6 -- pink
colors[12] = 0 -- white
colors[13] = 8 -- light grey
colors[14] = 7 -- grey
colors[15] = 15 -- black
colors[16] = 12 -- brown

metas[14] = 1 -- red
metas[1] = 2 -- orange
metas[4] = 3 -- yellow
metas[5] = 4 -- lime
metas[13] = 5 -- green
metas[9] = 6 -- cyan
metas[3] = 7 -- light blue
metas[11] = 8 -- blue
metas[10] = 9 -- purple
metas[2] = 10 -- magenta
metas[6] = 11 -- pink
metas[0] = 12 -- white
metas[8] = 13 -- light grey
metas[7] = 14 -- grey
metas[15] = 15 -- black
metas[12] = 16 -- brown

--Preferences
prefDS = false
prefCuboid = false

--Math Library
local mFloor = math.floor
local mSqrt = math.sqrt
local mPow = math.pow
local mMax = math.max
local mMin = math.min
local mAbs = math.abs
local mRandom = math.random

--Everything else
function CuboidPlusPlugin:new()
	local t = {}
	setmetatable(t, CuboidPlusPlugin)
	local w = Lua__cPlugin:new()
	tolua.setpeer(w, t)
	w:tolua__set_instance(w)
	return w
end

function OnDisable()
	Log( Plugin:GetName() .. " v." .. Plugin:GetVersion() .. " is shutting down..." )
end

function Initialize()
	Plugin:SetName( "Cuboid" )
	Plugin:SetVersion( 3 )

	PluginManager = cRoot:Get():GetPluginManager()
	PluginManager:AddHook( Plugin, cPluginManager.E_PLUGIN_CHAT )
	PluginManager:AddHook( Plugin, cPluginManager.E_PLUGIN_PLAYER_JOIN )
	PluginManager:AddHook( Plugin, cPluginManager.E_PLUGIN_BLOCK_PLACE )
	PluginManager:AddHook( Plugin, cPluginManager.E_PLUGIN_BLOCK_DIG )
	
	local cuboidplusINI = cIniFile("cuboid.ini")
	if ( cuboidplusINI:ReadFile() == true ) then
		prefDS = cuboidplusINI:GetValueB( "Settings" , "DoubleSlash", false)
		prefCuboid = cuboidplusINI:GetValueB( "Settings" , "CuboidEnable", true)
	end
	local dS = ''
	if prefDS==true then dS='/' end
	
	Plugin:AddCommand(dS .. "/cuboid", 		" Allows the player to select, required for most other commands.",	"cuboid.cuboid")
	Plugin:AddCommand(dS .. "/undo", 		" Undoes the last action of the player.",								"cuboid.undo")
	Plugin:AddCommand(dS .. "/redo", 		" Reapplies the last undo of the player.",								"cuboid.redo")
	Plugin:AddCommand(dS .. "/color", 		" Allows the player to use the cloth color tool.",					"cuboid.color")
	Plugin:AddCommand(dS .. "/compass", 	" - Gives the current facing direction.", 								"cuboid.compass")
	Plugin:AddCommand(dS .. "/superaxe", 	" - One tick block destroy when using an axe.", 						"cuboid.superaxe")
	Plugin:AddCommand(dS .. "/fill", 		" [BlockID] - Fills the selected cuboid with the supplied block ID.",	"cuboid.fill")
	Plugin:AddCommand(dS .. "/hfill", 		" [BlockID] - Fills the selected cuboid with a hollow rect of the supplied block ID.",	"cuboid.hfill")
	Plugin:AddCommand(dS .. "/overlay", 	" [BlockID] - Overlays every block in the selected cuboid with the supplied block ID.",	"cuboid.overlay")
	Plugin:AddCommand(dS .. "/replace",   	" [ReplaceID] [BlockID] - Replace the block in selected cuboid with the supplied block ID.",	"cuboid.replace")
	Plugin:AddCommand(dS .. "/del", 		" - Removes all blocks in the selected cuboid.", 						"cuboid.delete")
	Plugin:AddCommand(dS .. "/tree", 		" - Generate a tree.", 													"cuboid.tree")
	Plugin:AddCommand(dS .. "/forest", 		" [radius] [density] - Generate a forest.", 						"cuboid.forest")
	Plugin:AddCommand(dS .. "/circle", 		" [radius] [block] - builds a circle.", 							"cuboid.circle")
	Plugin:AddCommand(dS .. "/disk", 		" [radius] [block] - builds a filled circle.", 							"cuboid.disk")
	Plugin:AddCommand(dS .. "/cylinder",	" [radius] [height] [block] - builds a cylinder.", 						"cuboid.cylinder")
	Plugin:AddCommand(dS .. "/square",		" [size] [block] - builds a square.", 								"cuboid.square")
	Plugin:AddCommand(dS .. "/pyramid", 	" [size] [block] - builds a pyramid.", 									"cuboid.pyramid")
	Plugin:AddCommand(dS .. "/sphere",  	" [radius] [block] [filled] - builds a sphere.", 						"cuboid.sphere")
	Plugin:AddCommand(dS .. "/size",  	  	" Returns the size of the selection.", 						"cuboid.size")
	Plugin:AddCommand(dS .. "/wand",  		" Gives the player the wand tool.", 								"cuboid.wand")
	Plugin:AddCommand(dS .. "/save",  		" Save a selected cuboid to file.", 								"cuboid.save")
	Plugin:AddCommand(dS .. "/load",  		" Load a selected cuboid from file.", 								"cuboid.load")
	Plugin:AddCommand(dS .. "/pos1",  		" Sets the first select position to the players position.", 		"cuboid.pos1")
	Plugin:AddCommand(dS .. "/pos2",  		" Sets the second select position to the players position.", 		"cuboid.pos2")
	Plugin:AddCommand(dS .. "/ceil",  		" Sets the cuboid height to the max height. Favors pos1", 			"cuboid.ceil")
	Plugin:AddCommand(dS .. "/floor",  		" Sets the cuboid bottom to the minimum height. Favors pos2", 		"cuboid.floor")
	Plugin:AddCommand(dS .. "/copy",  		" Copy selected blocks to the clipboard relative to player position.", 			"cuboid.copy")
	Plugin:AddCommand(dS .. "/copyc",  		" Centers the relative position of the copy.", 			"cuboid.copycenter")
	Plugin:AddCommand(dS .. "/copyt",  		" Sets the relative position of the copy to the top.", 			"cuboid.copytop")
	Plugin:AddCommand(dS .. "/copyb",  		" Sets the relative position of the copy to the bottom.", 			"cuboid.copybottom")
	Plugin:AddCommand(dS .. "/paste",  		" Pastes blocks from the cipboard relative to player position.", 			"cuboid.paste")
	Plugin:AddCommand(dS .. "/pasteb",  	" Pastes blocks from the cipboard relative to player position ignoring air.", 			"cuboid.pasteb")
	Plugin:AddCommand(dS .. "/cbclean",  	" Removes liquids from the clipboard.", 			"cuboid.cbclean")
	Plugin:AddCommand(dS .. "/mirrorx",  	" Mirrors the cliboards X axis.", 			"cuboid.mirrorx")
	Plugin:AddCommand(dS .. "/mirrory",  	" Mirrors the clipboards Y axis.", 			"cuboid.mirrory")
	Plugin:AddCommand(dS .. "/mirrorz",  	" Mirrors the clipboards Z axis.", 			"cuboid.mirrorz")
	Plugin:AddCommand(dS .. "/rotate",  	" Rotate the clipboard in 90 degree increments.", 			"cuboid.rotate")
	Plugin:AddCommand(dS .. "/stack",		" Duplicates the selection relative to player direction.",	"cuboid.stack")
	Plugin:AddCommand(dS .. "/outset",	" Enlarge the cuboid in all directions.",	"cuboid.outset")
	Plugin:AddCommand(dS .. "/inset",	    " Contract the cuboid in all directions.",	"cuboid.inset")
	Plugin:AddCommand(dS .. "/expand",	" Enlarge the cuboid relative to the players direction.",	"cuboid.expand")
	Plugin:AddCommand(dS .. "/contract",	" Shrink the cuboid relative to the players direction.",	"cuboid.contract")
	Plugin:AddCommand(dS .. "/shift",	    " Moves the cuboid relative to player direction.",	"cuboid.shift")
	Plugin:AddCommand(dS .. "/brush",	    " Select a brush for world painting",	"cuboid.brush")
	Plugin:AddCommand(dS .. "/line",	    " Draws a line between pos1 and pos2.",	"cuboid.line")
	
	Plugin:BindCommand(dS .. "/cuboid",		"cuboid.cuboid",		HandleCuboid)
	Plugin:BindCommand(dS .. "/c",		    "cuboid.cuboid",		HandleCuboid)
	Plugin:BindCommand(dS .. "/undo",		 "cuboid.undo",			HandleUndo)
	Plugin:BindCommand(dS .. "/redo",		 "cuboid.redo",			HandleRedo)
	Plugin:BindCommand(dS .. "/color",		"cuboid.color",			HandleColor)
	Plugin:BindCommand(dS .. "/compass",	"cuboid.compass",		HandleCompass)
	Plugin:BindCommand(dS .. "/superaxe",	"cuboid.superaxe",		HandleSuperaxe)
	Plugin:BindCommand(dS .. "/fill", 		"cuboid.fill", 			HandleFill)
	Plugin:BindCommand(dS .. "/hfill", 		"cuboid.hfill", 		HandleHollowFill)
	Plugin:BindCommand(dS .. "/overlay", 	"cuboid.overlay", 		HandleOverlay)
	Plugin:BindCommand(dS .. "/over", 		"cuboid.over", 			HandleOverlay)
	Plugin:BindCommand(dS .. "/replace", 	"cuboid.replace", 		HandleReplace)
	Plugin:BindCommand(dS .. "/set", 		 "cuboid.fill", 		HandleFill)
	Plugin:BindCommand(dS .. "/z", 		    "cuboid.fill", 			HandleFill)
	Plugin:BindCommand(dS .. "/delete", 	"cuboid.delete", 		HandleDelete)
	Plugin:BindCommand(dS .. "/del", 		 "cuboid.delete", 		HandleDelete)
	Plugin:BindCommand(dS .. "/tree", 		"cuboid.tree", 			HandleTree)
	Plugin:BindCommand(dS .. "/forest", 	"cuboid.forest", 		HandleForest)
	Plugin:BindCommand(dS .. "/circle", 	"cuboid.circle", 		HandleCircle)
	Plugin:BindCommand(dS .. "/disk", 		"cuboid.disk", 			HandleDisk)
	Plugin:BindCommand(dS .. "/cylinder", 	"cuboid.cylinder",		HandleCylinder)
	Plugin:BindCommand(dS .. "/square", 	"cuboid.square",		HandleSquare)
	Plugin:BindCommand(dS .. "/pyramid", 	"cuboid.pyramid",		HandlePyramid)
	Plugin:BindCommand(dS .. "/sphere", 	"cuboid.sphere",		HandleSphere)
	Plugin:BindCommand(dS .. "/size", 	  	"cuboid.size",			HandleSize)
	Plugin:BindCommand(dS .. "/wand",		 "cuboid.wand",			HandleWand)
	Plugin:BindCommand(dS .. "/save",		  "cuboid.save",		HandleSave)
	Plugin:BindCommand(dS .. "/load",		  "cuboid.load",		HandleLoad)
	Plugin:BindCommand(dS .. "/pos1",		  "cuboid.pos1",		HandlePosOne)
	Plugin:BindCommand(dS .. "/pos2",		  "cuboid.pos2",		HandlePosTwo)
	Plugin:BindCommand(dS .. "/place",		"cuboid.place",			HandlePlace)
	Plugin:BindCommand(dS .. "/bget",		  "cuboid.bget",		HandleBlockGet)
	Plugin:BindCommand(dS .. "/ceil",		  "cuboid.ceil",		HandleCeil)
	Plugin:BindCommand(dS .. "/floor",		"cuboid.floor",			HandleFloor)
	Plugin:BindCommand(dS .. "/copy",		"cuboid.copy",			HandleCopy)
	Plugin:BindCommand(dS .. "/copycenter",	"cuboid.copycenter",	HandleCopyCenter)
	Plugin:BindCommand(dS .. "/copyc",		"cuboid.copycenter",	HandleCopyCenter)
	Plugin:BindCommand(dS .. "/cc",		    "cuboid.copycenter",	HandleCopyCenter)
	Plugin:BindCommand(dS .. "/copyt",		"cuboid.copytop",		HandleCopyTop)
	Plugin:BindCommand(dS .. "/ct",		    "cuboid.copytop",		HandleCopyTop)
	Plugin:BindCommand(dS .. "/copyb",		"cuboid.copybottom",	HandleCopyBottom)
	Plugin:BindCommand(dS .. "/cb",		    "cuboid.copybottom",	HandleCopyBottom)
	Plugin:BindCommand(dS .. "/paste",		"cuboid.paste",			HandlePaste)
	Plugin:BindCommand(dS .. "/pasteb",		"cuboid.pasteb",		HandlePasteB)
	Plugin:BindCommand(dS .. "/cbclean",	"cuboid.cbclean",		HandleCBClean)
	Plugin:BindCommand(dS .. "/cbc",	    "cuboid.cbclean",		HandleCBClean)
	Plugin:BindCommand(dS .. "/mirrorx",	"cuboid.mirrorx",		HandleMirrorX)
	Plugin:BindCommand(dS .. "/mirrory",	"cuboid.mirrory",		HandleMirrorY)
	Plugin:BindCommand(dS .. "/mirrorz",	"cuboid.mirrorz",		HandleMirrorZ)
	Plugin:BindCommand(dS .. "/rotate",	   "cuboid.rotate",		HandleRotate)
	Plugin:BindCommand(dS .. "/stack",	   "cuboid.stack",		HandleStack)
	Plugin:BindCommand(dS .. "/outset",	   "cuboid.outset",		HandleOutset)
	Plugin:BindCommand(dS .. "/inset",	   "cuboid.inset",		HandleInset)
	Plugin:BindCommand(dS .. "/expand",	   "cuboid.expand",		HandleExpand)
	Plugin:BindCommand(dS .. "/contract",	 "cuboid.contract",	HandleContract)
	Plugin:BindCommand(dS .. "/shift",	   "cuboid.shift",		HandleShift)
	Plugin:BindCommand(dS .. "/brush",	   "cuboid.brush",		HandleBrush)
	Plugin:BindCommand(dS .. "/b",	       "cuboid.brush",		HandleBrush)
	Plugin:BindCommand(dS .. "/paint",	   "cuboid.paint",		HandlePaint)
	Plugin:BindCommand(dS .. "/line",	   "cuboid.line",		HandleLine)

	itemsINI = cIniFile("items.ini")
	if ( itemsINI:ReadFile() == true ) then
		Log("Core: loaded "  .. itemsINI:GetNumValues('Items') .. " item names.")
		HAVE_ITEM_NAMES = true
	end

	local World = cRoot:Get():GetWorld()
	-- local PlayerList = World:GetAllPlayers()
	
	--if #PlayerList > 0 then
	--	for i, TempPlayer in ipairs( PlayerList ) do
	--		HandlePlayerJoin(TempPlayer:GetName())
	--	end
	--end

	Log( "Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion() )
	
	return true
end

function HandlePlayerJoin( Name )
	if points[Name] == nil then
		points[Name] = {}
		points[Name]["enabled"] = false
		points[Name]["1"] = {}
		points[Name]["2"] = {}
 		points[Name]["1"]["x"] = 0
		points[Name]["1"]["y"] = -1
		points[Name]["1"]["z"] = 0
		points[Name]["2"]["x"] = 0
		points[Name]["2"]["y"] = -1
		points[Name]["2"]["z"] = 0
		points[Name]["block"] = 0
	end
	
	if superaxe[Name] == nil then
		superaxe[Name] = false
	end
	
	if colorOn[Name] == nil then
		colorOn[Name] = false
	end
	
	if cuboidOn[Name] == nil then
		cuboidOn[Name] = prefCuboid
	end
	
	if pointCset[Name] == nil then
		pointCset[Name] = 0
	end
	
	if paintOn[Name] == nil then
		paintOn[Name] = false
	end
	
	if userBrush[Name] == nil then
	  userBrush[Name] = nil
	end
	
	cuboidHistory[Name] = {}
	cuboidSave[Name] = {}
	
end

function HandlePaint( Split, Player )
	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	
	if paintOn[Name] == false then
		paintOn[Name] = true
		Server:SendMessage( cChatColor.Green .. "Paint Enabled!", Player)
	elseif paintOn[Name] == true then
		paintOn[Name] = false
		Server:SendMessage( cChatColor.Green .. "Paint Disabled!", Player)
	end
	return true
end

function HandleCuboid( Split, Player )
	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	if cuboidOn[Name] == false then
		cuboidOn[Name] = true
		Server:SendMessage( cChatColor.Green .. "Cuboid Enabled!", Player)
	elseif cuboidOn[Name] == true then
		cuboidOn[Name] = false
		Server:SendMessage( cChatColor.Green .. "Cuboid Disabled!", Player)
	end
	--Handle Basic Brush Setup
  if userBrush[Name] == nil then 
    userBrush[Name] = {}
    userBrush[Name]["Range"] = defaultBRange
    userBrush[Name]["Priority"] = false
    userBrush[Name]["bLock"] = false
    userBrush[Name]["sLock"] = false
  end
	
	return true
end

function HandleColor( Split, Player )
	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	if colorOn[Name] == false then
		colorOn[Name] = true
		Server:SendMessage( cChatColor.Green .. "Color Enabled!", Player)
	elseif colorOn[Name] == true then
		colorOn[Name] = false
		Server:SendMessage( cChatColor.Green .. "Cuboid Disabled!", Player)
	end
	return true
end

function IncrementUndoGroup ( Name )
  undoLimit = 10
  
  local World = cRoot:Get():GetWorld()
  local Server = cRoot:Get():GetServer()
  
  if cuboidHistory[Name] == nil then
		cuboidHistory[Name] = {}
		cuboidHistory[Name][0] = {}
	elseif #cuboidHistory[Name] >= undoLimit then
	   if cuboidHistory[Name][#cuboidHistory[Name]-undoLimit] ~= nil then
	     --Clean up the undos on the bottom of the stack
	     table.remove(cuboidHistory[Name], 1)
	   end
   end
   cuboidHistory[Name][#cuboidHistory[Name]+1] = {}
   
   --Server:SendMessage( cChatColor.Red .. "Cuboid Commands Logged: " .. #cuboidHistory[Name]-1, Player )
  return true
end

function HandleWand( Split, Player )
	Player:GetInventory():AddItem( cItem( 280, 1 ) )
	return true
end

function HandleLoad( Split, Player )
	
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	if #Split ~= 2 then
		Player:SendMessage(cChatColor.Red .. 'Must supply the coubiod name.')
		return true
	end
	
	file = io.open("Plugins/Cuboid/".. Name .."_".. Split[2] ..".cube", "r")
	
	if file == nil then
		Player:SendMessage(cChatColor.Red .. 'No cuboid by that name.')
		return true
	end
	
	local total = 0
	while true do
		local line = file:read("*line")
		if line == nil then break end
		x, y, z, block, meta = split(line)
		World:FastSetBlock(x, y, z, block, meta)
		total = total + 1
	end
	
	Player:SendMessage(cChatColor.Green .. 'Load Complete: ' .. cChatColor.White .. total .. cChatColor.Green .. ' blocks restored.' )
	
	return true
	
end

function split(text, start)
  local s,e,word = string.find(text, "(%S+)", start or 1)
  if s then return word, split(text, e+1); end
end

function HandleSave( Split, Player )
	
	local World = cRoot:Get():GetWorld()
	local Name  = Player:GetName()
	
	if #Split ~= 2 then
		Player:SendMessage(cChatColor.Red .. 'Must supply a name for the cuboid.')
		return true
	end
	
	local min   = getMinimum(points[Name])
	local max   = getMaximum(points[Name])
	local total = (max["x"]-min["x"]+1)*(max["y"]-min["y"]+1)*(max["z"]-min["z"]+1)
	
	if total > 200000 then
		Player:SendMessage(cChatColor.Red .. 'Selection is too large (+200k).')
		return true
	end

	Log('Cuboid: Saving selection to file.')
	file = io.open("Plugins/Cuboid/".. Name .."_".. Split[2] ..".cube", "w")
	
	if file == nil then
		Player:SendMessage(cChatColor.Red .. 'Could not open file to save.')
		return true
	end
	
	x = min["x"]
	while x <= max["x"] do
		y = min["y"]
		while y <= max["y"] do
			z = min["z"]
			while z <= max["z"] do
				file:write(""..x.." "..y.." "..z.." "..World:GetBlock(x, y, z).." ".. World:GetBlockMeta(x, y, z) .."\n")
				z = z + 1
			end
			y = y + 1
		end
		x = x + 1
	end
	
	file:close()

	Log('Cuboid: Finished saving selection!')
	Player:SendMessage(cChatColor.Green .. 'Save Complete: ' .. cChatColor.White .. total .. cChatColor.Green .. ' blocks saved.' )
	
	return true
end

function HandleCopy( Split, Player )
	
	local World = cRoot:Get():GetWorld()
	local Name  = Player:GetName()
	
	if pointCset[Name] ~= 3 then
		Server:SendMessage( cChatColor.Red .. "Must select a cuboid first!", Player )
		return true
	end
	if userCopy[Name] == nil then userCopy[Name] = {} end
	if userCopy[Name]["data"] == nil then userCopy[Name]["data"] = {} end
	
	local min   = getMinimum(points[Name])
	local max   = getMaximum(points[Name])
	local total = (max["x"]-min["x"]+1)*(max["y"]-min["y"]+1)*(max["z"]-min["z"]+1)
	
	if total > copyLimit then
		Player:SendMessage(cChatColor.Red .. 'Selection is too large (+' ..copyLimit.. ').')
		return true
	end

  userCopy[Name] = {}
  userCopy[Name]["data"] = {}
	Log('Cuboid: Copying ' .. total .. ' blocks into memory.')
	
	x = min["x"]
	while x <= max["x"] do
	 ax = 1+x-min["x"]
	 userCopy[Name]["data"][ax] = {}
		
    y = min["y"]
		while y <= max["y"] do
			ay = 1+y-min["y"]
			userCopy[Name]["data"][ax][ay] = {}
			
      z = min["z"]
			while z <= max["z"] do
			  az = 1+z-min["z"]
			  
        userCopy[Name]["data"][ax][ay][az] = {}
			  userCopy[Name]["data"][ax][ay][az]["b"] = World:GetBlock(x, y, z)
			  userCopy[Name]["data"][ax][ay][az]["m"] = World:GetBlockMeta(x, y, z)
				z = z + 1
			end
			y = y + 1
		end
		x = x + 1
	end
	
	userCopy[Name]["xOff"] = min["x"] - mFloor(Player:GetPosX())
	userCopy[Name]["yOff"] = min["y"] - mFloor(Player:GetPosY())
	userCopy[Name]["zOff"] = min["z"] - mFloor(Player:GetPosZ())

	Player:SendMessage(cChatColor.Green .. 'Copied: ' .. cChatColor.White .. total .. cChatColor.Green .. ' blocks into memory.' )
	
	return true
end

function HandleCopyCenter( Split, Player )
	
	local World = cRoot:Get():GetWorld()
	local Name  = Player:GetName()
	
	if userCopy[Name] == nil or userCopy[Name]["data"] == nil then
		Player:SendMessage(cChatColor.Red .. 'No blocks in clipboard.')
		return true
	end
	
	local max   = {}
	 max["x"] = #userCopy[Name]["data"]
	 max["y"] = #userCopy[Name]["data"][max["x"]]
	 max["z"] = #userCopy[Name]["data"][max["x"]][max["y"]]
	 
	 userCopy[Name]["xOff"] = -mFloor(max["x"]/2)
	 userCopy[Name]["zOff"] = -mFloor(max["z"]/2)
	 
	 Player:SendMessage(cChatColor.Green .. 'Clipboard centered on X/Z axis.' )
	 return true
end

function HandleCopyTop( Split, Player )
	
	local World = cRoot:Get():GetWorld()
	local Name  = Player:GetName()
	
	if userCopy[Name] == nil or userCopy[Name]["data"] == nil then
		Player:SendMessage(cChatColor.Red .. 'No blocks in clipboard.')
		return true
	end
	
	local max   = {}
	max["x"] = #userCopy[Name]["data"]
	max["y"] = #userCopy[Name]["data"][max["x"]]
	max["z"] = #userCopy[Name]["data"][max["x"]][max["y"]]
	 
	userCopy[Name]["yOff"] = -max["y"]
	Player:SendMessage(cChatColor.Green .. 'Clipboard Y set to ' .. userCopy[Name]["yOff"] .. '.' )
	return true
end

function HandleCopyBottom( Split, Player )
	
	local World = cRoot:Get():GetWorld()
	local Name  = Player:GetName()
	
	if userCopy[Name] == nil or userCopy[Name]["data"] == nil then
		Player:SendMessage(cChatColor.Red .. 'No blocks in clipboard.')
		return true
	end

	userCopy[Name]["yOff"] = 0
	Player:SendMessage(cChatColor.Green .. 'Clipboard Y set to ' .. userCopy[Name]["yOff"] .. '.' )
	return true
end

function HandlePaste( Split, Player)
	
	local World = cRoot:Get():GetWorld()
	local Name  = Player:GetName()
	
	if userCopy[Name] == nil or userCopy[Name]["data"] == nil then
		Player:SendMessage(cChatColor.Red .. 'No blocks in clipboard.')
		return true
	end
	
	local min   = {}
	 min["x"] = 1
	 min["y"] = 1
	 min["z"] = 1
	local max   = {}
	 max["x"] = #userCopy[Name]["data"]
	 max["y"] = #userCopy[Name]["data"][max["x"]]
	 max["z"] = #userCopy[Name]["data"][max["x"]][max["y"]]
	local total = (max["x"]-min["x"]+1)*(max["y"]-min["y"]+1)*(max["z"]-min["z"]+1)

	Log('Cuboid: Pasting ' .. total .. ' blocks.')
	local pX = mFloor(Player:GetPosX())+userCopy[Name]["xOff"]
	local pY = mFloor(Player:GetPosY())+userCopy[Name]["yOff"]
	local pZ = mFloor(Player:GetPosZ())+userCopy[Name]["zOff"]
	
	--Brush position support
	if (#Split>=2) and (userBrush[Name]~=nil) then
		if (Split[2]=="brush") and (userBrush[Name]["val_2"]>-1) and (userBrush[Name]["Active"]=="Paste") then
			pX = userBrush[Name]["val_1"]+userCopy[Name]["xOff"]
			pY = userBrush[Name]["val_2"]+userCopy[Name]["yOff"]
			pZ = userBrush[Name]["val_3"]+userCopy[Name]["zOff"]
		end
	end
	
	IncrementUndoGroup( Name )
	
	x = min["x"]
	while x <= max["x"] do
	 ax = x+pX-1
		y = min["y"]
		while y <= max["y"] do
			ay = y+pY-1
			z = min["z"]
			while z <= max["z"] do
			 	az = z+pZ-1
			  	CuboidBlockPlace(ax,ay,az, userCopy[Name]["data"][x][y][z]["b"], userCopy[Name]["data"][x][y][z]["m"], Name)
				z = z + 1
			end
			y = y + 1
		end
		x = x + 1
	end

	Player:SendMessage(cChatColor.Green .. 'Pasted: ' .. cChatColor.White .. total .. cChatColor.Green .. ' blocks.' )
	return true
end

function HandlePasteB( Split, Player )
	
	local World = cRoot:Get():GetWorld()
	local Name  = Player:GetName()
	
	if userCopy[Name] == nil or userCopy[Name]["data"] == nil then
		Player:SendMessage(cChatColor.Red .. 'No blocks in clipboard.')
		return true
	end
	
	local min   = {}
	 min["x"] = 1
	 min["y"] = 1
	 min["z"] = 1
	local max   = {}
	 max["x"] = #userCopy[Name]["data"]
	 max["y"] = #userCopy[Name]["data"][max["x"]]
	 max["z"] = #userCopy[Name]["data"][max["x"]][max["y"]]
	local total = (max["x"]-min["x"]+1)*(max["y"]-min["y"]+1)*(max["z"]-min["z"]+1)

	Log('Cuboid: Pasting ' .. total .. ' blocks.')
	
	local pX = mFloor(Player:GetPosX())+userCopy[Name]["xOff"]
	local pY = mFloor(Player:GetPosY())+userCopy[Name]["yOff"]
	local pZ = mFloor(Player:GetPosZ())+userCopy[Name]["zOff"]
	
	--Brush position support
	if (#Split>=2) and (userBrush[Name]~=nil) then
		if (Split[2]=="brush") and (userBrush[Name]["val_2"]>-1) and (userBrush[Name]["Active"]=="PasteB") then
			pX = userBrush[Name]["val_1"]+userCopy[Name]["xOff"]
			pY = userBrush[Name]["val_2"]+userCopy[Name]["yOff"]
			pZ = userBrush[Name]["val_3"]+userCopy[Name]["zOff"]
		end
	end
	
	IncrementUndoGroup( Name )
	
	x = min["x"]
	while x <= max["x"] do
	 ax = x+pX-1
		
    y = min["y"]
		while y <= max["y"] do
			ay = y+pY-1
			
      z = min["z"]
			while z <= max["z"] do
			  az = z+pZ-1
			  
			  if userCopy[Name]["data"][x][y][z]["b"] > 0 then
			    CuboidBlockPlace(ax,ay,az, userCopy[Name]["data"][x][y][z]["b"], userCopy[Name]["data"][x][y][z]["m"], Name)
			  end
				z = z + 1
			end
			y = y + 1
		end
		x = x + 1
	end

	Player:SendMessage(cChatColor.Green .. 'Pasted: ' .. cChatColor.White .. total .. cChatColor.Green .. ' blocks.' )
	
	return true
end

function HandleCBClean( Split, Player )
	
	local World = cRoot:Get():GetWorld()
	local Name  = Player:GetName()
	
	if userCopy[Name] == nil or userCopy[Name]["data"] == nil then
		Player:SendMessage(cChatColor.Red .. 'No blocks in clipboard.')
		return true
	end
	
	local min   = {}
	 min["x"] = 1
	 min["y"] = 1
	 min["z"] = 1
	local max   = {}
	 max["x"] = #userCopy[Name]["data"]
	 max["y"] = #userCopy[Name]["data"][max["x"]]
	 max["z"] = #userCopy[Name]["data"][max["x"]][max["y"]]
	local total = (max["x"]-min["x"]+1)*(max["y"]-min["y"]+1)*(max["z"]-min["z"]+1)
	
	x = min["x"]
	while x <= max["x"] do
    y = min["y"]
		while y <= max["y"] do
      z = min["z"]
			while z <= max["z"] do
			  
			  if userCopy[Name]["data"][x][y][z]["b"] >=8 and userCopy[Name]["data"][x][y][z]["b"] <=11 then
			   userCopy[Name]["data"][x][y][z]["b"] = 0
			   userCopy[Name]["data"][x][y][z]["m"] = 0
			  end
				z = z + 1
			end
			y = y + 1
		end
		x = x + 1
	end

	Player:SendMessage(cChatColor.Green .. 'Removed liquids from clipboard.' )
	
	return true
end

function HandleRotate( Split, Player )
	
	local World = cRoot:Get():GetWorld()
	local Name  = Player:GetName()
	
	if userCopy[Name] == nil or userCopy[Name]["data"] == nil then
		Player:SendMessage(cChatColor.Red .. 'No blocks in clipboard.')
		return true
	end
	
	if #Split >= 2 and Split[2]~=0 then
	 rotateQuadrant = mFloor(mMax(0,Split[2])/90) % 4
	else
	 rotateQuadrant = 1
	end
	
	if rotateQuadrant == 0 then
    if Split[2] >=360 then
	    Player:SendMessage(cChatColor.Red .. '360 degree rotation is pointless.')
		  return true
    else
      --No rotation specified, default to 90
      rotateQuadrant = 1
    end
  end
	
	local min   = {}
	 min["x"] = 1
	 min["y"] = 1
	 min["z"] = 1
	local max   = {}
	 max["x"] = #userCopy[Name]["data"]
	 max["y"] = #userCopy[Name]["data"][max["x"]]
	 max["z"] = #userCopy[Name]["data"][max["x"]][max["y"]]
	local total = (max["x"]-min["x"]+1)*(max["y"]-min["y"]+1)*(max["z"]-min["z"]+1)
	
	--Setup the temporary table
	local rotateData = {}
  newMax = {}
  if (rotateQuadrant == 2) then
    newMax["x"] = max["x"]
    newMax["z"] = max["z"]
  else
    newMax["x"] = max["z"]
    newMax["z"] = max["x"]
  end
  newMax["y"] = max["y"]
  x = min["x"]
	while x <= newMax["x"] do
	  rotateData[x] = {}
	  y = min["y"]
		while y <= newMax["y"] do
      rotateData[x][y] = {}
      z = min["z"]
      while z <= newMax["z"] do
			  rotateData[x][y][z] = {}
				z = z + 1
			end
			y = y + 1
		end
		x = x + 1
	end
	
	--Fill the table
	x = min["x"]
	while x <= newMax["x"] do
	  y = min["y"]
		while y <= newMax["y"] do
      z = min["z"]
      while z <= newMax["z"] do
			  if rotateQuadrant == 1 then
			    rotateData[1+newMax["x"]-x][y][z]["b"] = userCopy[Name]["data"][z][y][x]["b"]
			    rotateData[1+newMax["x"]-x][y][z]["m"] = userCopy[Name]["data"][z][y][x]["m"]
			  elseif rotateQuadrant == 2 then
			    rotateData[x][y][z]["b"] = userCopy[Name]["data"][1+max["x"]-x][y][1+max["z"]-z]["b"]
			    rotateData[x][y][z]["m"] = userCopy[Name]["data"][1+max["x"]-x][y][1+max["z"]-z]["m"]
			  else
			    rotateData[1+newMax["x"]-x][y][z]["b"] = userCopy[Name]["data"][1+newMax["z"]-z][y][1+newMax["x"]-x]["b"]
			    rotateData[1+newMax["x"]-x][y][z]["m"] = userCopy[Name]["data"][1+newMax["z"]-z][y][1+newMax["x"]-x]["m"]
			  end
				z = z + 1
			end
			y = y + 1
		end
		x = x + 1
	end
	
	--Set OffsetCoords
	tmpX = userCopy[Name]["xOff"]
	tmpZ = userCopy[Name]["zOff"]
	--Stuff goes here
	
	userCopy[Name]["data"] = {}
  userCopy[Name]["data"] = DeepCopy(rotateData)

	Player:SendMessage(cChatColor.Green .. 'Rotated clipboard by ' ..(90*rotateQuadrant).. ' degrees.' )
	
	return true
end

function HandleStack( Split, Player )
	
	local World = cRoot:Get():GetWorld()
	local Name  = Player:GetName()
	
	if pointCset[Name] ~= 3 then
		Server:SendMessage( cChatColor.Red .. "Must select a cuboid first!", Player )
		return true
	end
	
	local min   = getMinimum(points[Name])
	local max   = getMaximum(points[Name])
	local total = (max["x"]-min["x"]+1)*(max["y"]-min["y"]+1)*(max["z"]-min["z"]+1)
	
	if total > copyLimit then
		Player:SendMessage(cChatColor.Red .. 'Selection is too large (+' ..copyLimit.. ').')
		return true
	end
	
	--Default to 1 if no
	splitNum = 1
	if #Split >= 2 and Split[2]~=0 then
	 splitNum = 0 + Split[2]
	end
	
	incX = 0
	incY = 0
	incZ = 0
	
	local pitch = Player:GetPitch()
	if pitch < - 60 then
	   --Up
	   incY = (1+max["y"]-min["y"])
	elseif pitch > 60 then
	   --Down
	   incY = -(1+max["y"]-min["y"])
  else
    local degrees = Player:GetRotation()
	  if degrees < -135 then degrees = 360 + degrees end
	
	  if (-45 <= degrees and degrees < 45) then
    	-- North
    	incZ = (1+max["z"]-min["z"])
    elseif (45 <= degrees and degrees < 135) then
    	-- East
    	incX = -(1+max["x"]-min["x"])
    elseif (135 <= degrees and degrees < 225) then
    	-- South
    	incZ = -(1+max["z"]-min["z"])
    elseif ((225 <= degrees and degrees < 315) or (-135 <= degrees and degrees < -45)) then
    	-- West
    	incX = (1+max["x"]-min["x"])
    end
  end
	
	adjX = 0
	adjY = 0
	adjZ = 0
	
	IncrementUndoGroup( Name )
	
	--Needs optimization for larger stacks
	--Should check splitNum*total if blocks should be pre loaded in a table. See undo for details.
	s = 1
	while s <= splitNum do
		adjX = s*incX
		adjY = s*incY
		adjZ = s*incZ	
		x = min["x"]
		while x <= max["x"] do
    	y = min["y"]
			while y <= max["y"] do
      	z = min["z"]
				while z <= max["z"] do
			    CuboidBlockPlace(x+adjX, y+adjY, z+adjZ, World:GetBlock(x, y, z), World:GetBlockMeta(x, y, z), Name)
					z = z + 1
				end
				y = y + 1
			end
			x = x + 1
		end
		s = s + 1
	end

	Player:SendMessage(cChatColor.Green .. 'Multiplied: ' .. cChatColor.White .. total .. cChatColor.Green .. ' blocks ' .. splitNum .. ' times. (' ..(total*splitNum).. ' blocks changed)')
	
	return true
end

function HandleMirrorX( Split, Player )
	
	local World = cRoot:Get():GetWorld()
	local Name  = Player:GetName()
	
	if userCopy[Name] == nil or userCopy[Name]["data"] == nil then
		Player:SendMessage(cChatColor.Red .. 'No blocks in clipboard.')
		return true
	end
	
	local min   = {}
	 min["x"] = 1
	 min["y"] = 1
	 min["z"] = 1
	local max   = {}
	 max["x"] = #userCopy[Name]["data"]
	 max["y"] = #userCopy[Name]["data"][max["x"]]
	 max["z"] = #userCopy[Name]["data"][max["x"]][max["y"]]
	local total = (max["x"]-min["x"]+1)*(max["y"]-min["y"]+1)*(max["z"]-min["z"]+1)
	
	local copyData = DeepCopy(userCopy[Name]["data"])
	
	x = min["x"]
	while x <= max["x"] do
	  y = min["y"]
		while y <= max["y"] do
      z = min["z"]
      while z <= max["z"] do
			  userCopy[Name]["data"][x][y][z]["b"] = copyData[1+max["x"]-x][y][z]["b"]
			  userCopy[Name]["data"][x][y][z]["m"] = copyData[1+max["x"]-x][y][z]["m"]
			  
				z = z + 1
			end
			y = y + 1
		end
		x = x + 1
	end
	
  userCopy[Name]["xOff"] = -max["x"]-mFloor(2+userCopy[Name]["xOff"]-mAbs(max["x"]/2))

	Player:SendMessage(cChatColor.Green .. 'Mirrored clipboard on x axis.' )
	
	return true
end

function HandleMirrorY( Split, Player )
	
	local World = cRoot:Get():GetWorld()
	local Name  = Player:GetName()
	
	if userCopy[Name] == nil or userCopy[Name]["data"] == nil then
		Player:SendMessage(cChatColor.Red .. 'No blocks in clipboard.')
		return true
	end
	
	local min   = {}
	 min["x"] = 1
	 min["y"] = 1
	 min["z"] = 1
	local max   = {}
	 max["x"] = #userCopy[Name]["data"]
	 max["y"] = #userCopy[Name]["data"][max["x"]]
	 max["z"] = #userCopy[Name]["data"][max["x"]][max["y"]]
	local total = (max["x"]-min["x"]+1)*(max["y"]-min["y"]+1)*(max["z"]-min["z"]+1)
	
	local copyData = DeepCopy(userCopy[Name]["data"])
	
	x = min["x"]
	while x <= max["x"] do
	  y = min["y"]
		while y <= max["y"] do
      z = min["z"]
      while z <= max["z"] do
			  userCopy[Name]["data"][x][y][z]["b"] = copyData[x][1+max["y"]-y][z]["b"]
			  userCopy[Name]["data"][x][y][z]["m"] = copyData[x][1+max["y"]-y][z]["m"]
			  
				z = z + 1
			end
			y = y + 1
		end
		x = x + 1
	end
	
  userCopy[Name]["yOff"] = -max["y"]-mFloor(2+userCopy[Name]["yOff"]-mAbs(max["y"]/2))

	Player:SendMessage(cChatColor.Green .. 'Mirrored clipboard on y axis.' )
	
	return true
end

function HandleMirrorZ( Split, Player )
	
	local World = cRoot:Get():GetWorld()
	local Name  = Player:GetName()
	
	if userCopy[Name] == nil or userCopy[Name]["data"] == nil then
		Player:SendMessage(cChatColor.Red .. 'No blocks in clipboard.')
		return true
	end
	
	local min   = {}
	 min["x"] = 1
	 min["y"] = 1
	 min["z"] = 1
	local max   = {}
	 max["x"] = #userCopy[Name]["data"]
	 max["y"] = #userCopy[Name]["data"][max["x"]]
	 max["z"] = #userCopy[Name]["data"][max["x"]][max["y"]]
	local total = (max["x"]-min["x"]+1)*(max["y"]-min["y"]+1)*(max["z"]-min["z"]+1)
	
	local copyData = DeepCopy(userCopy[Name]["data"])
	
	x = min["x"]
	while x <= max["x"] do
	  y = min["y"]
		while y <= max["y"] do
      z = min["z"]
      while z <= max["z"] do
			  userCopy[Name]["data"][x][y][z]["b"] = copyData[x][y][1+max["z"]-z]["b"]
			  userCopy[Name]["data"][x][y][z]["m"] = copyData[x][y][1+max["z"]-z]["m"]
			  
				z = z + 1
			end
			y = y + 1
		end
		x = x + 1
	end
	
  userCopy[Name]["zOff"] = -max["z"]-mFloor(4+userCopy[Name]["zOff"]-mAbs(max["z"]/2))

	Player:SendMessage(cChatColor.Green .. 'Mirrored clipboard on z axis.' )
	
	return true
end

function HandleCompass( Split, Player )
	
	local Server = cRoot:Get():GetServer()
	local degrees = Player:GetRotation()
	
	if degrees < 0 then
		degrees = 360 - mAbs(degrees)
	end
	
	if (0 <= degrees and degrees < 22.5) then
    	direction = "North"
    elseif (22.5 <= degrees and degrees < 67.5) then
    	direction = "North East"
    elseif (67.5 <= degrees and degrees < 112.5) then
    	direction = "East"
    elseif (112.5 <= degrees and degrees < 157.5) then
    	direction = "South East"
    elseif (157.5 <= degrees and degrees < 202.5) then
    	direction = "South"
    elseif (202.5 <= degrees and degrees < 247.5) then
    	direction = "South West"
    elseif (247.5 <= degrees and degrees < 292.5) then
    	direction = "West"
    elseif (292.5 <= degrees and degrees < 337.5) then
    	direction = "North West"
    elseif (337.5 <= degrees and degrees < 360.0) then
    	direction = "North"
    else 
    	direction = "Center of the earth!!!!"
    end

	Server:SendMessage( cChatColor.Green .. "Compass: " .. cChatColor.White .. direction .. " (" .. round(degrees, 0) .. "º) " , Player )
	
	return true
	
end

function HandleSuperaxe( Split, Player )
	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	if superaxe[Name] == false then
		superaxe[Name] = true
		Server:SendMessage( cChatColor.Green .. "Super Axe Enabled!", Player)
	elseif superaxe[Name] == true then
		superaxe[Name] = false
		Server:SendMessage( cChatColor.Green .. "Super Axe Disabled!", Player)
	end
	return true	
end

function CuboidBlockPlace( x, y, z, Block, Meta, Name )
	Meta = Meta or 0
	local World = cRoot:Get():GetWorld()
	local OldBlock = World:GetBlock(x, y, z)
	
	if cuboidHistory[Name] == nil then
		cuboidHistory[Name] = {}
	end
	
	Count = #cuboidHistory[Name][#cuboidHistory[Name]] + 1
	cuboidHistory[Name][#cuboidHistory[Name]][Count] = {x=x, y=y, z=z, Block=OldBlock}
	World:FastSetBlock(x, y, z, Block, Meta)
end

function BrushBlockPlace( x, y, z, Block, Meta, Name )
	Meta = Meta or 0
	local World = cRoot:Get():GetWorld()
	local OldBlock = World:GetBlock(x, y, z)
	
	if cuboidHistory[Name] == nil then
		cuboidHistory[Name] = {}
	end
	
	Count = #cuboidHistory[Name][#cuboidHistory[Name]] + 1
	cuboidHistory[Name][#cuboidHistory[Name]][Count] = {x=x, y=y, z=z, Block=OldBlock}
	World:SetBlock(x, y, z, Block, Meta)
end

function HandleRedo( Split, Player )
	local World = cRoot:Get():GetWorld()
	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	
	if (cuboidRedo[Name] ==nil) then
		Server:SendMessage( cChatColor.Red .. "Nothing to redo.", Player )
		return true
	end
	
	IncrementUndoGroup(Name)
	if #cuboidRedo[Name] > 0 then
		local redoTable = cuboidRedo[Name]
		for _,voxel in ipairs(redoTable) do
			CuboidBlockPlace(voxel.x, voxel.y, voxel.z, voxel.Block, 0, Name)
		end
		  
		Server:SendMessage( cChatColor.Green .. "Reapplied " .. cChatColor.White .. #cuboidRedo[Name] .. cChatColor.Green .. " blocks.", Player )
		cuboidRedo[Name] = nil
		return true
	else
		Server:SendMessage( cChatColor.Red .. "No undos in recent history.", Player )
		return true
	end
end

function HandleUndo( Split, Player )
	local World = cRoot:Get():GetWorld()
	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	
	cuboidRedo[Name] = {}
	if #cuboidHistory[Name] > 0 then
	  historyIndex = #cuboidHistory[Name]
	  if #cuboidHistory[Name][historyIndex] > 0 then
	    local undoTable = cuboidHistory[Name][historyIndex]
		  for _,voxel in ipairs(undoTable) do
			  cuboidRedo[Name][#cuboidRedo[Name]+1] = {x=voxel.x, y=voxel.y, z=voxel.z, Block=World:GetBlock(voxel.x, voxel.y, voxel.z)}
			  World:FastSetBlock(voxel.x, voxel.y, voxel.z, voxel.Block, 0)
		  end
		  
		  Server:SendMessage( cChatColor.Green .. "Changed back " .. cChatColor.White .. #cuboidHistory[Name][historyIndex] .. cChatColor.Green .. " blocks.", Player )
		  cuboidHistory[Name][historyIndex] = nil
		  return true
	  else
		  Server:SendMessage( cChatColor.Red .. "Nothing to undo.", Player )
		  return true
		end
	else
	  Server:SendMessage( cChatColor.Red .. "No commands in recent history.", Player )
		return true
	end
end

function generateTree( x, y, z, Name )
	
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	
	IncrementUndoGroup( Name )
	
	y = y + 1

	local trunk = mRandom(5, 7)
		
	i = 0
	while i < trunk do
		CuboidBlockPlace(x, y+i, z, E_BLOCK_LOG, 0, Name)
		i = i + 1
	end
	
	j = 0
	while j < trunk do
		local radius = trunk - j
		if radius < 4 then
			if radius > 2 then 
				radius = 2
			end
			local i = x - radius
			while i <= x+ radius do
				k = z - radius
				while k <= z+radius do
					if k ~= z and i ~= x then
						if mRandom() > 0.1 then
							CuboidBlockPlace(i, y+j, k, E_BLOCK_LEAVES, 0, Name)
						end
					else
						CuboidBlockPlace(i, y+j, k, E_BLOCK_LEAVES, 0, Name)
					end
					k = k + 1
				end
				i = i + 1
			end
			CuboidBlockPlace(x, y+j, z, E_BLOCK_LOG, 0, Name)
		end
		j = j + 1
	end
	
	CuboidBlockPlace(x+1, y+trunk, z, E_BLOCK_LEAVES, 0, Name)
	CuboidBlockPlace(x-1, y+trunk, z, E_BLOCK_LEAVES, 0, Name)
	CuboidBlockPlace(x, y+trunk, z+1, E_BLOCK_LEAVES, 0, Name)
	CuboidBlockPlace(x, y+trunk, z-1, E_BLOCK_LEAVES, 0, Name)
	CuboidBlockPlace(x, y+trunk, z, E_BLOCK_LEAVES, 0, Name)

	
end

function HandleTree( Split, Player )
	
	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	
	if points[Name]["1"]["x"] == 0 then
		Server:SendMessage( cChatColor.Red .. "Must select a center point.", Player )
		return true
	end
	
	x = points[Name]["1"]["x"]
	y = points[Name]["1"]["y"]
	z = points[Name]["1"]["z"]
	
	generateTree(x, y, z, Name)
		
	pointCset[Name] = 0
	return true
	
end

function HandleForest( Split, Player )
	
	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	local World = cRoot:Get():GetWorld()
	
	if points[Name]["1"]["x"] == 0 then
		Server:SendMessage( cChatColor.Red .. "Must select a center point.", Player )
		return true
	end
	
	if #Split ~= 3 then
		Server:SendMessage( cChatColor.Red .. "Usage: /forest [radius] [density]", Player )
		return true
	end
	
	radius = tonumber(Split[2])
	density = tonumber(Split[3])
	
	count = 0
	g = 0
	while g < density do
		x = points[Name]["1"]["x"] + mRandom((radius * -1), radius)
		y = points[Name]["1"]["y"]
		z = points[Name]["1"]["z"] + mRandom((radius * -1), radius)
		
		-- find the ground
		ground = World:GetBlock(x, y, z)
		yoffset = 0
		while true do
			if ground ~= E_BLOCK_AIR and ground ~= E_BLOCK_LOG and ground ~= E_BLOCK_LEAVES then
				break
			end
			yoffset = yoffset + 1
			ground = World:GetBlock(x, y-yoffset, z)
		end
		y = y - yoffset
		
		generateTree(x, y, z, Name)
		g = g + 1
	end
	
	pointCset[Name] = 0
	return true
	
end

function HandleCircle( Split, Player )
	
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	local xCenter = points[Name]["1"]["x"]
	local zCenter = points[Name]["1"]["y"]
	local yCenter = points[Name]["1"]["z"]
	
	if points[Name]["1"]["x"] == 0 then
		Server:SendMessage( cChatColor.Red .. "Must select a center point.", Player )
		return true
	end
	
	if #Split ~= 3 then
		Server:SendMessage( cChatColor.Red .. "Usages: /circle [block] [radius]", Player )
		return true
	end
	
	local radius = tonumber(Split[3])
	
	local fillBlock, fillMeta = cuboidBlock(Split[2])
	if fillBlock == -1 then
		Server:SendMessage( cChatColor.Red .. "Invalid block ID.", Player )
		return true
	end
	
	IncrementUndoGroup( Name )
	
	xMin = xCenter-radius
	xMax = xCenter+radius
	yMin = yCenter-radius
	yMax = yCenter+radius
	zMin = zCenter
	zMax = zCenter
	count = 0
	i = xMin
	while i <= xMax do
		j = yMin
		while j <= yMax do
			k = zMin
			while k <= zMax do
				diff = mSqrt( mPow(i-xCenter, 2) + mPow(j-yCenter, 2) + mPow(k-zCenter, 2) )
				if diff < radius+0.5 and diff > radius-0.5 then
					CuboidBlockPlace(i, k, j, fillBlock, fillMeta, Name)
					count = count + 1
				end
				k = k + 1
			end
			j = j + 1
		end
		i = i + 1
	end
	pointCset[Name] = 0
	return true
end

function HandleDisk( Split, Player )
	
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	local xCenter = points[Name]["1"]["x"]
	local zCenter = points[Name]["1"]["y"]
	local yCenter = points[Name]["1"]["z"]
	
	if points[Name]["1"]["x"] == 0 then
		Server:SendMessage( cChatColor.Red .. "Must select a center point.", Player )
		return true
	end
	
	if #Split ~= 3 then
		Server:SendMessage( cChatColor.Red .. "Usages: /disk [block] [radius]", Player )
		return true
	end
	
	local radius = tonumber(Split[3])
	
	local fillBlock, fillMeta = cuboidBlock(Split[2])
	if fillBlock == 0 then
		Server:SendMessage( cChatColor.Red .. "Invalid block ID.", Player )
		return true
	end
	
	IncrementUndoGroup( Name )
	
	xMin = xCenter-radius
	xMax = xCenter+radius
	yMin = yCenter-radius
	yMax = yCenter+radius
	zMin = zCenter
	zMax = zCenter
	count = 0
	i = xMin
	while i <= xMax do
		j = yMin
		while j <= yMax do
			k = zMin
			while k <= zMax do
				diff = mSqrt( mPow(i-xCenter, 2) + mPow(j-yCenter, 2) + mPow(k-zCenter, 2) )
				if diff < radius+0.5 then
					CuboidBlockPlace(i, k, j, fillBlock, fillMeta, Name)
					count = count + 1
				end
				k = k + 1
			end
			j = j + 1
		end
		i = i + 1
	end
	pointCset[Name] = 0
	return true
end

function HandleCylinder( Split, Player )
	
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	local xCenter = points[Name]["1"]["x"]
	local zCenter = points[Name]["1"]["y"]
	local yCenter = points[Name]["1"]["z"]
	
	if points[Name]["1"]["x"] == 0 then
		Server:SendMessage( cChatColor.Red .. "Must select a center point.", Player )
		return true
	end
	
	if #Split ~= 4 then
		Server:SendMessage( cChatColor.Red .. "Usages: /cylinder [block] [radius] [height]", Player )
		return true
	end
	
	local radius = tonumber(Split[3])
	
	local fillBlock, fillMeta = cuboidBlock(Split[2])
	if fillBlock == 0 then
		Server:SendMessage( cChatColor.Red .. "Invalid block ID.", Player )
		return true
	end
	
	IncrementUndoGroup( Name )
	
	height = tonumber(Split[4])
	
	Server:SendMessage( cChatColor.Blue .. "Building Cylinder...", Player )
	
	xMin = xCenter-radius
	xMax = xCenter+radius
	yMin = yCenter-radius
	yMax = yCenter+radius
	zMin = zCenter
	zMax = zCenter
	count = 0
	h = 0
	while h <= height do
		i = xMin
		while i <= xMax do
			j = yMin
			while j <= yMax do
				k = zMin
				while k <= zMax do
					diff = mSqrt( mPow(i-xCenter, 2) + mPow(j-yCenter, 2) + mPow(k-zCenter, 2) )
					if diff < radius+0.5 and diff > radius-0.5 then
						CuboidBlockPlace(i, k+h, j, fillBlock, 0, Name)
						count = count + 1
					end
					k = k + 1
				end
				j = j + 1
			end
			i = i + 1
		end
		h = h + 1
	end
	pointCset[Name] = 0
	return true
end

function HandleSquare( Split, Player )
	
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	local xCenter = points[Name]["1"]["x"]
	local zCenter = points[Name]["1"]["y"]
	local yCenter = points[Name]["1"]["z"]
	
	if points[Name]["1"]["x"] == 0 then
		Server:SendMessage( cChatColor.Red .. "Must select a center point.", Player )
		return true
	end
	
	if #Split ~= 3 then
		Server:SendMessage( cChatColor.Red .. "Usages: /square [block] [size]", Player )
		return true
	end
	
	local size    = tonumber(Split[3])
	
	local fillBlock, fillMeta = cuboidBlock(Split[2])
	if fillBlock == 0 then
		Server:SendMessage( cChatColor.Red .. "Invalid block ID.", Player )
		return true
	end
	
	IncrementUndoGroup( Name )

	-- top left
	local tlX = xCenter - size
	local tlY = yCenter - size

	-- top right
	local trX = xCenter + size
	local trY = yCenter - size

	-- bottom left
	local blX = xCenter - size
	local blY = yCenter + size

	-- bottom right
	local brX = xCenter + size
	local brY = yCenter + size

	-- TL -> TR
	-- BL -> BR
	-- TL -> BL
	-- TR -> RB
	
	count = 0
	
	-- set the bottom right block since it
	-- doesn't seem to be set by what follows
	CuboidBlockPlace(brX, zCenter, brY, fillBlock, 0, Name)

	i = 0
	while tlX+i < trX do
		CuboidBlockPlace(tlX+i, zCenter, tlY, fillBlock, 0, Name)
		count = count + 1
		i = i + 1
	end
	i = 0
	while blX+i < brX do
		CuboidBlockPlace(blX+i, zCenter, blY, fillBlock, 0, Name)
		count = count + 1
		i = i + 1
	end
	i = 0
	while tlY+i < blY do
		CuboidBlockPlace(tlX, zCenter, tlY+i, fillBlock, 0, Name)
		count = count + 1
		i = i + 1
	end
	i = 0
	while trY+i < brY do
		CuboidBlockPlace(trX, zCenter, trY+i, fillBlock, 0, Name)
		count = count + 1
		i = i + 1
	end
	pointCset[Name] = 0
	return true
end

function HandlePyramid( Split, Player )
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	local xCenter = points[Name]["1"]["x"]
	local zCenter = points[Name]["1"]["y"]
	local yCenter = points[Name]["1"]["z"]
	
	if points[Name]["1"]["x"] == 0 then
		Server:SendMessage( cChatColor.Red .. "Must select a center point.", Player )
		return true
	end
	
	if #Split ~= 3 then
		Server:SendMessage( cChatColor.Red .. "Usages: /square [block] [size]", Player )
		return true
	end
	
	local size = tonumber(Split[3])
	
	local fillBlock, fillMeta = cuboidBlock(Split[2])
	if fillBlock == 0 then
		Server:SendMessage( cChatColor.Red .. "Invalid block ID.", Player )
		return true
	end
	
	IncrementUndoGroup( Name )
	
	count = 0
	
	height = 0;
	while size > 0 do

		-- top left
		local tlX = xCenter - size
		local tlY = yCenter - size 

		-- top right               
		local trX = xCenter + size 
		local trY = yCenter - size 

		-- bottom left             
		local blX = xCenter - size 
		local blY = yCenter + size 

		-- bottom right            
		local brX = xCenter + size 
		local brY = yCenter + size 

		-- set the bottom right block since it
		-- doesn't seem to be set by what follows
		CuboidBlockPlace(brX, zCenter + height, brY, fillBlock, 0, Name)

		i = 0
		while tlX+i < trX do
			CuboidBlockPlace(tlX+i, zCenter + height, tlY, fillBlock, 0, Name)
			count = count + 1
			i = i + 1
		end
		i = 0
		while blX+i < brX do
			CuboidBlockPlace(blX+i, zCenter + height, blY, fillBlock, 0, Name)
			count = count + 1
			i = i + 1
		end
		i = 0
		while tlY+i < blY do
			CuboidBlockPlace(tlX, zCenter + height, tlY+i, fillBlock, 0, Name)
			count = count + 1
			i = i + 1
		end
		i = 0
		while trY+i < brY do
			CuboidBlockPlace(trX, zCenter + height, trY+i, fillBlock, 0, Name)
			count = count + 1
			i = i + 1
		end

		size = size - 1
		height = height + 1
	end
	pointCset[Name] = 0
	return true
end

function HandleSphere( Split, Player )
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	local xCenter = points[Name]["1"]["x"]
	local zCenter = points[Name]["1"]["y"]
	local yCenter = points[Name]["1"]["z"]
	
	if points[Name]["1"]["x"] == 0 then
		Server:SendMessage( cChatColor.Red .. "Must select a center point.", Player )
		return true
	end
	
	if #Split < 3 or #Split > 4 then
		Server:SendMessage( cChatColor.Red .. "Usages: /sphere [block] [size] [fill]", Player )
		return true
	end
	
	local radius = tonumber(Split[3])
	
	local fillBlock, fillMeta = cuboidBlock(Split[2])
	if fillBlock == 0 then
		Server:SendMessage( cChatColor.Red .. "Invalid block ID.", Player )
		return true
	end
	
	if #Split == 4 then
		fill = tonumber(Split[4])
		if fill ~= 1 and fill ~= 0 and fill ~= 2 then
			Server:SendMessage( cChatColor.Red .. "Invalid fill selection. 1 = solid, 0 = hollow", Player )
			return true
		end
	
	else
		fill = 0
	end
	
	IncrementUndoGroup( Name )
	
	Server:SendMessage( cChatColor.Blue .. "Building Sphere...", Player )
	
	xMin = xCenter-radius
	xMax = xCenter+radius
	yMin = yCenter-radius
	yMax = yCenter+radius
	zMin = zCenter-radius
	zMax = zCenter+radius
	
	local iAdjust = xCenter*2
	local jAdjust = yCenter*2
	
	local iPow
	
	count = 0
	i = xMin
	while i <= xCenter do
	  iPow = mPow(i-xCenter, 2)
		j = yMin
		while j <= yCenter do
		  jPow = mPow(j-yCenter, 2)
			k = zMin
			while k <= zMax do
				diff = mSqrt( iPow + jPow + mPow(k-zCenter, 2) )
				if diff < radius+0.5 and ( fill == 1 or fill == 2 or diff > radius-0.5 ) then
					if fill == 2 and diff > radius-0.5 then
						CuboidBlockPlace(i, k, j, E_BLOCK_AIR, 0, Name)
						CuboidBlockPlace(iAdjust-i, k, j, E_BLOCK_AIR, 0, Name)
						CuboidBlockPlace(i, k, jAdjust-j, E_BLOCK_AIR, 0, Name)
						CuboidBlockPlace(iAdjust-i, k, jAdjust-j, E_BLOCK_AIR, 0, Name)
						count = count + 1
					else
						CuboidBlockPlace(i, k, j, fillBlock, fillMeta, Name)
						CuboidBlockPlace(iAdjust-i, k, jAdjust-j, fillBlock, fillMeta, Name)
						CuboidBlockPlace(i, k, jAdjust-j, fillBlock, fillMeta, Name)
						CuboidBlockPlace(iAdjust-i, k, jAdjust-j, fillBlock, fillMeta, Name)
						count = count + 1
					end
				end
				k = k + 1
			end
			j = j + 1
		end
		i = i + 1
	end
	Server:SendMessage( cChatColor.Blue .. "Done.", Player )
	pointCset[Name] = 0
	return true
end

function cuboidBlock( Block ) 
	local blck = ""
	local bmeta = 0
  
  local sPos = string.find(Block, ":")
  if sPos ~= nil then
    blck = string.sub(Block, 1, sPos-1)
    bmeta = string.sub(Block, sPos+1)
    return blck, bmeta
  elseif (Block ~=nil) then 
    blck = Block
  else
    blck = nil
  end
	
  if ( HAVE_ITEM_NAMES == true ) then
		itemValue = itemsINI:GetValueI('Items', ''..blck..'', 0)
		if itemValue ~= 0 then
			if( not IsValidItem( tonumber(itemValue) ) ) then
				if( not IsValidItem( blck ) ) then
					return 0, bmeta
				else
					return blck, bmeta
				end
			else
				return itemValue, bmeta
			end
		else
			blck = tonumber(blck)
			if( blck == nil or not IsValidItem( blck ) ) then
				return 0, 0
			else
				return blck, bmeta
			end
		end
	else
		if( blck == nil or not IsValidItem( blck ) ) then
			return 0, 0
		else
			return blck, bmeta
		end
	end
end

function HandleSize ( Split, Player )
  	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
  
  	if pointCset[Name] == 3 then
    	cubeSize = getCuboidSize( Name )
    	Server:SendMessage( cChatColor.Blue .. "Selection size: " .. cubeSize .. " blocks.", Player )  
  	end
  
  	return true    
end

function HandleFill( Split, Player )
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	if pointCset[Name] == 3 then
	if Split[2] == nil then
		Server:SendMessage( cChatColor.Red .. "Invalid block ID. ( " .. fillBlock .. ")", Player )
		return true
	end	
    local fillBlock, fillMeta = cuboidBlock(Split[2])
		if fillBlock == nil then
			Server:SendMessage( cChatColor.Red .. "Invalid block ID. ( " .. fillBlock .. ")", Player )
			return true
		end
		
		IncrementUndoGroup( Name )
		
		min = getMinimum(points[Name])
		max = getMaximum(points[Name])
		
		minX = min["x"]
		minY = min["y"]
		minZ = min["z"]
		
		maxX = max["x"]
		maxY = max["y"]
		maxZ = max["z"]
		
		x = minX
		while x <= maxX do
			y = minY
			while y <= maxY do
				z = minZ
				while z <= maxZ do
					CuboidBlockPlace(x, y, z, fillBlock, fillMeta, Name)
					z = z + 1
				end
				y = y + 1
			end
			x = x + 1
		end
		fillSize = 1+ (1+mAbs(maxX - minX)) * (1+mAbs(maxY - minY)) * (1+mAbs(maxZ - minZ))
		Server:SendMessage( cChatColor.Blue .. "Filled area (" .. fillSize .. " blocks) with id: " .. fillBlock .. ":" .. fillMeta .. ".", Player )
	else
		Server:SendMessage( cChatColor.Red .. "Must select a cuboid first!", Player )
	end
	return true
end

function HandleHollowFill( Split, Player )
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	if pointCset[Name] == 3 then
		
		local fillBlock, fillMeta = cuboidBlock(Split[2])
		if fillBlock == nil then
			Server:SendMessage( cChatColor.Red .. "Invalid block ID. ( " .. fillBlock .. ")", Player )
			return true
		end
		
		IncrementUndoGroup( Name )
		
		min = getMinimum(points[Name])
		max = getMaximum(points[Name])
		
		minX = min["x"]
		minY = min["y"]
		minZ = min["z"]
		
		maxX = max["x"]
		maxY = max["y"]
		maxZ = max["z"]
		
		--Top & Bottom
		x = minX
		while x <= maxX do
		  z = minZ
		  while z <= maxZ do
		    CuboidBlockPlace(x, minY, z, fillBlock, fillMeta, Name)
		    CuboidBlockPlace(x, maxY, z, fillBlock, fillMeta, Name)
		    z = z + 1
		  end
			x = x + 1
		end
		
		--Sides
		x = minX
		while x <= maxX do
		  y = minY
		  while y <= maxY do
		    CuboidBlockPlace(x, y, minZ, fillBlock, fillMeta, Name)
		    CuboidBlockPlace(x, y, maxZ, fillBlock, fillMeta, Name)
		    y = y + 1
		  end
			x = x + 1
		end
		z = minZ
		while z <= maxZ do
		  y = minY
		  while y <= maxY do
		    CuboidBlockPlace(minX, y, z, fillBlock, fillMeta, Name)
		    CuboidBlockPlace(maxX, y, z, fillBlock, fillMeta, Name)
		    y = y + 1
		  end
			z = z + 1
		end
		
		--Empty Space
		x = minX+1
		while x <= maxX-1 do
			y = minY+1
			while y <= maxY-1 do
				z = minZ+1
				while z <= maxZ-1 do
					CuboidBlockPlace(x, y, z, 0, 0, Name)
					z = z + 1
				end
				y = y + 1
			end
			x = x + 1
		end
		fillSize = 1+ (1+mAbs(maxX - minX)) * (1+mAbs(maxY - minY)) * (1+mAbs(maxZ - minZ))
		Server:SendMessage( cChatColor.Blue .. "Filled area (" .. fillSize .. " blocks) with id: " .. fillBlock .. ":" ..fillMeta.. ".", Player )
	else
		Server:SendMessage( cChatColor.Red .. "Must select a cuboid first!", Player )
	end
	return true
end

function HandleLine( Split, Player )
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	if pointCset[Name] == 3 then
		if #Split < 2 then
			Server:SendMessage( cChatColor.Red .. "Usage: /line [BlockId]", Player )
			return true
		end
		
		local fillBlock, fillMeta = cuboidBlock(Split[2])
		if fillBlock == nil then
			Server:SendMessage( cChatColor.Red .. "Invalid block ID. ( " .. fillBlock .. ")", Player )
			return true
		end
		
		IncrementUndoGroup( Name )
		
		local erZ = 0
		local erX = 0
		local erY = 0
		local erYD = 0
		local x = points[Name]["1"]["x"]
		local z = points[Name]["1"]["z"]
		local y = points[Name]["1"]["y"]
		local xEnd = points[Name]["2"]["x"]
		local zEnd = points[Name]["2"]["z"]
		local yEnd = points[Name]["2"]["y"]
		local xInc = 0
		local yInc = 0
		local zInc = 0
		local dX = 0
		local dZ = 0
		local dY = 0
		
		if (x<xEnd) then
			dX = mAbs(xEnd-x)
			xInc = 1
		else
			dX = mAbs(x-xEnd)
			xInc = -1
		end
		if (y<yEnd) then
			dY = mAbs(yEnd-y)
			yInc = 1
		else
			dY = mAbs(y-yEnd)
			yInc = -1
		end
		if (z<zEnd) then
			dZ = mAbs(zEnd-z)
			zInc = 1
		else
			dZ = mAbs(z-zEnd)
			zInc = -1
		end
		
		if dX>dZ then
			local erZD = mAbs(dZ / dX)
			if dX>dY then
				erYD = mAbs(dX / dY)
			else
				erYD = mAbs(dY / dX)
			end
			while x ~= xEnd do
				erY = erY + erYD
				if (erY > 0.5) then
					while (erY > 0.5) do
						erY=erY-1
						y=y+yInc
						CuboidBlockPlace(x, y, z, fillBlock, fillMeta, Name)
					end
				else
					CuboidBlockPlace(x, y, z, fillBlock, fillMeta, Name)
				end
				erZ = erZ + erZD
				if (erZ > 0.5) then
					erZ=erZ-1
					z=z+zInc
				end
				x=x+xInc
			end
		else
			local erXD = mAbs(dX / dZ)
			if dZ>dY then
				erYD = mAbs(dZ / dY)
			else
				erYD = mAbs(dY / dZ)
			end
			while z ~= zEnd do
				erY = erY + erYD
				if (erY > 0.5) then
					while (erY > 0.5) do
						erY=erY-1
						y=y+yInc
						CuboidBlockPlace(x, y, z, fillBlock, fillMeta, Name)
					end
				else
					CuboidBlockPlace(x, y, z, fillBlock, fillMeta, Name)
				end
				erX = erX + erXD
				if (erX > 0.5) then
					erX=erX-1
					x=x+xInc
				end
				z=z+zInc
			end
		end
		Server:SendMessage( cChatColor.Blue .. "Line of id " .. fillBlock .. ":" .. fillMeta .. " drawn.", Player )
	else
		Server:SendMessage( cChatColor.Red .. "Must select a cuboid first!", Player )
	end
	return true
end

function HandleOverlay( Split, Player )
	
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	if pointCset[Name] == 3 then
		
		local fillBlock, fillMeta = cuboidBlock(Split[2])
		if fillBlock == nil then
			Server:SendMessage( cChatColor.Red .. "Invalid block ID. ( " .. fillBlock .. ")", Player )
			return true
		end
		
		IncrementUndoGroup( Name )
		
		min = getMinimum(points[Name])
		max = getMaximum(points[Name])
		
		minX = min["x"]
		minY = min["y"]
		minZ = min["z"]
		
		maxX = max["x"]
		maxY = max["y"]
		maxZ = max["z"]
		
		x = minX
		while x <= maxX do
			z = minZ
			while z <= maxZ do
				y = maxY-1
				while y >= minY do
				  if World:GetBlock(x, y, z) >0 and  World:GetBlock(x, y+1, z) == 0 then
					  CuboidBlockPlace(x, y+1, z, fillBlock, fillMeta, Name)
					  break
					end
					y = y - 1
				end
				z = z + 1
			end
			x = x + 1
		end
		fillSize = 1+ (1+mAbs(maxX - minX)) * (1+mAbs(maxY - minY)) * (1+mAbs(maxZ - minZ))
		Server:SendMessage( cChatColor.Blue .. "Overlayed area (" .. fillSize .. " blocks) with id: " .. fillBlock .. ":" ..fillMeta.. ".", Player )
	else
		Server:SendMessage( cChatColor.Red .. "Must select a cuboid first!", Player )
	end
	
	return true
end

function HandleReplace ( Split, Player )
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	if pointCset[Name] == 3 then
		local replaceBlock, replaceMeta = cuboidBlock(Split[2])
		if replaceBlock == nil then
			Server:SendMessage( cChatColor.Red .. "Invalid replace block ID. ( " .. replaceBlock .. ")", Player )
			return true
		end
		
		local fillBlock, fillMeta = cuboidBlock(Split[3])
		if fillBlock == nil then
			Server:SendMessage( cChatColor.Red .. "Invalid set block ID. ( " .. fillBlock .. ")", Player )
			return true
		end
		
		IncrementUndoGroup( Name )
		
		min = getMinimum(points[Name])
		max = getMaximum(points[Name])
		
		minX = min["x"]
		minY = min["y"]
		minZ = min["z"]
		
		maxX = max["x"]
		maxY = max["y"]
		maxZ = max["z"]
		
		cBlocks = 0
		x = minX
		while x <= maxX do
			y = minY
			while y <= maxY do
				z = minZ
				while z <= maxZ do
				  	if World:GetBlock(x,y,z) == replaceBlock then
					  CuboidBlockPlace(x, y, z, fillBlock, fillMeta, Name)
					  cBlocks = cBlocks + 1
					end
					z = z + 1
				end
				y = y + 1
			end
			x = x + 1
		end
		fillSize = 1+ (1+mAbs(maxX - minX)) * (1+mAbs(maxY - minY)) * (1+mAbs(maxZ - minZ))
		Server:SendMessage( cChatColor.Blue .. "Replaced " .. cBlocks .. " blocks in area (" .. fillSize .. " blocks) with id: " .. fillBlock .. ":" ..fillMeta.. ".", Player )
		
	else
		Server:SendMessage( cChatColor.Red .. "Must select a cuboid first!", Player )
	end
	
	return true
end

function HandleDelete( Split, Player )
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	if pointCset[Name] == 3 then
		IncrementUndoGroup( Name )

		min = getMinimum(points[Name])
		max = getMaximum(points[Name])
		
		minX = min["x"]
		minY = min["y"]
		minZ = min["z"]
		
		maxX = max["x"]
		maxY = max["y"]
		maxZ = max["z"]
		
		count = 0
		x = minX
		while x <= maxX do
			y = minY
			while y <= maxY do
				z = minZ
				while z <= maxZ do
					CuboidBlockPlace(x, y, z, 0, 0, Name)
					count = count + 1
					z = z + 1
				end
				y = y + 1
			end
			x = x + 1
		end
	else
		Server:SendMessage( cChatColor.Red .. "Must select a cuboid first!", Player )
	end
	
	return true
end

function HandlePosOne( Split, Player )
	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	local World = cRoot:Get():GetWorld()
	
	if cuboidOn[Name] == true then
		X = mFloor(Player:GetPosX())
		Y = mFloor(Player:GetPosY())
		Z = mFloor(Player:GetPosZ())
			
		if Y ~= -1 then
			Server:SendMessage( cChatColor.Green .. "Point A set: ".. cChatColor.White .." X:" ..X.. " Y:" ..Y.. " Z:" ..Z.. "", Player )
			points[Name]["1"]["x"] = X
			points[Name]["1"]["y"] = Y
			points[Name]["1"]["z"] = Z
			if pointCset[Name] == 2 or pointCset[Name] == 3 then
			    cubeSize = getCuboidSize( Name )
  				Server:SendMessage( cChatColor.Blue .. "Cuboid Ready! (Size: " .. cubeSize .. " blocks)", Player )
          		pointCset[Name] = 3
			else
				pointCset[Name] = 1	
			end
		end
	end
	return true
end


function HandlePosTwo( Split, Player )
	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	local World = cRoot:Get():GetWorld()
	
	if cuboidOn[Name] == true then
		X = mFloor(Player:GetPosX())
		Y = mFloor(Player:GetPosY())
		Z = mFloor(Player:GetPosZ())
			
		if Y ~= -1 then
			Server:SendMessage( cChatColor.Green .. "Point B set: ".. cChatColor.White .." X:" ..X.. " Y:" ..Y.. " Z:" ..Z.. "", Player )
			points[Name]["2"]["x"] = X
			points[Name]["2"]["y"] = Y
			points[Name]["2"]["z"] = Z
			if pointCset[Name] == 1 or pointCset[Name] == 3 then
			    cubeSize = getCuboidSize( Name )
				Server:SendMessage( cChatColor.Blue .. "Cuboid Ready! (Size: " .. cubeSize .. " blocks)", Player )
				pointCset[Name] = 3
			else
				pointCset[Name] = 2	
			end
		end
	end
	
	return true
end

function HandleOutset( Split, Player )
	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	local World = cRoot:Get():GetWorld()
	
	if cuboidOn[Name] == true then
	  if pointCset[Name] == 3 then
	     local altSize = 1
       if #Split >= 2 then
		 altSize = tonumber(Split[2])
		 if altSize < 1 then altSize = 1 end
       end
	  
	    if (points[Name]["1"]["x"]<points[Name]["2"]["x"]) then
	       points[Name]["1"]["x"] = points[Name]["1"]["x"] - altSize
	       points[Name]["2"]["x"] = points[Name]["2"]["x"] + altSize
	    else
	       points[Name]["1"]["x"] = points[Name]["1"]["x"] + altSize
	       points[Name]["2"]["x"] = points[Name]["2"]["x"] - altSize
      	end
     
      	if (points[Name]["1"]["z"]<points[Name]["2"]["z"]) then
	       points[Name]["1"]["z"] = points[Name]["1"]["z"] - altSize
	       points[Name]["2"]["z"] = points[Name]["2"]["z"] + altSize
	    else
         	points[Name]["1"]["z"] = points[Name]["1"]["z"] + altSize
	    	points[Name]["2"]["z"] = points[Name]["2"]["z"] - altSize
      	end
    
      	if (points[Name]["1"]["y"]<points[Name]["2"]["y"]) then
        	points[Name]["1"]["y"] = points[Name]["1"]["y"] - altSize
        	if points[Name]["1"]["y"]<0 then points[Name]["1"]["y"] = 0 end
	    	points[Name]["2"]["y"] = points[Name]["2"]["y"] + altSize
        	if points[Name]["2"]["y"]>127 then points[Name]["2"]["y"] = 127 end
	    else
	    	points[Name]["1"]["y"] = points[Name]["1"]["y"] + altSize
       		if points[Name]["1"]["y"]>127 then points[Name]["1"]["y"] = 127 end
         	points[Name]["2"]["y"] = points[Name]["2"]["y"] - altSize
	    	if points[Name]["2"]["y"]<0 then points[Name]["2"]["y"] = 0 end
      	end
      
      		cubeSize = getCuboidSize( Name )
			Server:SendMessage( cChatColor.Blue .. "Cuboid expanded to " .. cubeSize .. " blocks.", Player )
    	else
		  	Server:SendMessage( cChatColor.Red .. "Must select a cuboid first!", Player )
		end
	end
	
	return true
end

function HandleInset( Split, Player )

	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	local World = cRoot:Get():GetWorld()
	
	if cuboidOn[Name] == true then
	  if pointCset[Name] == 3 then
	     local altSize = 1
       if #Split >= 2 then
		    altSize = tonumber(Split[2])
		    if altSize < 1 then altSize = 1 end
       end
	     
       min = getMinimum(points[Name])
	   max = getMaximum(points[Name])
	
       if (points[Name]["1"]["x"]<points[Name]["2"]["x"]) then
	       if (max["x"]-min["x"]>=altSize) then 
            points[Name]["1"]["x"] = points[Name]["1"]["x"] + altSize end
	       if (max["x"]-min["x"]>=(altSize*2)) then
	          points[Name]["2"]["x"] = points[Name]["2"]["x"] - altSize end
	     else
	       if (max["x"]-min["x"]>=altSize) then
            points[Name]["1"]["x"] = points[Name]["1"]["x"] - altSize end
	       if (max["x"]-min["x"]>=(altSize*2)) then
            points[Name]["2"]["x"] = points[Name]["2"]["x"] + altSize end
        end
     
      if (points[Name]["1"]["z"]<points[Name]["2"]["z"]) then
         if (max["z"]-min["z"]>=altSize) then
	          points[Name]["1"]["z"] = points[Name]["1"]["z"] + altSize end
	       if (max["z"]-min["z"]>=(altSize*2)) then
            points[Name]["2"]["z"] = points[Name]["2"]["z"] - altSize end
	    else
	       if (max["z"]-min["z"]>=altSize) then
            points[Name]["1"]["z"] = points[Name]["1"]["z"] - altSize end
	       if (max["z"]-min["z"]>=(altSize*2)) then
            points[Name]["2"]["z"] = points[Name]["2"]["z"] + altSize end
      end
    
      if (points[Name]["1"]["y"]<points[Name]["2"]["y"]) then
         if (max["y"]-min["y"]>=altSize) then
            points[Name]["1"]["y"] = points[Name]["1"]["y"] + altSize end
         if (max["y"]-min["y"]>=(altSize*2)) then
            points[Name]["2"]["y"] = points[Name]["2"]["y"] - altSize end
	   else
         if (max["y"]-min["y"]>=altSize) then
            points[Name]["1"]["y"] = points[Name]["1"]["y"] - altSize end
	       if (max["y"]-min["y"]>=(altSize*2)) then
            points[Name]["2"]["y"] = points[Name]["2"]["y"] + altSize end
     end
        
      cubeSize = getCuboidSize( Name )
			Server:SendMessage( cChatColor.Blue .. "Cuboid contracted to " .. cubeSize .. " block(s).", Player )
    else
		  Server:SendMessage( cChatColor.Red .. "Must select a cuboid first!", Player )
		end
	end
	
	return true
end

function HandleExpand( Split, Player )

	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	local World = cRoot:Get():GetWorld()
	
	if cuboidOn[Name] == true then
	  if pointCset[Name] == 3 then
	     local altSize = 1
       if #Split >= 2 then
		    altSize = tonumber(Split[2])
		    if altSize < 1 then altSize = 1 end
       end
	  
	     min = getMinimum(points[Name])
		   max = getMaximum(points[Name])
       
	     local pitch = Player:GetPitch()
	     if pitch < - 60 then
	         --Up
	         if max["y"]+altSize > 127 then altSize = 127-max["y"] end
	         if points[Name]["1"]["y"]<points[Name]["2"]["y"] then
	           points[Name]["2"]["y"] = points[Name]["2"]["y"] + altSize
	         else
	           points[Name]["1"]["y"] = points[Name]["1"]["y"] + altSize
	         end
	     elseif pitch > 60 then
	         --Down
	         if max["y"]-altSize < 0 then altSize = max["y"] end
	         if points[Name]["1"]["y"]>points[Name]["2"]["y"] then
	           points[Name]["2"]["y"] = points[Name]["2"]["y"] - altSize
	         else
	           points[Name]["1"]["y"] = points[Name]["1"]["y"] - altSize
	         end
       else
          local degrees = Player:GetRotation()
	        if degrees < -135 then degrees = 360 + degrees end
	
	        if (-45 <= degrees and degrees < 45) then
    	       -- North
    	       if points[Name]["1"]["z"]<points[Name]["2"]["z"] then
	             points[Name]["2"]["z"] = points[Name]["2"]["z"] + altSize
	           else
	             points[Name]["1"]["z"] = points[Name]["1"]["z"] + altSize
	           end
          elseif (45 <= degrees and degrees < 135) then
    	       -- East
    	       if points[Name]["1"]["x"]>points[Name]["2"]["x"] then
	             points[Name]["2"]["x"] = points[Name]["2"]["x"] - altSize
	           else
	             points[Name]["1"]["x"] = points[Name]["1"]["x"] - altSize
	           end
          elseif (135 <= degrees and degrees < 225) then
    	       -- South
    	       if points[Name]["1"]["z"]>points[Name]["2"]["z"] then
	             points[Name]["2"]["z"] = points[Name]["2"]["z"] - altSize
	           else
	             points[Name]["1"]["z"] = points[Name]["1"]["z"] - altSize
	           end
          elseif ((225 <= degrees and degrees < 315) or (-135 <= degrees and degrees < -45)) then
    	       -- West
    	       if points[Name]["1"]["x"]<points[Name]["2"]["x"] then
	             points[Name]["2"]["x"] = points[Name]["2"]["x"] + altSize
	           else
	             points[Name]["1"]["x"] = points[Name]["1"]["x"] + altSize
	           end
          end
      end
      
      cubeSize = getCuboidSize( Name )
			Server:SendMessage( cChatColor.Blue .. "Cuboid expanded to " .. cubeSize .. " blocks.", Player )
    else
		  Server:SendMessage( cChatColor.Red .. "Must select a cuboid first!", Player )
		end
	end
	
	return true
end

function HandleContract( Split, Player )
	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	local World = cRoot:Get():GetWorld()
	
	if cuboidOn[Name] == true then
	  if pointCset[Name] == 3 then
	     local altSize = 1
       if #Split >= 2 then
		    altSize = tonumber(Split[2])
		    if altSize < 1 then altSize = 1 end
       end
	  
	     min = getMinimum(points[Name])
		   max = getMaximum(points[Name])
       
	     local pitch = Player:GetPitch()
	     if pitch < - 60 then
	         --Up
	         if max["y"]-altSize < 0 then altSize = max["y"] end
	         if points[Name]["1"]["y"]<points[Name]["2"]["y"] then
	           points[Name]["2"]["y"] = points[Name]["2"]["y"] - altSize
	         else
	           points[Name]["1"]["y"] = points[Name]["1"]["y"] - altSize
	         end
	     elseif pitch > 60 then
	         --Down
	         if min["y"]+altSize >max["y"] then altSize = max["y"]-min["y"] end
	         if points[Name]["1"]["y"]>points[Name]["2"]["y"] then
	           points[Name]["2"]["y"] = points[Name]["2"]["y"] + altSize
	         else
	           points[Name]["1"]["y"] = points[Name]["1"]["y"] + altSize
	         end
       else
          local degrees = Player:GetRotation()
	        if degrees < -135 then degrees = 360 + degrees end
	
	        if (-45 <= degrees and degrees < 45) then
    	       -- North
    	       if max["z"]-altSize < 0 then altSize = max["z"] end
    	       if points[Name]["1"]["z"]<points[Name]["2"]["z"] then
	             points[Name]["2"]["z"] = points[Name]["2"]["z"] - altSize
	           else
	             points[Name]["1"]["z"] = points[Name]["1"]["z"] - altSize
	           end
          elseif (45 <= degrees and degrees < 135) then
    	       -- East
    	       if min["x"]+altSize >max["x"] then altSize = max["x"]-min["x"] end
    	       if points[Name]["1"]["x"]>points[Name]["2"]["x"] then
	             points[Name]["2"]["x"] = points[Name]["2"]["x"] + altSize
	           else
	             points[Name]["1"]["x"] = points[Name]["1"]["x"] + altSize
	           end
          elseif (135 <= degrees and degrees < 225) then
    	       -- South
    	       if min["z"]+altSize >max["z"] then altSize = max["z"]-min["z"] end
    	       if points[Name]["1"]["z"]>points[Name]["2"]["z"] then
	             points[Name]["2"]["z"] = points[Name]["2"]["z"] + altSize
	           else
	             points[Name]["1"]["z"] = points[Name]["1"]["z"] + altSize
	           end
          elseif ((225 <= degrees and degrees < 315) or (-135 <= degrees and degrees < -45)) then
    	       -- West
    	       if max["x"]-altSize < 0 then altSize = max["x"] end
             if points[Name]["1"]["x"]<points[Name]["2"]["x"] then
	             points[Name]["2"]["x"] = points[Name]["2"]["x"] - altSize
	           else
	             points[Name]["1"]["x"] = points[Name]["1"]["x"] - altSize
	           end
          end
      end
      
      cubeSize = getCuboidSize( Name )
			Server:SendMessage( cChatColor.Blue .. "Cuboid contracted to " .. cubeSize .. " blocks.", Player )
    else
		  Server:SendMessage( cChatColor.Red .. "Must select a cuboid first!", Player )
		end
	end
	
	return true
end

function HandleShift ( Split, Player)
  local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	local World = cRoot:Get():GetWorld()
	
	if cuboidOn[Name] == true then
	  if pointCset[Name] == 3 then
	     local altMove = 1
       if #Split >= 2 then
		    altMove = tonumber(Split[2])
		    if altMove < 1 then altMove = 1 end
       end
       
       min = getMinimum(points[Name])
		   max = getMaximum(points[Name])
       
	     local pitch = Player:GetPitch()
	     if pitch < - 60 then
	         --Up
	         if max["y"]+altMove > 127 then altMove = 127-max["y"] end
	         points[Name]["1"]["y"] = points[Name]["1"]["y"] + altMove
	         points[Name]["2"]["y"] = points[Name]["2"]["y"] + altMove
	     elseif pitch > 60 then
	         --Down
	         if min["y"]-altMove < 0 then altMove = min["y"] end
	         points[Name]["1"]["y"] = points[Name]["1"]["y"] - altMove
	         points[Name]["2"]["y"] = points[Name]["2"]["y"] - altMove
       else
          local degrees = Player:GetRotation()
	        if degrees < -135 then degrees = 360 + degrees end
	
	        if (-45 <= degrees and degrees < 45) then
    	       -- North
    	       points[Name]["1"]["z"] = points[Name]["1"]["z"] + altMove
	           points[Name]["2"]["z"] = points[Name]["2"]["z"] + altMove
          elseif (45 <= degrees and degrees < 135) then
    	       -- East
    	       points[Name]["1"]["x"] = points[Name]["1"]["x"] - altMove
	           points[Name]["2"]["x"] = points[Name]["2"]["x"] - altMove
          elseif (135 <= degrees and degrees < 225) then
    	       -- South
    	       points[Name]["1"]["z"] = points[Name]["1"]["z"] - altMove
	           points[Name]["2"]["z"] = points[Name]["2"]["z"] - altMove
          elseif ((225 <= degrees and degrees < 315) or (-135 <= degrees and degrees < -45)) then
    	       -- West
    	       points[Name]["1"]["x"] = points[Name]["1"]["x"] + altMove
	           points[Name]["2"]["x"] = points[Name]["2"]["x"] + altMove
          end
      end
      
      Server:SendMessage( cChatColor.Blue .. "Cuboid shifted by " .. altMove .. " block(s).", Player )
    end
  end
  
  return true
end

function HandleCeil( Split, Player )

	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	local World = cRoot:Get():GetWorld()
	
	if cuboidOn[Name] == true then
		
		if pointCset[Name] == 3 then
		  if points[Name]["1"]["y"] >= points[Name]["2"]["y"] then
         points[Name]["1"]["y"] = 127
         Server:SendMessage( cChatColor.Green .. "Point A set: ".. cChatColor.White .." X:" ..points[Name]["1"]["x"].. " Y:" ..points[Name]["1"]["y"].. " Z:" ..points[Name]["1"]["z"].. "", Player )
      else
         points[Name]["2"]["y"] = 127
         Server:SendMessage( cChatColor.Green .. "Point B set: ".. cChatColor.White .." X:" ..points[Name]["2"]["x"].. " Y:" ..points[Name]["2"]["y"].. " Z:" ..points[Name]["2"]["z"].. "", Player )
      end
      
      cubeSize = getCuboidSize(Name)
		  Server:SendMessage( cChatColor.Blue .. "Cuboid Ready! (Size: " .. cubeSize .. " blocks)", Player )
		else
		  Server:SendMessage( cChatColor.Red .. "Must select a cuboid first!", Player )
		end

	end
	
	return true
end

function HandleFloor( Split, Player )

	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	local World = cRoot:Get():GetWorld()
	
	if cuboidOn[Name] == true then
		
		if pointCset[Name] == 3 then
		  if points[Name]["1"]["y"] >= points[Name]["2"]["y"] then
         points[Name]["2"]["y"] = 0
         Server:SendMessage( cChatColor.Green .. "Point B set: ".. cChatColor.White .." X:" ..points[Name]["2"]["x"].. " Y:" ..points[Name]["2"]["y"].. " Z:" ..points[Name]["2"]["z"].. "", Player )
      else
         points[Name]["1"]["y"] = 0
         Server:SendMessage( cChatColor.Green .. "Point A set: ".. cChatColor.White .." X:" ..points[Name]["1"]["x"].. " Y:" ..points[Name]["1"]["y"].. " Z:" ..points[Name]["1"]["z"].. "", Player )
      end
      
      cubeSize = getCuboidSize(Name)
		  Server:SendMessage( cChatColor.Blue .. "Cuboid Ready! (Size: " .. cubeSize .. " blocks)", Player )
		else
		  Server:SendMessage( cChatColor.Red .. "Must select a cuboid first!", Player )
		end
		
	end
	
	return true
end

function HandlePlace( Split, Player )

	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	local World = cRoot:Get():GetWorld()
	local fillBlock, fillMeta = cuboidBlock(Split[2])
	
	if cuboidOn[Name] == true then
		
		IncrementUndoGroup( Name )
		
		X = mFloor(Player:GetPosX())
		Y = mFloor(Player:GetPosY())
		Z = mFloor(Player:GetPosZ())
			
		if Y ~= -1 then
		CuboidBlockPlace(X, Y, Z, fillBlock, 0, Name)
			Server:SendMessage( cChatColor.Green .. "Block placed at: ".. cChatColor.White .." X:" ..X.. " Y:" ..Y.. " Z:" ..Z.. "", Player )					end
	end
	return true
end

function HandleBlockGet( Split, Player )

	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	local World = cRoot:Get():GetWorld()
	
	if cuboidOn[Name] == true then
		if pointCset[Name] == 1 then
			X = points[Name]["1"]["x"]
		  	Y = points[Name]["1"]["y"]
			Z = points[Name]["1"]["z"]
			
			Server = cRoot:Get():GetServer()
			World = cWorld:GetWorld()
		  	block = World:GetBlock(X, Y, Z)
			meta = World:GetBlockMeta(X, Y, Z)

			Server:SendMessage( cChatColor.Green .. "Material is: ".. cChatColor.White .." Block: (" ..block.. "(" ..meta.. "))", Player )
			
			if pointCset[Name] == 1 or pointCset[Name] == 3 or pointCset[Name] == 2 then
    			pointCset[Name] = 3
			else
				pointCset[Name] = 1
			end
		end
	end
	return true
end

function CuboidPlusPlugin:OnPlayerJoin( Player )
	Log("Cuboid: Player Join!")
	local Name = Player:GetName()
	HandlePlayerJoin(Name)
	return false
end

function CuboidPlusPlugin:OnBlockPlace( PacketData, Player )
	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	local World = cRoot:Get():GetWorld()
		
	if PacketData.m_ItemType == 280 then --Cuboiding!
		if cuboidOn[Name] == true then
			X = PacketData.m_PosX
			Y = PacketData.m_PosY
			Z = PacketData.m_PosZ
			
			if Y ~= -1 then
				Server:SendMessage( cChatColor.Green .. "Point B set: ".. cChatColor.White .." X:" ..X.. " Y:" ..Y.. " Z:" ..Z.. "", Player )
				points[Name]["2"]["x"] = X
				points[Name]["2"]["y"] = Y
				points[Name]["2"]["z"] = Z
				if pointCset[Name] == 1 or pointCset[Name] == 3 then
					cubeSize = getCuboidSize( Name )
					Server:SendMessage( cChatColor.Blue .. "Cuboid Ready! (Size: " .. cubeSize .. " blocks)", Player )
					pointCset[Name] = 3
				else
					pointCset[Name] = 2
				end
			end
		end
	elseif PacketData.m_ItemType == 352 then
		if colorOn[Name] == true then
			X = PacketData.m_PosX
			Y = PacketData.m_PosY
			Z = PacketData.m_PosZ
			
			World = cWorld:GetWorld()
			
			block = World:GetBlock(X, Y, Z)
			
			if block == 35 then
				
				meta = World:GetBlockMeta(X, Y, Z)
				color = metas[meta]
				
				if color >= 16 then
					new_color = 1
				else
					new_color = color + 1
				end
				
				IncrementUndoGroup( Name )
				CuboidBlockPlace(X, Y, Z, 35, colors[new_color], Name)
				
				if verbose then Log("Cuboid: " ..Name.. " changed cloth color: " ..meta.. " to " ..colors[new_color].. " @ X:" ..X.. " Y:" ..Y.. " Z:" ..Z.. "") end
			end
		end
		
	elseif PacketData.m_ItemType == 262 then --Painting!
    if cuboidOn[Name] == true then
      if userBrush[Name] ~= nil then
        local RayCast = cTracer( World )
        if (RayCast:Trace( Vector3f(Player:GetEyePosition()) , Player:GetLookVector(), userBrush[Name]["Range"] )) then
          bPos = {}
          bPos["x"] = RayCast.BlockHitPosition.x
          bPos["y"] = RayCast.BlockHitPosition.y
          bPos["z"] = RayCast.BlockHitPosition.z
          if userBrush[Name]["Active"] == "Set" then
            if userBrush[Name]["Shape"] == "Sphere" then
              Server:SendMessage( cChatColor.Red .. "Sphere", Player )
              HandleBrush_Sphere(bPos, Player)
            elseif userBrush[Name]["Shape"] == "Cube" then
              Server:SendMessage( cChatColor.Red .. "Cube", Player )
              HandleBrush_Cube(bPos, Player)
            end
          elseif userBrush[Name]["Active"] == "Smooth" then
            Server:SendMessage( cChatColor.Red .. userBrush[Name]["Brush"], Player )
            HandleBrush_Smooth(bPos, Player)
          elseif userBrush[Name]["Active"] == "Radial" then
            Server:SendMessage( cChatColor.Red .. userBrush[Name]["Brush"], Player )
            HandleBrush_Radial(bPos, Player)
          elseif userBrush[Name]["Active"] == "Drain" then
            Server:SendMessage( cChatColor.Red .. userBrush[Name]["Brush"], Player )
            HandleBrush_Drain(bPos, Player)
		  elseif userBrush[Name]["Active"] == "Paste" then
            Server:SendMessage( cChatColor.Red .. userBrush[Name]["Brush"], Player )
            userBrush[Name]["val_1"] = bPos["x"]
          	userBrush[Name]["val_2"] = bPos["y"]
          	userBrush[Name]["val_3"] = bPos["z"]
          	HandlePaste( {1,"brush"}, Player )
          elseif userBrush[Name]["Active"] == "PasteB" then
            Server:SendMessage( cChatColor.Red .. userBrush[Name]["Brush"], Player )
            userBrush[Name]["val_1"] = bPos["x"]
          	userBrush[Name]["val_2"] = bPos["y"]
          	userBrush[Name]["val_3"] = bPos["z"]
          	HandlePasteB( {1,"brush"}, Player )
          end
        end
      else
        Server:SendMessage( cChatColor.Red .. "No brush selected.", Player )
      end
    end	
  end

	return false
end

function CuboidPlusPlugin:OnBlockDig( PacketData, Player )	
  
	-- super axe code
	local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	local World = cRoot:Get():GetWorld()
	if PacketData.m_PosY ~= 0 then	
		Inv = Player:GetInventory()
		Itm = Inv:GetEquippedItem()
		Item = Itm.m_ItemID
    if Item == 280 then --Wand
        if cuboidOn[Name] == true then
			X = PacketData.m_PosX
			Y = PacketData.m_PosY
			Z = PacketData.m_PosZ
			  
			Server:SendMessage( cChatColor.Green .. "Point A set: ".. cChatColor.White .." X:" ..X.. " Y:" ..Y.. " Z:" ..Z.. "", Player )
			points[Name]["1"]["x"] = X
			points[Name]["1"]["y"] = Y
			points[Name]["1"]["z"] = Z
			if pointCset[Name] == 2 or pointCset[Name] == 3 then
				cubeSize = getCuboidSize( Name )
				Server:SendMessage( cChatColor.Blue .. "Cuboid Ready! (Size: " .. cubeSize .. " blocks)", Player )
				pointCset[Name] = 3
			else
				pointCset[Name] = 1
			end
		    return true
		end
	elseif (paintOn[Name] == true) and (Item ~= 0) then
		X = PacketData.m_PosX
		Y = PacketData.m_PosY
		Z = PacketData.m_PosZ
		
		Inv = Player:GetInventory()
		Itm = Inv:GetEquippedItem()
		Item = Itm.m_ItemID
			
		IncrementUndoGroup( Name )
		CuboidBlockPlace(X, Y, Z, Item, 0, Name)
	elseif (superaxe[Name] == true) and (Item == 270 or Item == 274 or Item == 278) then					
		X = PacketData.m_PosX
		Y = PacketData.m_PosY
		Z = PacketData.m_PosZ
		ent = World:DigBlock(X, Y, Z, cItem(278))	
	end
	end
	return false
end

--Brush Commands
--  Brush Configuration
--    ["Range"] -> Obvious
--  Brush Data Table
--    ["Brush"] -> Brush configuration handling
--    ["Active"] -> Actual brush type
--    ["Shape"] -> Shape of brush
--    ["Radius"] -> Distance from center
--    ["Block"] -> Primary block
--    ["Meta"]  -> Primary block meta
--    ["Block2"] -> Secondary block
--    ["Meta2"]  -> Secondary block meta
--    ["Solid"] -> 0=Hollow, 1=Solid
--    ["bLock"] -> Prevents user from changing the primary block
--    ["b2Lock"] -> Prevents user from changing the second block
--    ["sLock"] -> Prevents user from changing the shape
--    ["val_1"]  -> Generic configuration used by different things
--    ["val_2"]  -> Generic configuration used by different things
--    ["val_3"]  -> Generic configuration used by different things
--	  ["val"]	-> Generic configuration used for arrays
function HandleBrush(Split, Player)
  local Server = cRoot:Get():GetServer()
	local Name = Player:GetName()
	local World = cRoot:Get():GetWorld()
  
  if cuboidOn[Name] == true then
    if #Split>=2 then
      if Split[2] == "sphere" or Split[2] == "sp" then --Brush Shape
        if userBrush[Name]["sLock"] == false then
          userBrush[Name]["Shape"] = "Sphere"
          Server:SendMessage( cChatColor.Green .. "Brush shape set to "..userBrush[Name]["Shape"]..".", Player)
          return true
        else
          Server:SendMessage( cChatColor.Red .. "Brush ["..userBrush[Name]["Brush"].."] is a fixed shape.", Player)
        end
        return true 
      elseif Split[2] == "cube" then --Brush Shape
        if userBrush[Name]["sLock"] == false then
          userBrush[Name]["Shape"] = "Cube"
          Server:SendMessage( cChatColor.Green .. "Brush shape set to "..userBrush[Name]["Shape"]..".", Player)
          return true
        else
          Server:SendMessage( cChatColor.Red .. "Brush ["..userBrush[Name]["Brush"].."] is a fixed shape.", Player)  
        end
        return true
      elseif Split[2] == "radius" or Split[2] == "r" then --Brush Configuration
        if #Split>=3 then
          if Split[3]~=nil then
              userBrush[Name]["Radius"] = tonumber(Split[3])
              if userBrush[Name]["Radius"]<1 then userBrush[Name]["Radius"] = 1 end
              Server:SendMessage( cChatColor.Green .. "Brush radius set to "..userBrush[Name]["Radius"]..".",Player)
              return true
          end
        end
        Server:SendMessage( cChatColor.Red .. "Invalid brush size.", Player)
        return true
      elseif Split[2] == "range" or Split[2] == "rng" then --Brush Configuration
        if #Split>=3 then
          if Split[3]~=nil then
            userBrush[Name]["Range"] = tonumber(Split[3])
            if (userBrush[Name]["Range"] < 10) then userBrush[Name]["Range"] = 10 end
            if (userBrush[Name]["Range"] > 250) then userBrush[Name]["Range"] = 250 end
            Server:SendMessage( cChatColor.Green .. "Brush range set to " .. userBrush[Name]["Range"], Player)
          else
            Server:SendMessage( cChatColor.Red .. "Invalid brush range.", Player)
          end
        else
          userBrush[Name]["Range"] = defaultBRange
          Server:SendMessage( cChatColor.Green .. "Brush range returned to default", Player)
        end
        return true
      elseif Split[2] == "erase" or Split[2] == "er" then --Preconfigured brush
        userBrush[Name]["Brush"] = "Erase"
        userBrush[Name]["Active"] = "Set"
        userBrush[Name]["Shape"] = "Sphere"
        userBrush[Name]["Radius"] = 5
        userBrush[Name]["Block"] = 0
        userBrush[Name]["Meta"] = 0
        userBrush[Name]["Block2"] = -1
        userBrush[Name]["Meta2"] = -1
        userBrush[Name]["Solid"] = 1
        userBrush[Name]["bLock"] = true
        userBrush[Name]["b2Lock"] = false
        userBrush[Name]["sLock"] = false
        
        if #Split>=3 then
        	local fillBlock, fillMeta = cuboidBlock(Split[3])
		  	if fillBlock == nil then
				Server:SendMessage( cChatColor.Red .. "Invalid block ID. ( " .. fillBlock .. ")", Player )
			    return true
			else
			    userBrush[Name]["Block2"] = fillBlock
				userBrush[Name]["Meta2"] = fillMeta
		    end
		end
        
        Server:SendMessage( cChatColor.Green .. "Erase brush selected. ["..userBrush[Name]["Shape"].." -r"..userBrush[Name]["Radius"].."]", Player)
        return true
      elseif Split[2] == "set" or Split[2] == "fill" or Split[2] == "z" then --Preconfigured brush
        userBrush[Name]["Brush"] = "Set"
        userBrush[Name]["Active"] = "Set"
        userBrush[Name]["Shape"] = "Sphere"
        userBrush[Name]["Radius"] = 5
        userBrush[Name]["Block"] = 1
        userBrush[Name]["Meta"] = 0
        userBrush[Name]["Block2"] = -1
        userBrush[Name]["Meta2"] = -1
        userBrush[Name]["Solid"] = 1
        userBrush[Name]["bLock"] = false
        userBrush[Name]["b2Lock"] = true
        userBrush[Name]["sLock"] = false
        
        if #Split>=3 then
          local fillBlock, fillMeta = cuboidBlock(Split[3])
		      if fillBlock == nil then
			      Server:SendMessage( cChatColor.Red .. "Invalid block ID. ( " .. fillBlock .. ")", Player )
			      return true
			    else
			      userBrush[Name]["Block"] = fillBlock
				  userBrush[Name]["Meta"] = fillMeta
		      end
		    end
        
        Server:SendMessage( cChatColor.Green .. userBrush[Name]["Brush"] .. " brush selected. [" .. userBrush[Name]["Shape"].." -r"..userBrush[Name]["Radius"].." -b" .. userBrush[Name]["Block"]..":"..userBrush[Name]["Meta"] .. "]", Player)
        return true
      elseif Split[2] == "replace" or Split[2] == "rep" then --Preconfigured brush
        userBrush[Name]["Brush"] = "Replace"
        userBrush[Name]["Active"] = "Set"
        userBrush[Name]["Shape"] = "Sphere"
        userBrush[Name]["Radius"] = 5
        userBrush[Name]["Block"] = 1
        userBrush[Name]["Meta"] = 0
        userBrush[Name]["Block2"] = 0
        userBrush[Name]["Meta2"] = -1
        userBrush[Name]["Solid"] = 1
        userBrush[Name]["bLock"] = false
        userBrush[Name]["b2Lock"] = false
        userBrush[Name]["sLock"] = false
        
        if #Split>=3 then
          local fillBlock, fillMeta = cuboidBlock(Split[3])
		      if fillBlock == nil then
			      Server:SendMessage( cChatColor.Red .. "Invalid block ID. ( " .. fillBlock .. ")", Player )
			      return true
			    else
			      userBrush[Name]["Block"] = fillBlock
				  userBrush[Name]["Meta"] = fillMeta
		      end
		    end
		    
		    if #Split>=4 then
          local repBlock, repMeta = cuboidBlock(Split[4])
		      if repBlock == nil then
			      Server:SendMessage( cChatColor.Red .. "Invalid block ID. ( " .. repBlock .. ")", Player )
			      return true
			    else
			      userBrush[Name]["Block2"] = repBlock
				  userBrush[Name]["Meta2"] = repMeta
		      end
		    end
        
        Server:SendMessage( cChatColor.Green .. userBrush[Name]["Brush"] .. " brush selected. [" .. userBrush[Name]["Shape"].." -r"..userBrush[Name]["Radius"].." -b" .. userBrush[Name]["Block"]..":"..userBrush[Name]["Meta"].." -br" .. userBrush[Name]["Block2"]..":"..userBrush[Name]["Meta2"] .. "]", Player)
        return true
      elseif Split[2] == "smooth" or Split[2] == "sm" then --Preconfigured brush
        userBrush[Name]["Brush"] = "Smooth"
        userBrush[Name]["Active"] = "Smooth"
        userBrush[Name]["Shape"] = "Sphere"
        userBrush[Name]["Radius"] = 5
        userBrush[Name]["Block"] = 1
        userBrush[Name]["Meta"] = 0
        userBrush[Name]["Block2"] = 0
        userBrush[Name]["Meta2"] = -1
        userBrush[Name]["Solid"] = 1
        userBrush[Name]["bLock"] = true
        userBrush[Name]["b2Lock"] = true
        userBrush[Name]["sLock"] = true
        userBrush[Name]["val_1"] = 13
      
        Server:SendMessage( cChatColor.Green .. userBrush[Name]["Brush"] .. " brush selected. [" .. userBrush[Name]["Shape"].." -r"..userBrush[Name]["Radius"].." -b" .. userBrush[Name]["Block"]..":"..userBrush[Name]["Meta"].." -br" .. userBrush[Name]["Block2"]..":"..userBrush[Name]["Meta2"] .. "]", Player)
        return true
      elseif Split[2] == "lift" or Split[2] == "l" then --Preconfigured brush
        userBrush[Name]["Brush"] = "Lift"
        userBrush[Name]["Active"] = "Smooth"
        userBrush[Name]["Shape"] = "Sphere"
        userBrush[Name]["Radius"] = 5
        userBrush[Name]["Block"] = 1
        userBrush[Name]["Meta"] = 0
        userBrush[Name]["Block2"] = 0
        userBrush[Name]["Meta2"] = -1
        userBrush[Name]["Solid"] = 1
        userBrush[Name]["bLock"] = true
        userBrush[Name]["b2Lock"] = true
        userBrush[Name]["sLock"] = true
        userBrush[Name]["val_1"] = 13-5
      
        Server:SendMessage( cChatColor.Green .. userBrush[Name]["Brush"] .. " brush selected. [" .. userBrush[Name]["Shape"].." -r"..userBrush[Name]["Radius"].." -b" .. userBrush[Name]["Block"]..":"..userBrush[Name]["Meta"].." -br" .. userBrush[Name]["Block2"]..":"..userBrush[Name]["Meta2"] .. "]", Player)
        return true
      elseif Split[2] == "melt" or Split[2] == "m" then --Preconfigured brush
        userBrush[Name]["Brush"] = "Melt"
        userBrush[Name]["Active"] = "Smooth"
        userBrush[Name]["Shape"] = "Sphere"
        userBrush[Name]["Radius"] = 5
        userBrush[Name]["Block"] = 1
        userBrush[Name]["Meta"] = 0
        userBrush[Name]["Block2"] = 0
        userBrush[Name]["Meta2"] = -1
        userBrush[Name]["Solid"] = 1
        userBrush[Name]["bLock"] = true
        userBrush[Name]["b2Lock"] = true
        userBrush[Name]["sLock"] = true
        userBrush[Name]["val_1"] = 13+2
      
        Server:SendMessage( cChatColor.Green .. userBrush[Name]["Brush"] .. " brush selected. [" .. userBrush[Name]["Shape"].." -r"..userBrush[Name]["Radius"].." -b" .. userBrush[Name]["Block"]..":"..userBrush[Name]["Meta"].." -br" .. userBrush[Name]["Block2"]..":"..userBrush[Name]["Meta2"] .. "]", Player)
        return true
      elseif Split[2] == "over" or Split[2] == "o" then --Preconfigured brush
		userBrush[Name]["Brush"] = "Over"
        userBrush[Name]["Active"] = "Radial"
        userBrush[Name]["Shape"] = "Radial"
        userBrush[Name]["Radius"] = 5
        userBrush[Name]["Block"] = 1
        userBrush[Name]["Meta"] = 0
        userBrush[Name]["Block2"] = 0
        userBrush[Name]["Meta2"] = -1
        userBrush[Name]["Solid"] = 1
        userBrush[Name]["bLock"] = true
        userBrush[Name]["b2Lock"] = true
        userBrush[Name]["sLock"] = true
        userBrush[Name]["val_1"] = 0
        userBrush[Name]["val_2"] = 0
		
		if #Split>=3 then
			local fillBlock, fillMeta = cuboidBlock(Split[3])
			if fillBlock == nil then
				Server:SendMessage( cChatColor.Red .. "Invalid block ID. ( " .. fillBlock .. ")", Player )
			    return true
			else
			    userBrush[Name]["Block"] = fillBlock
				userBrush[Name]["Meta"] = fillMeta
		    end
		end
		
        Server:SendMessage( cChatColor.Green .. userBrush[Name]["Brush"] .. " brush selected. [" .. userBrush[Name]["Shape"].." -r"..userBrush[Name]["Radius"].." -b" .. userBrush[Name]["Block"]..":"..userBrush[Name]["Meta"].." -br" .. userBrush[Name]["Block2"]..":"..userBrush[Name]["Meta2"] .. "]", Player)
        return true
	elseif Split[2] == "top" or Split[2] == "t" then --Preconfigured brush
		userBrush[Name]["Brush"] = "Top"
        userBrush[Name]["Active"] = "Radial"
        userBrush[Name]["Shape"] = "Radial"
        userBrush[Name]["Radius"] = 5
        userBrush[Name]["Block"] = 1
        userBrush[Name]["Meta"] = 0
        userBrush[Name]["Block2"] = 0
        userBrush[Name]["Meta2"] = -1
        userBrush[Name]["Solid"] = 1
        userBrush[Name]["bLock"] = true
        userBrush[Name]["b2Lock"] = true
        userBrush[Name]["sLock"] = true
        userBrush[Name]["val_1"] = 1
        userBrush[Name]["val_2"] = 0
		
		if #Split>=3 then
			local fillBlock, fillMeta = cuboidBlock(Split[3])
			if fillBlock == nil then
				Server:SendMessage( cChatColor.Red .. "Invalid block ID. ( " .. fillBlock .. ")", Player )
			    return true
			else
			    userBrush[Name]["Block"] = fillBlock
				userBrush[Name]["Meta"] = fillMeta
		    end
		end
		
        Server:SendMessage( cChatColor.Green .. userBrush[Name]["Brush"] .. " brush selected. [" .. userBrush[Name]["Shape"].." -r"..userBrush[Name]["Radius"].." -b" .. userBrush[Name]["Block"]..":"..userBrush[Name]["Meta"].." -br" .. userBrush[Name]["Block2"]..":"..userBrush[Name]["Meta2"] .. "]", Player)
        return true
	elseif Split[2] == "drain" or Split[2] == "d" then --Preconfigured brush
        userBrush[Name]["Brush"] = "Drain"
        userBrush[Name]["Active"] = "Drain"
        userBrush[Name]["Shape"] = "Sphere"
        userBrush[Name]["Radius"] = 5
        userBrush[Name]["Block"] = 1
        userBrush[Name]["Meta"] = 0
        userBrush[Name]["Block2"] = 0
        userBrush[Name]["Meta2"] = -1
        userBrush[Name]["Solid"] = 1
        userBrush[Name]["bLock"] = true
        userBrush[Name]["b2Lock"] = true
        userBrush[Name]["sLock"] = true
      
        Server:SendMessage( cChatColor.Green .. userBrush[Name]["Brush"] .. " brush selected. [" .. userBrush[Name]["Shape"].." -r"..userBrush[Name]["Radius"].." -b" .. userBrush[Name]["Block"]..":"..userBrush[Name]["Meta"].." -br" .. userBrush[Name]["Block2"]..":"..userBrush[Name]["Meta2"] .. "]", Player)
        return true
      elseif Split[2] == "paste" or Split[2] == "p" then --Preconfigured brush
        userBrush[Name]["Brush"] = "Paste"
        userBrush[Name]["Active"] = "Paste"
        userBrush[Name]["Shape"] = "Paste"
        userBrush[Name]["Radius"] = 5
        userBrush[Name]["Block"] = 1
        userBrush[Name]["Meta"] = 0
        userBrush[Name]["Block2"] = 0
        userBrush[Name]["Meta2"] = -1
        userBrush[Name]["Solid"] = 1
        userBrush[Name]["bLock"] = true
        userBrush[Name]["b2Lock"] = true
        userBrush[Name]["sLock"] = true
        userBrush[Name]["val_1"] = 0
        userBrush[Name]["val_2"] = -1
        userBrush[Name]["val_3"] = 0
      
        Server:SendMessage( cChatColor.Green .. userBrush[Name]["Brush"] .. " brush selected.", Player)
        return true
      elseif Split[2] == "pasteb" or Split[2] == "pb" then --Preconfigured brush
        userBrush[Name]["Brush"] = "PasteB"
        userBrush[Name]["Active"] = "PasteB"
        userBrush[Name]["Shape"] = "PasteB"
        userBrush[Name]["Radius"] = 5
        userBrush[Name]["Block"] = 1
        userBrush[Name]["Meta"] = 0
        userBrush[Name]["Block2"] = 0
        userBrush[Name]["Meta2"] = -1
        userBrush[Name]["Solid"] = 1
        userBrush[Name]["bLock"] = true
        userBrush[Name]["b2Lock"] = true
        userBrush[Name]["sLock"] = true
        userBrush[Name]["val_1"] = 0
        userBrush[Name]["val_2"] = -1
        userBrush[Name]["val_3"] = 0
      
        Server:SendMessage( cChatColor.Green .. userBrush[Name]["Brush"] .. " brush selected.", Player)
        return true
      end
      
      --Made it this far. Might as well check if it's a number
      if userBrush[Name]["bLock"]==false then
        local fillBlock, fillMeta = cuboidBlock(Split[2])
		if fillBlock ~= nil then
			userBrush[Name]["Block"] = fillBlock
			userBrush[Name]["Meta"] = fillMeta
		    
		    if #Split>=3 then
				local fillBlock, fillMeta = cuboidBlock(Split[3])
		        if fillBlock == nil then
					Server:SendMessage( cChatColor.Red .. "Invalid block ID. ( " .. fillBlock .. ")", Player )
					return true
			    else
					userBrush[Name]["Block"] = fillBlock
					userBrush[Name]["Meta"] = fillMeta
					Server:SendMessage( cChatColor.Green .. "Brush block set to " ..userBrush[Name]["Block"]..":"..userBrush[Name]["Meta"].." & " ..userBrush[Name]["Block2"]..":"..userBrush[Name]["Meta2"].. ".", Player)
				end
			end
			Server:SendMessage( cChatColor.Green .. "Brush block set to " ..userBrush[Name]["Block"]..":"..userBrush[Name]["Meta"].. ".", Player)
			return true
        end
      end
    end
  end
  return true
end

function HandleBrush_Sphere(pos, Player)
	
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	local radius = userBrush[Name]["Radius"]
	local fillBlock = userBrush[Name]["Block"]
 	local fillMeta = userBrush[Name]["Meta"]
	local replaceBlock = userBrush[Name]["Block2"]
	local replaceMeta = userBrush[Name]["Meta2"]
	local fill = userBrush[Name]["Solid"]
	
	IncrementUndoGroup( Name )
	
	local xMin = pos["x"]-radius
	local xMax = pos["x"]+radius
	local yMin = pos["z"]-radius --reversed z/y because... idk. it works.
	local yMax = pos["z"]+radius
	local zMin = pos["y"]-radius
	local zMax = pos["y"]+radius
	local count = 0
	
	local xpow
	local ypow
	local zpow
	
	local xAdjust = pos["x"]*2
	local tmpI = 0
	
	i = xMin
	while i <= pos["x"] do
	  xpow = mPow(i-pos["x"], 2)
		j = yMin
		while j <= yMax do
		  ypow = mPow(j-pos["z"], 2)
			k = zMin
			while k <= zMax do
				diff = mSqrt( xpow + ypow + mPow(k-pos["y"], 2) )
				tmpI = xAdjust-i
				if diff < radius+0.5 and ( fill == 1 or diff > radius-0.5 ) then
					if replaceBlock == -1 then
						CuboidBlockPlace(i, k, j, fillBlock, fillMeta, Name)
						CuboidBlockPlace(tmpI, k, j, fillBlock, fillMeta, Name)
					else
						if (World:GetBlock(i, k, j) == replaceBlock) and (replaceMeta == -1 or World:GetBlockMeta(i, k, j) == replaceMeta) then
							CuboidBlockPlace(i, k, j, fillBlock, fillMeta, Name)
						end
						if (World:GetBlock(tmpI, k, j) == replaceBlock) and (replaceMeta == -1 or World:GetBlockMeta(tmpI, k, j) == replaceMeta) then
							CuboidBlockPlace(tmpI, k, j, fillBlock, fillMeta, Name)
						end
					end
				end
				k = k + 1
			end
			j = j + 1
		end
		i = i + 1
	end
	
	Server:SendMessage(cChatColor.Green .."x"..pos["x"].." y"..pos["z"].." z"..pos["y"].." c"..count, Player)
  return true
end

function HandleBrush_Cube(pos, Player)
	
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	local radius = userBrush[Name]["Radius"]
	local fillBlock = userBrush[Name]["Block"]
	local fillMeta = userBrush[Name]["Meta"]
	local replaceBlock = userBrush[Name]["Block2"]
	local replaceMeta = userBrush[Name]["Meta2"]
 	local fill = userBrush[Name]["Solid"]
	
	IncrementUndoGroup( Name )
	
  	local xMin = pos["x"]-radius
	local xMax = pos["x"]+radius
	local yMin = pos["y"]-radius
	local yMax = pos["y"]+radius
	local zMin = pos["z"]-radius
	local zMax = pos["z"]+radius
	count = 0
	
	if yMin<0 then yMin = 0 end
	if yMax > 127 then yMax = 127 end
	
	x = xMin
	while x <= xMax do
		y = yMin
		while y <= yMax do
			z = zMin
			while z <= zMax do
				if replaceBlock == -1 then
          			CuboidBlockPlace(x, y, z, fillBlock, fillMeta, Name)
        		else
          			if (World:GetBlock(x, y, z) == replaceBlock) and (replaceMeta == -1 or World:GetBlockMeta(x, y, z) == replaceMeta) then
            			CuboidBlockPlace(x, y, z, fillBlock, fillMeta, Name)
          			end
        		end
				z = z + 1
			end
			y = y + 1
		end
		x = x + 1
	end
	
  return true
end

function HandleBrush_Radial( pos, Player )
	
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	local radius = userBrush[Name]["Radius"]
	local fillBlock = userBrush[Name]["Block"]
	local fillMeta = userBrush[Name]["Meta"]
	local replaceBlock = userBrush[Name]["Block2"]
	local replaceMeta = userBrush[Name]["Meta2"]
 	local fill = userBrush[Name]["Solid"]
	
	IncrementUndoGroup( Name )
	
	local xMin = pos["x"]-radius
	local xMax = pos["x"]+radius
	local yMin = pos["y"]
	local yMax = pos["y"]
	local zMin = pos["z"]-radius
	local zMax = pos["z"]+radius
	
	count = 0
	i = xMin
	while i <= xMax do
		j = zMin
		while j <= zMax do
			diff = mSqrt( mPow(i-pos["x"], 2) + mPow(j-pos["z"], 2) )
			if diff < radius+0.5 then
				--Start from mouse position and find a solid block.
        		y = pos["y"]
       			while (y>0) and World:GetBlock(i, y, j)==0 do
        			y = y - 1
        		end
        
        		if (y>0) then
          			--Must have been found. place blocks.
          			CuboidBlockPlace(i, y+userBrush[Name]["val_1"], j, fillBlock, fillMeta, Name)
        		end
			end
			j = j + 1
		end
		i = i + 1
	end
	pointCset[Name] = 0
	return true
end

function HandleBrush_Smooth(pos, Player)
	
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	local radius = userBrush[Name]["Radius"]
	local fillBlock = userBrush[Name]["Block"]
 	local fillMeta = userBrush[Name]["Meta"]
	local replaceBlock = userBrush[Name]["Block2"]
	local replaceMeta = userBrush[Name]["Meta2"]
	local fill = userBrush[Name]["Solid"]
	
	IncrementUndoGroup( Name )
	
	xMin = pos["x"]-radius
	xMax = pos["x"]+radius
	yMin = pos["z"]-radius --reversed z/y because... idk. it works.
	yMax = pos["z"]+radius
	zMin = pos["y"]-radius
	zMax = pos["y"]+radius
	count = 0
	
	local xpow
	local ypow
	local zpow
	
	i = xMin
	while i <= xMax do
	  xpow = mPow(i-pos["x"], 2)
		j = yMin
		while j <= yMax do
		  ypow = mPow(j-pos["z"], 2)
			k = zMin
			while k <= zMax do
				diff = mSqrt( xpow + ypow + mPow(k-pos["y"], 2) )
				if diff < radius+0.5 and ( fill == 1 or diff > radius-0.5 ) then
					bSolid = 0
					for x=-1, 1, 1 do
						for y=-1, 1, 1 do
							for z=-1, 1, 1 do
								if (World:GetBlock(i+x, k+y, j+z)>0) then
									bSolid = bSolid + 1
								end
							end
						end
					end
          
					if (bSolid>userBrush[Name]["val_1"]) then
						CuboidBlockPlace(i, k, j, 1, 0, Name)
					else
						CuboidBlockPlace(i, k, j, 0, 0, Name)
					end
				end
				k = k + 1
			end
			j = j + 1
		end
		i = i + 1
	end
	
	Server:SendMessage(cChatColor.Green .."x"..pos["x"].." y"..pos["z"].." z"..pos["y"].." c"..count, Player)
  return true
end

function HandleBrush_Drain(pos, Player)
	local Server = cRoot:Get():GetServer()
	local World = cRoot:Get():GetWorld()
	local Name = Player:GetName()
	
	local radius = userBrush[Name]["Radius"]
	local fill = userBrush[Name]["Solid"]
	
	IncrementUndoGroup( Name )
	
	local xMin = pos["x"]-radius
	local xMax = pos["x"]+radius
	local yMin = pos["z"]-radius --reversed z/y because... idk. it works.
	local yMax = pos["z"]+radius
	local zMin = pos["y"]-radius
	local zMax = pos["y"]+radius
	local count = 0
	
	local xpow
	local ypow
	local zpow
	
	local xAdjust = pos["x"]*2
	local tmpI = 0
	
	i = xMin
	while i <= pos["x"] do
	  xpow = mPow(i-pos["x"], 2)
		j = yMin
		while j <= yMax do
		  ypow = mPow(j-pos["z"], 2)
			k = zMin
			while k <= zMax do
				diff = mSqrt( xpow + ypow + mPow(k-pos["y"], 2) )
				tmpI = xAdjust-i
				if diff < radius+0.5 and ( fill == 1 or diff > radius-0.5 ) then
					if (World:GetBlock(i,k,j)>=8) and (World:GetBlock(i,k,j)<=11) then
						CuboidBlockPlace(i, k, j, 0, 0, Name)
					end
					if (World:GetBlock(tmpI,k,j)>=8) and (World:GetBlock(tmpI,k,j)<=11) then
						CuboidBlockPlace(tmpI, k, j, 0, 0, Name)
					end
				end
				k = k + 1
			end
			j = j + 1
		end
		i = i + 1
	end
	Server:SendMessage(cChatColor.Green .."x"..pos["x"].." y"..pos["z"].." z"..pos["y"].." c"..count, Player)
  return true
end

--Check if a block id is solid
function GetSolid(Id)
  return true
end

-- used for cuboid selections
function getMinimum(points)
	newPoints = {}
	newPoints["x"] = mMin(points["1"]["x"], points["2"]["x"])
	newPoints["y"] = mMin(points["1"]["y"], points["2"]["y"])
	newPoints["z"] = mMin(points["1"]["z"], points["2"]["z"])
	return newPoints
end

-- used for cuboid selections
function getMaximum(points)	
	newPoints = {}
	newPoints["x"] = mMax(points["1"]["x"], points["2"]["x"])
	newPoints["y"] = mMax(points["1"]["y"], points["2"]["y"])
	newPoints["z"] = mMax(points["1"]["z"], points["2"]["z"])	
	return newPoints	
end

-- copys a table and all subtables (taken from a random site)
function DeepCopy(t)
  if type(t) ~= 'table' then return t end
  local mt = getmetatable(t)
  local res = {}
  for k,v in pairs(t) do
    if type(v) == 'table' then
      v = DeepCopy(v)
    end
    res[k] = v
  end
  setmetatable(res,mt)
  return res
end

-- used for cuboid size
function getCuboidSize( Name )
  min = getMinimum(points[Name])
	max = getMaximum(points[Name])
		
	minX = min["x"]
	minY = min["y"]
	minZ = min["z"]
		
	maxX = max["x"]
	maxY = max["y"]
	maxZ = max["z"]
  
  cubeSize = (1+maxX-minX) * (1+maxY-minY) * (1+maxZ-minZ)
  return cubeSize
end

-- used for compass
function round(num, idp)
  local mult = 10^(idp or 0)
  return mFloor(num * mult + 0.5) / mult
end

Plugin = CuboidPlusPlugin:new()
cRoot:Get():GetPluginManager():AddPlugin( Plugin )
cRoot:Get():GetServer():SendMessage("CuboidPlus Reloaded.")
