t.MakeWedge=function(C,e,s,B)return(game:GetService("\084\101\114\114\097\105\110")):AutoWedgeCell(C,e,s)end t.SelectTerrainRegion=function(C,e,s,B)local l=(game:GetService("\087\111\114\107\115\112\097\099\101")):FindFirstChild("\084\101\114\114\097\105\110")if not l then return end assert(C)assert(e)if not type(C)=="\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(C))end if not type(e)=="\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(e))end local A=l.GetCell local E=l.WorldToCellPreferSolid local H=l.CellCenterToWorld local j=Enum.CellMaterial.Empty local S=Instance.new("\077\111\100\101\108")S.Name="\083\101\108\101\099\116\105\111\110\067\111\110\116\097\105\110\101\114"S.Archivable=false if B then S.Parent=B else S.Parent=game:GetService("\087\111\114\107\115\112\097\099\101")end local O=nil local f=nil local g=0 local W=nil local q={}local i={}local n=Instance.new("\080\097\114\116")n.Name="\083\101\108\101\099\116\105\111\110\080\097\114\116"n.Transparency=1 n.Anchored=true n.Locked=true n.CanCollide=false n.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 m(C)local e=(C.CFrame.p-C.Size/2)+Vector3.new(2,2,2)local s=E(l,e)local B=(C.CFrame.p+C.Size/2)-Vector3.new(2,2,2)local A=E(l,B)local H=Vector3int16.new(A.x,A.y,A.z)local j=Vector3int16.new(s.x,s.y,s.z)return Region3int16.new(j,H)end function createAdornment(C)local e=nil local s=nil if#i>0 then e=i[1].part s=i[1].box table.remove(i,1)s.Visible=true else e=n:Clone()e.Archivable=false s=b:Clone()s.Archivable=false s.Adornee=e s.Parent=S s.Adornee=e s.Parent=S end if C then s.Color=C end return e,s end function cleanUpAdornments()for C,e in pairs(q)do if e.KeepAlive~=f then e.SelectionBox.Visible=false table.insert(i,{part=e.SelectionPart,box=e.SelectionBox})q[C]=nil end end end function incrementAliveCounter()g=g+1 if g>1000000 then g=0 end return g end function adornFullCellsInRegion(C,e)local s=(C.CFrame.p-C.Size/2)+Vector3.new(2,2,2)local B=(C.CFrame.p+C.Size/2)-Vector3.new(2,2,2)local S=E(l,s)local O=E(l,B)f=incrementAliveCounter()for C=S.y,O.y,1 do for s=S.z,O.z,1 do for B=S.x,O.x,1 do local E=A(l,B,C,s)if E~=j then local A=H(l,B,C,s)local E=Vector3int16.new(B,C,s)local j=false for C,s in pairs(q)do if C==E then s.KeepAlive=f if e then s.SelectionBox.Color=e end j=true break end end if not j then local C,s=createAdornment(e)C.Size=Vector3.new(4,4,4)C.CFrame=CFrame.new(A)local B={SelectionPart=C,SelectionBox=s;KeepAlive=f}q[E]=B end end end end end cleanUpAdornments()end W=C if s then local s,B=createAdornment(e)s.Size=C.Size s.CFrame=C.CFrame q.SelectionPart=s q.SelectionBox=B O=function(C,e)if C and C~=W then W=C s.Size=C.Size s.CFrame=C.CFrame end if e then B.Color=e end end else adornFullCellsInRegion(C,e)O=function(C,e)if C and C~=W then W=C adornFullCellsInRegion(C,e)end end end local K=function()O=nil if S then S:Destroy()end q=nil end return O,K end
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
--------------------------------------------Terrain Utilities Begin-----------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
--makes a wedge at location x, y, z
--sets cell x, y, z to default material if parameter is provided, if not sets cell x, y, z to be whatever material it previously w
--returns true if made a wedge, false if the cell remains a block
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
