Is there any possibilites to make this code run faster?

Hello there! I make a generation like in minecraft, but I have one problem. It takes so long to generate it. for example, while generating 50x50x50 world it would cause script execution limit. Or if I place task.wait(), it will take forever to load 125000 blocks. Here are the parts used to generate blocks:

for x = 0,50,1 do
	for z = 0,50,1 do
		for y = 80,130,1 do
			block=generationmodule.GetBlock(x,y,z,0.1)
			blockdata.AddBlockToList(block,{x,y,z},{})
			task.wait()
		end
	end
end
print("Successfully Generated The World!")
rs.RemoteEvents.RenderWorld:FireAllClients(blockdata.BlockList)
function module.AddBlockToList(name,pos,data)
	local x= tostring(pos[1])
	local y = tostring(pos[2])
	local z =tostring(pos[3])
	if not module.BlockList[x] then
		module.BlockList[x]={}
	end
	if not module.BlockList[x][y] then
		module.BlockList[x][y]={}
	end
	module.BlockList[x][y][z]={['name']=name,['position']=pos,['data']=data}
end
function module.GetBlock(x,y,z,seed)
	local amplitude=100
	--print(math.noise(x,z,seed))
	--local sin=math.sin(x*4)/4
	--print(sin)
	local noise=math.noise(x/100,z/100,seed)
	--local noise=perlinnoise.new({x,0,z,seed},amplitude,4)
	local surfacey=80+(noise)*amplitude
	
	if surfacey>y then
		return 'Stone'
	else
		return 'Air'
	end
end
1 Like

call wait() just before the script crashes or just before the next frame is supposed to render

local a = os.clock()

for 
..... 
if os.clock() - a >= 4.9 then wait() a = os.clock() end
end

just make sure the number above is smaller than the time it takes for the script to crash, i put 4.9 because idk how long it takes but seems to be about 5 seconds.
larger values will create longer lag spikes but itll run much faster and finish quicker, if the number is less than 1/60th you will not have any lag but itll take a while to run (but still be faster than putting wait() on every iteration)

1 Like

You can increase the limit of when task.wait() would fire. So have something like a counter and make it check whether to wait or not. So for example, every 50 blocks generated, fire task.wait(). The higher the number, the laggier the rendering would get.

1 Like

Try using coroutines. The script can run multiple threads at once. I believe in the roblox reference API under coroutines, it shows a video of a terrain generating system using coroutines.

Do you really need this line …

Tables in Lua are dynamically resized upon need. This is resource heavy, so if you know the final size of the table, you can use:

module.BlockList = table.create(51)
module.BlockList[x] = table.create(51)
module.BlockList[x][y] = table.create(51)

This way tables will be created with the given size, vastly speeding up the process.

Secondly, I suggest to simply put nil in a table whenever you are having an air block. You can then adjust your code so that whenever no value is found in a table, you will assume it is an air.

Thirdly, there is really no need to convert x, y and z to strings. Why not have numbers as indexes? It will also speed up future game mechanics, when one block affects the block next to it. Otherwise you will have to convert to int, add one and convert back to string.

Finally, as ZatorcinatorZ said, coroutines could help, but only if you use Actors and Parallel Lua. Otherwise it will not make a difference.

I made something like this:

function Generate(x1,x2,z1,z2)
	local a = os.clock()
	for x = x1,x2,1 do
		for z = z1,z2,1 do
			for y = 60,150,1 do
				--print(math.noise(x,z,0.9))
				local block=generationmodule.GetBlock(x,y,z,0.1)
				--print(block)
				blockdata.AddBlockToList(block,{x,y,z},{})
				if os.clock() - a >= 4.9 then task.wait() a = os.clock() end
			end
			--for y = 70,80,1 do
			--	--blockmodule.PlaceBlock('Stone',x,y,z)
			--	blockdata.AddBlockToList('Stone',{x,y,z},{})
			--end
		end
	end
end
a1=coroutine.create(function()
	Generate(0,50,0,50)
end)
coroutine.resume(a1)
a2=coroutine.create(function()
	Generate(51,100,51,100)
end)
coroutine.resume(a2)
print(blockdata.BlockList)
rs.RemoteEvents.RenderWorld:FireAllClients(blockdata.BlockList)

But it still causes script time out. Also,I use strings as key because for some reason I can’t use negative numbers. Also when I give local script a table, if int keys don’t start for 0, they convert to string by themselves