t.MakeWedge=function(g,X,m,f)return(game:GetService("\084\101\114\114\097\105\110")):AutoWedgeCell(g,X,m)end t.SelectTerrainRegion=function(g,X,m,f)local E=(game:GetService("\087\111\114\107\115\112\097\099\101")):FindFirstChild("\084\101\114\114\097\105\110")if not E then return end assert(g)assert(X)if not type(g)=="\082\101\103\105\111\110\051"then error("\114\101\103\105\111\110\084\111\083\101\108\101\099\116 \040\102\105\114\115\116 \097\114\103\041\044 \115\104\111\117\108\100 \098\101 \111\102 \116\121\112\101 \082\101\103\105\111\110\051\044 \098\117\116 \105\115 \116\121\112\101",type(g))end if not type(X)=="\066\114\105\099\107\067\111\108\111\114"then error("\099\111\108\111\114 \040\115\101\099\111\110\100 \097\114\103\041\044 \115\104\111\117\108\100 \098\101 \111\102 \116\121\112\101 \066\114\105\099\107\067\111\108\111\114\044 \098\117\116 \105\115 \116\121\112\101",type(X))end local A=E.GetCell local o=E.WorldToCellPreferSolid local n=E.CellCenterToWorld local r=Enum.CellMaterial.Empty local b=Instance.new("\077\111\100\101\108")b.Name="\083\101\108\101\099\116\105\111\110\067\111\110\116\097\105\110\101\114"b.Archivable=false if f then b.Parent=f else b.Parent=game:GetService("\087\111\114\107\115\112\097\099\101")end local s=nil local t=nil local i=0 local k=nil local V={}local W={}local p=Instance.new("\080\097\114\116")p.Name="\083\101\108\101\099\116\105\111\110\080\097\114\116"p.Transparency=1 p.Anchored=true p.Locked=true p.CanCollide=false p.Size=Vector3.new(4.2,4.2,4.2)local B=Instance.new("\083\101\108\101\099\116\105\111\110\066\111\120")local function u(g)local X=(g.CFrame.p-g.Size/2)+Vector3.new(2,2,2)local m=o(E,X)local f=(g.CFrame.p+g.Size/2)-Vector3.new(2,2,2)local A=o(E,f)local n=Vector3int16.new(A.x,A.y,A.z)local r=Vector3int16.new(m.x,m.y,m.z)return Region3int16.new(r,n)end function createAdornment(g)local X=nil local m=nil if#W>0 then X=W[1].part m=W[1].box table.remove(W,1)m.Visible=true else X=p:Clone()X.Archivable=false m=B:Clone()m.Archivable=false m.Adornee=X m.Parent=b m.Adornee=X m.Parent=b end if g then m.Color=g end return X,m end function cleanUpAdornments()for g,X in pairs(V)do if X.KeepAlive~=t then X.SelectionBox.Visible=false table.insert(W,{part=X.SelectionPart;box=X.SelectionBox})V[g]=nil end end end function incrementAliveCounter()i=i+1 if i>1000000 then i=0 end return i end function adornFullCellsInRegion(g,X)local m=(g.CFrame.p-g.Size/2)+Vector3.new(2,2,2)local f=(g.CFrame.p+g.Size/2)-Vector3.new(2,2,2)local b=o(E,m)local s=o(E,f)t=incrementAliveCounter()for g=b.y,s.y,1 do for m=b.z,s.z,1 do for f=b.x,s.x,1 do local o=A(E,f,g,m)if o~=r then local A=n(E,f,g,m)local o=Vector3int16.new(f,g,m)local r=false for g,m in pairs(V)do if g==o then m.KeepAlive=t if X then m.SelectionBox.Color=X end r=true break end end if not r then local g,m=createAdornment(X)g.Size=Vector3.new(4,4,4)g.CFrame=CFrame.new(A)local f={SelectionPart=g;SelectionBox=m,KeepAlive=t}V[o]=f end end end end end cleanUpAdornments()end k=g if m then local m,f=createAdornment(X)m.Size=g.Size m.CFrame=g.CFrame V.SelectionPart=m V.SelectionBox=f s=function(g,X)if g and g~=k then k=g m.Size=g.Size m.CFrame=g.CFrame end if X then f.Color=X end end else adornFullCellsInRegion(g,X)s=function(g,X)if g and g~=k then k=g adornFullCellsInRegion(g,X)end end end local x=function()s=nil if b then b:Destroy()end V=nil end return s,x end

