How do I optimize this script?

I made an infinite mining generation script from a tutorial for my mining game, but it’s horribly optimized and I don’t know how exactly to optimize it. If someone mines for a bit eventually the amount of existing blocks and values start lagging the game for every block you mine.

So far I’ve looked into occlusion culling but that wouldn’t work as it would probably not help with performance if it keeps checking what objects are on screen, another thing I’ve tried is changing how the blocks and values get stored, but that ended up causing more lag, and so I’m just kind of stumped at this point I don’t know how to optimize this.

This is my code right now

local RS = game:GetService("ReplicatedStorage")
local positions = {
	Vector3.new(6,0,0);
	Vector3.new(-6,0,0);
	Vector3.new(0,6,0);
	Vector3.new(0,-6,0);
	Vector3.new(0,0,6);
	Vector3.new(0,0,-6);
}

local oreTable = {}
for i, v in ipairs(game.ServerStorage.Ores:GetChildren()) do
	if v:IsA("Part") then
		table.insert(oreTable, {ore = v, chance = v.Chance.Value})
	end
end

local rollTable = {}
for _, data in ipairs(oreTable) do
	for i = 1, data.chance, 1 do
		table.insert(rollTable, data)
	end
end

function Generate(pos)
	if pos then
		for _,pos2 in pairs(positions) do
			local newPos = pos+pos2
			local previouslyGenerated
			for _,generated in pairs(workspace.Cubes.Generated:GetChildren()) do
				if generated.Value == newPos then
					previouslyGenerated = true
				end
			end
			if newPos.Y > 0 then
				previouslyGenerated = true
			end
			if not previouslyGenerated then
				local random = math.random(1, #rollTable)
				local ore = rollTable[random].ore:Clone()
				ore.Position = newPos
				ore.Parent = workspace.Cubes
				RS.BlockGen.OnServerEvent:Connect(function(plr, rPart)
					Generate(rPart.Position)
					rPart:Destroy()
				end)
				local val = Instance.new("Vector3Value")
				val.Value = newPos
				val.Parent = workspace.Cubes.Generated
			end
		end
	end
end

for i,cube in pairs(workspace.Cubes:GetChildren()) do
	if cube:IsA("Part") then
		local val = Instance.new("Vector3Value")
		val.Value = cube.Position
		val.Parent = workspace.Cubes.Generated
		RS.BlockGen.OnServerEvent:Connect(function(plr, rPart)
			Generate(rPart.Position)
			rPart:Destroy()
		end)
	end
end

There’s a lot of things to optimize in this script that only you can do. With only little knowledge of your script, all I can really do is make it pretty:

-- services
local ReplicatedStorage = game:GetService("ReplicatedStorage")

-- tables
local Positions = {
	Vector3.new(6,0,0);
	Vector3.new(-6,0,0);
	Vector3.new(0,6,0);
	Vector3.new(0,-6,0);
	Vector3.new(0,0,6);
	Vector3.new(0,0,-6);
}

local OreTable = {}
local RollTable = {}

-- for loops
for Index, Inst in ipairs(game.ServerStorage.Ores:GetChildren()) do
	if Inst:IsA("Part") then
		table.insert(OreTable, {ore = Inst, chance = Inst.Chance.Value})
	end
end

for Index, Data in ipairs(OreTable) do
	for i = 1, Data.chance, 1 do
		table.insert(RollTable, Data)
	end
end

-- main functions
function Generate(Position)
	if Position then
		for _, Position2 in pairs(Positions) do
			local NewPosition = Position+Position2
			local previouslyGenerated
			
			for _, Generated in pairs(workspace.Cubes.Generated:GetChildren()) do
				if Generated.Value == NewPosition then
					previouslyGenerated = true
				end
			end
			
			if NewPosition.Y > 0 then
				previouslyGenerated = true
			end
			
			if not previouslyGenerated then
				local random = math.random(1, #RollTable)
				local ore = RollTable[random].ore:Clone()
				
				ore.Position = NewPosition
				ore.Parent = workspace.Cubes
				
				ReplicatedStorage.BlockGen.OnServerEvent:Connect(function(plr, rPart)
					Generate(rPart.Position)
					rPart:Destroy()
				end)
				
				local Vector = Instance.new("Vector3Value")
				Vector.Value = NewPosition
				Vector.Parent = workspace.Cubes.Generated
			end
		end
	end
end

for Index,Cube in pairs(workspace.Cubes:GetChildren()) do
	if Cube:IsA("Part") then
		local Vector = Instance.new("Vector3Value")
		Vector.Value = Cube.Position
		Vector.Parent = workspace.Cubes.Generated
		ReplicatedStorage.BlockGen.OnServerEvent:Connect(function(plr, rPart)
			Generate(rPart.Position)
			rPart:Destroy()
		end)
	end
end
1 Like

Some mistakes upon first reading the code,

You shouldn’t connect this event in the for loop, this will repeatedly connect the same event even though it only needs to be connected once. Move it to the bottom of the script.

By the looks of it (assuming this is voxels) you aren’t implementing any form of greedy meshing, which means that you are rendering triangles for every block instead of greedy meshing it.

@/5uphi 's video explains greedy meshing pretty well

as well as this write-up by Elttob Consume everything - how greedy meshing works

1 Like

Could you elaborate on what you mean by there are things in the script that only I can optimize? Also thanks for that.

From what I understand by skimming through the tutorials, what this does is merge the blocks into one giant block as opposed to many tiny blocks, right? This isn’t what I’m looking for as the player might wanna go back into previous sections of the mine where presumably the blocks might be merged, and they can’t mine it anymore of course. Though you are correct it is voxels.

It did optimize my game a lot though by removing the event in the for loop. I still feel like the game lags just a little bit when I go past a certain point while mining.

I’m saying that if I were to optimize the script, I am surely to run into some errors due to my limited knowledge of other scripts / events you have.

You would just have to recalculate the greedy mesh for that specific area when the player mines/places a block. This is how every voxel game including Minecraft does it. Making and optimising a voxel game is a surprisingly complicated topic, I’d recommend you give these a read.