trying to make a terrain destruction/regeneration system, but the issue comes at regeneration. I assume the issue is data is being overwritten for intersecting chunks, and so the destroyed data is the one being used for regeneration aswell, not entirely sure how to fix it.
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local RunService = game:GetService("RunService")
local Terrain = workspace.Terrain
local destructionRadius = 5
local gridResolution = 4
local destructionDelay = 0.05
local regenerationDelay = 5
local regenerationStep = 0.1
local destroying = false
local activeRegions = {}
local function getRegionId(region)
return tostring(region.CFrame) .. tostring(region.Size)
end
local function regenerateTerrain(regionId)
local data = activeRegions[regionId]
if not data or data.state ~= "destroying" or data.regenerating ~= true then
return
end
local region = data.region
local material = data.material
local originalOccupancy = data.occupancy
local currentOccupancy = {}
for x = 1, #originalOccupancy do
currentOccupancy[x] = {}
for y = 1, #originalOccupancy[x] do
currentOccupancy[x][y] = {}
for z = 1, #originalOccupancy[x][y] do
currentOccupancy[x][y][z] = 0
end
end
end
while true do
local allDone = true
for x = 1, #currentOccupancy do
for y = 1, #currentOccupancy[x] do
for z = 1, #currentOccupancy[x][y] do
local target = originalOccupancy[x][y][z]
local diff = target - currentOccupancy[x][y][z]
if math.abs(diff) > 0.01 then
currentOccupancy[x][y][z] = currentOccupancy[x][y][z] + regenerationStep * diff
allDone = false
else
currentOccupancy[x][y][z] = target
end
end
end
end
Terrain:WriteVoxels(region, gridResolution, material, currentOccupancy)
if allDone then break end
task.wait(0.05)
end
activeRegions[regionId] = nil
end
local function destroyTerrain(position, radius)
local region = Region3.new(
position - Vector3.new(radius, radius, radius),
position + Vector3.new(radius, radius, radius)
):ExpandToGrid(gridResolution)
local regionId = getRegionId(region)
if activeRegions[regionId] and activeRegions[regionId].state == "destroying" then
return
end
local material, occupancy = Terrain:ReadVoxels(region, gridResolution)
activeRegions[regionId] = {
region = region,
material = material,
occupancy = occupancy,
state = "destroying",
regenerating = false
}
local airMaterials = {}
local airOccupancy = {}
for x = 1, #occupancy do
airMaterials[x] = {}
airOccupancy[x] = {}
for y = 1, #occupancy[x] do
airMaterials[x][y] = {}
airOccupancy[x][y] = {}
for z = 1, #occupancy[x][y] do
airMaterials[x][y][z] = Enum.Material.Air
airOccupancy[x][y][z] = 0
end
end
end
Terrain:WriteVoxels(region, gridResolution, airMaterials, airOccupancy)
task.delay(regenerationDelay, function()
if activeRegions[regionId] and not activeRegions[regionId].regenerating then
activeRegions[regionId].regenerating = true
regenerateTerrain(regionId)
end
end)
end
mouse.Button1Down:Connect(function()
destroying = true
while destroying do
local targetPosition = mouse.Hit.Position
destroyTerrain(targetPosition, destructionRadius)
task.wait(destructionDelay)
end
end)
mouse.Button1Up:Connect(function()
destroying = false
end)