Insane lag spikes in voxel game!

Please fix me if I put this in the wrong category.

Hello developers! I am working on a voxel game inspired by a mix of Minecraft and Cubic Castles! I have a problem though, the game receives insane lag spikes when I load in a streaming area.

I used a generating system from an uncopylocked world generator game that I tweaked many times because I honestly cant program that in myself. But this resource also doesn’t have unloading parts or chunks at all.

Script:

local part = Instance.new("Part")
part.TopSurface = Enum.SurfaceType.Smooth
part.BottomSurface = Enum.SurfaceType.Smooth
part.Anchored = true
part.Size = Vector3.new(4,4,4)

local terrainModel = workspace.TerrainModel

local runservice = game:GetService("RunService")
local frequency = 120
local amplitude = 20
local highest = 5

local width = 500

local parts = {}
local hasExisted = {}
math.randomseed(tick())
local seed = math.random(1,2875300)
local maxcaves = 5
currentcaves = 0

local biomex,biomez = math.random(1,100),math.random(1,100)
local heightMult = .75+math.noise(biomex/100,biomez/100,seed)
amplitude = heightMult*amplitude
print("amplitude",amplitude)
local generating = false
local Scale = 90
local lowestT = 5
local waterblocks = {}
print(seed)
function getY(x,z,i)
	local t = (math.noise(x/frequency,z/frequency,seed)+math.noise(x/frequency*3,z/frequency*3,seed)+math.noise(x/frequency,z/frequency,seed)+math.noise(x/frequency*2,z/frequency*2,seed)+math.noise(x/frequency/5,z/frequency/5,seed))
	if t < lowestT then
		lowestT = t
	end
	local ogt = t
	t = math.floor(t*(amplitude/4))/(amplitude/4)
	t = t*amplitude + (i*4)
	if i >= highest-2 and ogt <= -.8  then
		
		if i == highest-2 then
			return {"sand",t}
		end
		return {"water",t}
	elseif i >= highest-2 and (ogt> -.8 and ogt< -.6) then--or (t< -.8 and t>= -.85) then
		return {"sand",t}
	end
	
	return t
end

function checkPartExists(x,y,z)
	return hasExisted[tostring((x)).."_"..tostring((y)).."_"..tostring((z))]
end

function addTexture(part,id,topid,sides)
	
	local enums = {"Front","Back","Top","Bottom","Left","Right"}
	for i,v in pairs (enums) do
		
		local t = Instance.new("Texture")
		local brightness = math.random(210, 255)
		t.Color3 = Color3.fromRGB(brightness, brightness, brightness)
		t.Face = v
		t.StudsPerTileU = 4
		t.StudsPerTileV = 4
		if id == 128774672 then
			t.Transparency = .35		
		end
		if v == "Top" and topid then
			t.Texture = "rbxassetid://"..topid
		elseif v == "Bottom" and id then
			t.Texture = "rbxassetid://"..id
		elseif sides then
			t.Texture = "rbxassetid://"..sides
		else
			t.Texture = "rbxassetid://"..id
		end
		local randomValue = math.random(220, 255)
		t.Parent = part
	end
end

function checkSurroundings(pos,i)
	local x,y,z = pos.X,pos.Y,pos.Z
	if not checkPartExists(x+4,y,z) then
		createBlock(x+4,y,z,i)
	end
	if not checkPartExists(x-4,y,z) then
		createBlock(x-4,y,z,i)
	end
	if not checkPartExists(x,y,z+4) then
		createBlock(x,y,z+4,i)
	end
	if not checkPartExists(x,y,z-4) then
		createBlock(x,y,z-4,i)
	end
end

function loadBlock(lastBlock,i_)
	if i_ and i_ + 1 > highest then
		return
	end
	local pos = lastBlock.Position
	local x = pos.X
	local z = pos.Z
	local i = i_ or lastBlock.IValue.Value
	checkSurroundings(Vector3.new(x,pos.Y-4,z),i-1)
	if not checkPartExists(x,pos.Y-4,z) then
		createBlock(x,pos.Y-4,z,i-1)
	end
	if i < highest - 4 then
		local newpos = pos+Vector3.new(0,4,0)
		checkSurroundings(newpos,i+1)
	end
	
end

local event = game.ServerStorage:WaitForChild("Event")

event.Event:connect(function(part)
	local x,y,z = part.Position.X,part.Position.Y,part.Position.Z
	parts[tostring((x)).."_"..tostring((y)).."_"..tostring((z))] = nil
	part:Destroy()
end)

