Lag spikes from .Touched event

hello everyone i’m making a client-sided collecting system for my game

the problem is that each cube collected make bigger and bigger lag spike

i’ll appreciate help

-- server code

remotes.CubeCollected.OnServerEvent:Connect(function(player, cube: string)
	local data = RS.Data:WaitForChild(player.Name)
	local Stats = data:WaitForChild("Stats")
	local TotalStats = data:WaitForChild("Total Stats")
	
	Stats.Cubes.Value += CubesModule[cube.Name].Value
	TotalStats["Total Cubes"].Value += CubesModule[cube.Name].Value
	Stats.XP.Value += CubesModule[cube.Name].Value/10
end)


local function parseVector3(str)
	local x, y, z = string.match(str, "([^,]+), ([^,]+), ([^,]+)")
	if x and y and z then
		return Vector3.new(tonumber(x), tonumber(y), tonumber(z))
	end
	return nil
end


local function isPositionTaken(pos, takenPositions, tolerance)
	for _, taken in takenPositions do
		if (pos - taken).Magnitude <= tolerance then
			return true
		end
	end
	return false
end

local spawnDebounces = {}

remotes.CubeData.OnServerInvoke = function(player)
	if spawnDebounces[player.Name] then return end
	table.insert(spawnDebounces, player.Name)

	local data = RS.Data:WaitForChild(player.Name)
	local spawnSpeed = data["Cube Stats"].Speed.Value
	local spawnLimit = data["Cube Stats"].Limit.Value
	
	if #data.Cubes:GetChildren() >= spawnLimit then return end
	
	spawn(function()
		task.wait(1/spawnSpeed - 0.001)
		spawnDebounces[player.Name] = nil
	end)

	local chosedCube = CubesModule.ChooseCube()

	local cube = Instance.new("StringValue")
	cube.Name = chosedCube


	local takenPositions = {}
	for _, existingCube in data.Cubes:GetChildren() do
		local pos = parseVector3(existingCube.Value)
		if pos then
			table.insert(takenPositions, pos)
		end
	end

	local maxAttempts = 20
	local found = false
	local cubePos
	local tolerance = 1

	for attempt = 1, maxAttempts do
		local randomX = math.random(-spawnArea.Size.X/2+ 0.5, spawnArea.Size.X/2 - 0.5)
		local randomZ = math.random(-spawnArea.Size.Z/2+ 0.5, spawnArea.Size.Z/2 - 0.5)
		local tryPos = spawnArea.Position + Vector3.new(randomX, spawnArea.Size.Y/2 + 0.5, randomZ)
		if not isPositionTaken(tryPos, takenPositions, tolerance) then
			cubePos = tryPos
			found = true
			break
		end
	end

	if not found then
		
		return nil
	end

	cube.Value = tostring(cubePos)
	cube.Parent = data.Cubes

	return cube
end
-- client code
local function spawnCube()
	local cubeValue = Remotes.CubeData:InvokeServer()
	if not cubeValue then return end

	local cubesTemplates = RS:WaitForChild("Cubes")
	local cubeTemplate = cubesTemplates:FindFirstChild(cubeValue.Name)
	if not cubeTemplate then return end

	local cube = cubeTemplate:Clone()

	local x, y, z = string.match(cubeValue.Value, "([^,]+), ([^,]+), ([^,]+)")
	if x and y and z then
		cube.Position = Vector3.new(tonumber(x), tonumber(y), tonumber(z))
	end

	local connection
	connection = cube.Touched:Connect(function(hit)
		if debounce then return end
		debounce = true
		if hit.Parent == player.Character then
			cubeValue:Destroy()
			game.Debris:AddItem(cube, 0.6)
			Remotes.CubeCollected:FireServer(cubeValue)
			AnimateCollect(cube)
			if connection then
				connection:Disconnect()
				connection = nil
				debounce = false
			end
		end
	end)
	cube.Parent = playerCubesFolder
end

RS.Remotes.LoadCubes:FireServer(playerCubesFolder)

while task.wait(1/CubeStats.Speed.Value) and playerCubesFolder do
	spawnCube()
end

video:

3rd Try…

Trying to follow your flow here.
Removed reset as it’s gone after.
(if that is what you’re doing)

Client
local function spawnCube()
	if #playerCubesFolder:GetChildren() >= 50 then return end

	local cubeValue = Remotes.CubeData:InvokeServer()
	if not cubeValue then return end

	local cubeTemplate = RS.Cubes:FindFirstChild(cubeValue.Name)
	if not cubeTemplate then return end

	local cube = cubeTemplate:Clone()

	local x, y, z = string.match(cubeValue.Value, "([^,]+), ([^,]+), ([^,]+)")
	if x and y and z then
		cube.Position = Vector3.new(tonumber(x), tonumber(y), tonumber(z))
	end

	local db = false
	con = cube.Touched:Connect(function(hit)
		if db then return end
		if hit.Parent == player.Character then db = true
			cubeValue:Destroy()
			Remotes.CubeCollected:FireServer(cubeValue)
			AnimateCollect(cube)
			game.Debris:AddItem(cube, 0.5)
			con:Disconnect()
		end
	end)

	cube.Parent = playerCubesFolder
end

RS.Remotes.LoadCubes:FireServer(playerCubesFolder)

while task.wait(1 / CubeStats.Speed.Value) do
	if not playerCubesFolder then break end
	spawnCube()
end

doesn’t fixes issue collecting still makes lags

nope this doesn’t remove lags either

You’re firing tons of InvokeServer calls per second and causing the CPU to overload - the server likely as well. Perhaps, instead of spawning 1 new cube per iteration, you send just 1 call per second and get a batch of cube data within that 1 second timeframe to spawn your cubes.

For example, if your rate is 20 cubes per second, instead of calling for data for 1 cube across 1/20 seconds, you send just 1 call and receive back cube data for 20 cubes all at once in which you can then spawn into the game world - you’ll have to calculate however many cubes should have spawned within that 1 second timeframe using the cube stats and whatnot but the effect would be the same except now there won’t be performance issues.

lag grows no matter at what speed cubes spawn
forget to say that what causing lag is a CubeCollected event because if i remove it there is no lags
adding print to event doesn’t help it prints one time only and only when collecting a cube
but i need it give player rewards

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