t.MakeWedge = function(x, y, z, defaultmaterial)
	return game:GetService("Terrain"):AutoWedgeCell(x,y,z)
end

t.SelectTerrainRegion = function(regionToSelect, color, selectEmptyCells, selectionParent)
	local terrain = game:GetService("Workspace"):FindFirstChild("Terrain")
	if not terrain then return end

	assert(regionToSelect)
	assert(color)

	if not type(regionToSelect) == "Region3" then
		error("regionToSelect (first arg), should be of type Region3, but is type",type(regionToSelect))
	end
	if not type(color) == "BrickColor" then
		error("color (second arg), should be of type BrickColor, but is type",type(color))
	end

	-- frequently used terrain calls (speeds up call, no lookup necessary)
	local GetCell = terrain.GetCell
	local WorldToCellPreferSolid = terrain.WorldToCellPreferSolid
	local CellCenterToWorld = terrain.CellCenterToWorld
	local emptyMaterial = Enum.CellMaterial.Empty

	-- container for all adornments, passed back to user
	local selectionContainer = Instance.new("Model")
	selectionContainer.Name = "SelectionContainer"
	selectionContainer.Archivable = false
	if selectionParent then
		selectionContainer.Parent = selectionParent
	else
		selectionContainer.Parent = game:GetService("Workspace")
	end

	local updateSelection = nil -- function we return to allow user to update selection
	local currentKeepAliveTag = nil -- a tag that determines whether adorns should be destroyed
	local aliveCounter = 0 -- helper for currentKeepAliveTag
	local lastRegion = nil -- used to stop updates that do nothing
	local adornments = {} -- contains all adornments
	local reusableAdorns = {}

	local selectionPart = Instance.new("Part")
	selectionPart.Name = "SelectionPart"
	selectionPart.Transparency = 1
	selectionPart.Anchored = true
	selectionPart.Locked = true
	selectionPart.CanCollide = false
	selectionPart.Size = Vector3.new(4.2,4.2,4.2)

	local selectionBox = Instance.new("SelectionBox")

	-- srs translation from region3 to region3int16
	local function Region3ToRegion3int16(region3)
		local theLowVec = region3.CFrame.p - (region3.Size/2) + Vector3.new(2,2,2)
		local lowCell = WorldToCellPreferSolid(terrain,theLowVec)

		local theHighVec = region3.CFrame.p + (region3.Size/2) - Vector3.new(2,2,2)
		local highCell = WorldToCellPreferSolid(terrain, theHighVec)

		local highIntVec = Vector3int16.new(highCell.x,highCell.y,highCell.z)
		local lowIntVec = Vector3int16.new(lowCell.x,lowCell.y,lowCell.z)

		return Region3int16.new(lowIntVec,highIntVec)
	end

	-- helper function that creates the basis for a selection box
	function createAdornment(theColor)
		local selectionPartClone = nil
		local selectionBoxClone = nil

		if #reusableAdorns > 0 then
			selectionPartClone = reusableAdorns[1]["part"]
			selectionBoxClone = reusableAdorns[1]["box"]
			table.remove(reusableAdorns,1)

			selectionBoxClone.Visible = true
		else
			selectionPartClone = selectionPart:Clone()
			selectionPartClone.Archivable = false

			selectionBoxClone = selectionBox:Clone()
			selectionBoxClone.Archivable = false

			selectionBoxClone.Adornee = selectionPartClone
			selectionBoxClone.Parent = selectionContainer

			selectionBoxClone.Adornee = selectionPartClone

			selectionBoxClone.Parent = selectionContainer
		end
			
		if theColor then
			selectionBoxClone.Color = theColor
		end

		return selectionPartClone, selectionBoxClone
	end

	-- iterates through all current adornments and deletes any that don't have latest tag
	function cleanUpAdornments()
		for cellPos, adornTable in pairs(adornments) do

			if adornTable.KeepAlive ~= currentKeepAliveTag then -- old news, we should get rid of this
				adornTable.SelectionBox.Visible = false
				table.insert(reusableAdorns,{part = adornTable.SelectionPart, box = adornTable.SelectionBox})
				adornments[cellPos] = nil
			end
		end
	end

	-- helper function to update tag
	function incrementAliveCounter()
		aliveCounter = aliveCounter + 1
		if aliveCounter > 1000000 then
			aliveCounter = 0
		end
		return aliveCounter
	end

	-- finds full cells in region and adorns each cell with a box, with the argument color
	function adornFullCellsInRegion(region, color)
		local regionBegin = region.CFrame.p - (region.Size/2) + Vector3.new(2,2,2)
		local regionEnd = region.CFrame.p + (region.Size/2) - Vector3.new(2,2,2)

		local cellPosBegin = WorldToCellPreferSolid(terrain, regionBegin)
		local cellPosEnd = WorldToCellPreferSolid(terrain, regionEnd)

		currentKeepAliveTag = incrementAliveCounter()
		for y = cellPosBegin.y, cellPosEnd.y do
			for z = cellPosBegin.z, cellPosEnd.z do
				for x = cellPosBegin.x, cellPosEnd.x do
					local cellMaterial = GetCell(terrain, x, y, z)
					
					if cellMaterial ~= emptyMaterial then
						local cframePos = CellCenterToWorld(terrain, x, y, z)
						local cellPos = Vector3int16.new(x,y,z)

						local updated = false
						for cellPosAdorn, adornTable in pairs(adornments) do
							if cellPosAdorn == cellPos then
								adornTable.KeepAlive = currentKeepAliveTag
								if color then
									adornTable.SelectionBox.Color = color
								end
								updated = true
								break
							end 
						end

						if not updated then
							local selectionPart, selectionBox = createAdornment(color)
							selectionPart.Size = Vector3.new(4,4,4)
							selectionPart.CFrame = CFrame.new(cframePos)
							local adornTable = {SelectionPart = selectionPart, SelectionBox = selectionBox, KeepAlive = currentKeepAliveTag}
							adornments[cellPos] = adornTable
						end
					end
				end
			end
		end
		cleanUpAdornments()
	end


	------------------------------------- setup code ------------------------------
	lastRegion = regionToSelect

	if selectEmptyCells then -- use one big selection to represent the area selected
		local selectionPart, selectionBox = createAdornment(color)

		selectionPart.Size = regionToSelect.Size
		selectionPart.CFrame = regionToSelect.CFrame

		adornments.SelectionPart = selectionPart
		adornments.SelectionBox = selectionBox

		updateSelection = 
			function (newRegion, color)
				if newRegion and newRegion ~= lastRegion then
					lastRegion = newRegion
				 	selectionPart.Size = newRegion.Size
					selectionPart.CFrame = newRegion.CFrame
				end
				if color then
					selectionBox.Color = color
				end
			end
	else -- use individual cell adorns to represent the area selected
		adornFullCellsInRegion(regionToSelect, color)
		updateSelection = 
			function (newRegion, color)
				if newRegion and newRegion ~= lastRegion then
					lastRegion = newRegion
					adornFullCellsInRegion(newRegion, color)
				end
			end

	end

	local destroyFunc = function()
		updateSelection = nil
		if selectionContainer then selectionContainer:Destroy() end
		adornments = nil
	end

	return updateSelection, destroyFunc
end