function createBlock(x,y,z,i,creation)
	if y == "none" then return end
	if hasExisted[tostring((x)).."_"..tostring((y)).."_"..tostring((z))] == true then
		return
	end
	local p = part:Clone()
	local t__ = nil
	if type(y) == "table" then
		t__ = y[1]
		y = y[2]
	end
	local newy = y 
	p.Parent = terrainModel
	p.CanTouch = false
	p.CanQuery = false
	local numb = Instance.new("NumberValue")
	numb.Name = "IValue"
	numb.Value = i
	numb.Parent = p
	if t__ == "water" then
		p.Name = "Water"
		p.Transparency = 1
		p.CanCollide = false
		if creation == nil then
			newy = -(math.ceil(amplitude/8)+9)
		end
		addTexture(p,128774672)
	elseif t__ == "sand" then
		p.Name = "Sand"
		p.BrickColor = BrickColor.new("Buttermilk")
		addTexture(p,38349529)
	else
		if i == highest then
			p.Name = "Grass"
			p.BrickColor = BrickColor.new("Bright green")
			addTexture(p,179655033,17896536771,17896559648)
		elseif i >= highest-2 then
			p.Name = "Dirt"
			p.BrickColor = BrickColor.new("Brown")
			addTexture(p,8275209660)
		elseif i < highest-15 then
			p.Name = "Bedrock"
			p.BrickColor = BrickColor.new("Black")
			addTexture(p,152572095)
		else
			p.Name = "Stone"
			p.BrickColor = BrickColor.new("Medium stone grey")
			addTexture(p,132879294)
		end
	end
	if hasExisted[tostring((x)).."_"..tostring((newy)).."_"..tostring((z))] == true then
		return
	end
	parts[tostring((x)).."_"..tostring((newy)).."_"..tostring((z))] = p
	hasExisted[tostring((x)).."_"..tostring((newy)).."_"..tostring((z))] = true
	--[[if t__ == "water" then
		spawn(function()
			wait(5)
			while wait(1) do
				if x + 4 <= 150 then
					if parts[tostring((x+4)).."_"..tostring((newy)).."_"..tostring((z))] == nil then
						createBlock(x+4,{"water",newy},z,i,true)
					end
				end
				if x - 4 >= -150 then
					if parts[tostring((x-4)).."_"..tostring((newy)).."_"..tostring((z))] == nil then
						createBlock(x-4,{"water",newy},z,i,true)
					end
				end
				if parts[tostring((x)).."_"..tostring((newy-4)).."_"..tostring((z))] == nil then
					createBlock(x,{"water",newy-4},z,i-1,true)
				end
				if z + 4 <= 150 then
					if parts[tostring((x)).."_"..tostring((newy)).."_"..tostring((z+4))] == nil then
						createBlock(x,{"water",newy},z+4,i,true)
					end
				end
				if z - 4 >= -150 then
					if parts[tostring((x)).."_"..tostring((newy)).."_"..tostring((z-4))] == nil then
						createBlock(x,{"water",newy},z-4,i,true)
					end
				end
			end
		end)
	end--]]
	p.CFrame = CFrame.new(x,newy,z)
end

terrainModel.ChildRemoved:connect(function(child)
	if child:FindFirstChild("IValue") then
		loadBlock(child)
	end
end)

function RollingHillsOG()
	generating = true
	for i = highest-4,highest do
		for x = -width,width,4 do
			for z = -width,width,4 do
				local y = getY(x,z,i)
				createBlock(x,y,z,i,nil)
			end
			wait()
		end
		wait(0)
	end
	generating = false
end
RollingHillsOG()
--[[
function RollingHills(chunkx,chunkz)
	generating = true
	for i = highest,highest do
		for x = 0+(chunkx*75),75+(chunkx*75),4 do
			for z = 0+(chunkz*75),75+(chunkz*75),4 do
				local y = getY(x,z,i)
				createBlock(x,y,z,i)
			end
		end
		wait(1)
	end
	generating = false
end
for x=  -4,4 do
	
	for z  = -4,4 do
		RollingHills(x,z)
		wait(.5)
	end
end
for x=  -8,-4 do
	
	for z  = -8,-4 do
		RollingHills(x,z)
		wait(.5)
	end
end--]]



Please help!

Maybe the parts can go into a storage when far away or something- but I don’t know how to make that and I am still learning Lua.

EDIT: I realized the textures also make massive lag spikes along with the blocks!

Your best optimization would be to utilize Parallel Luau, which is a highly advanced topic I recommend reading: Parallel Luau | Documentation - Roblox Creator Hub

They even have examples on procedural terrain generation utilizing this method.

1 Like

After minutes that felt like hours of trying to get stuff to work I cant find anything! Do you have a clue of what I should do?

Yes, the article I linked has all the resource you will need to learn about parallel scripting and how to apply it to terrain generation.

Thank you so much!! It was hard to get it going but I did!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.