Terrain:PasteRegion() and Terrain:CopyRegion() missing parameter and return descriptions

The developer hub pages documenting Terrain:PasteRegion and Terrain:CopyRegion are missing some information: the descriptions and default values (if any) of its parameters. Not only is Terrain:CopyRegion missing descriptions and default values of its parameters, it’s also missing a summary of its return value

Terrain:PasteRegion’s page:

Terrain:CopyRegion’s page:


Pinging @Ozzypig

I can try to explain these methods as they’re used in the terrain tool’s region copy+paste functionality:

Terrain:CopyRegion() takes a Region3int16, which is similar to a Region3 made of Vector3s, just it uses Vector3int16. Unlike most terrain methods that take a Region3 in stud coordinates, CopyRegion uses voxel coordinates, so you’ll want to * or / by 4. I don’t think it throws an error if you pass it an invalid region (e.g. where min > max).

-- From snapping mouse to terrain etc.
local minStuds = Vector3.new(x0, y0, z0)
local maxStuds = Vector3.new(x1, y1, z1)

local voxelResolution = 4 -- Size of a voxel in studs
local minVoxels = Vector3int16.new(
	math.floor(minStuds.x / voxelResolution),
	math.floor(minStuds.y / voxelResolution),
	math.floor(minStuds.z / voxelResolution))
local maxVoxels = Vector3int16.new(
	math.ceil(maxStuds.x / voxelResolution),
	math.ceil(maxStuds.y / voxelResolution),
	math.ceil(maxStuds.z / voxelResolution))

local terrainRegion = terrain:CopyRegion(Region3int16.new(minVoxels, maxVoxels))

The API returns a TerrainRegion instance: https://developer.roblox.com/en-us/api-reference/class/TerrainRegion

Terrain:PasteRegion() takes the TerrainRegion instance you got from CopyRegion() and applies it back to the terrain. The corner parameter is where to place the “min” of the given TerrainRegion, again in voxel coordinates. pasteEmptyCells is for whether you want to apply the air voxels from the copied region to the new location, i.e. do you want the pasted region to completely overwrite all the existing terrain in the target area (pasteEmptyCells = true), or do you want to merge it with the terrain that’s already there (pasteEmptyCells = false).

For both methods, none of the parameters have default values.

Example using both methods, with pasteEmptyCells = false on the left and = true on the right:

Generated by this code
local terrain = game:GetService("Workspace").Terrain
local resolution = 4

local test1Corner = Vector3.new(0, 4, 0) * resolution
local test2Corner = Vector3.new(10, 4, 0) * resolution

for _, cornerStuds in ipairs({test1Corner, test2Corner}) do
	local bottomBlockSize = Vector3.new(20, 8, 40)
	terrain:FillBlock(CFrame.new(cornerStuds + bottomBlockSize / 2), bottomBlockSize, Enum.Material.Grass)

	local topBlockSize = Vector3.new(12, 40, 4)
	terrain:FillBlock(CFrame.new(cornerStuds + topBlockSize / 2), topBlockSize, Enum.Material.Grass)

local copyCenter = Vector3.new(5, 4, 40) * resolution
local copyRadius = 12
terrain:FillBall(copyCenter, copyRadius, Enum.Material.Snow)

local copyMinStuds = copyCenter - Vector3.new(copyRadius, copyRadius, copyRadius)
local copyMaxStuds = copyCenter + Vector3.new(copyRadius, copyRadius, copyRadius)
local copyRegion = Region3int16.new(
		math.floor(copyMinStuds.x / resolution),
		math.floor(copyMinStuds.y / resolution),
		math.floor(copyMinStuds.z / resolution)
		math.ceil(copyMaxStuds.x / resolution),
		math.ceil(copyMaxStuds.y / resolution),
		math.ceil(copyMaxStuds.z / resolution)

local copiedTerrainRegion = terrain:CopyRegion(copyRegion)

for _, data in ipairs({
	{test1Corner, false},
	{test2Corner, true}
}) do
	local testCornerStuds = data[1]
	local pasteEmptyCells = data[2]

	local targetCorner = Vector3int16.new(
		math.floor(testCornerStuds.x / resolution) + 1,
		math.floor(testCornerStuds.y / resolution) - 1,
		math.floor(testCornerStuds.Z / resolution) - 2
	terrain:PasteRegion(copiedTerrainRegion, targetCorner, pasteEmptyCells)

Thanks guys - this is really helpful! I’ll be sure to update the devhub pages as soon as I can. The Vector3int16 and Region3int16 pages recently got an update, so it makes sense that the terrain pages also get the same treatment.


I had to dive deep into core scripts to figure out how on Earth I was expected to use CopyRegion/PasteRegion without just using extents, it would be very helpful for that to be documented on the page.