Help with decreasing server-sided lag

  1. What do you want to achieve? Keep it simple and clear!
    Basically, I want to decrease the server lag from my Tower Defense game.

  2. What is the issue? Include screenshots / videos if possible!
    Well, my issue is that I’m creating alot of lag with my Targetting system for a Burst tower when around 25 Towers are placed down(for an example, a second for the server takes around 0.3-0.6 extra seconds IRL to be ran).

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I’ve searched A LOT on the Devforum for solutions, but still couldn’t manage to reduce the lag enough to playable levels. I have absolutely no idea how to optimize the code even more.

heres my code:

function LazerLoopStart(tower, range)
	local atkrange = tower:WaitForChild("range")
	atkrange.Parent = workspace.ignore
	local loop = coroutine.wrap(function()
		while wait(tower.info.firerate.Value) do
			local bursts = data.Data[tower.Name][tower.info.lvl.Value]["bursts"]
			for count = 1, bursts, 1 do
				local connection = atkrange.Touched:Connect(function() end)
				local results = atkrange:GetTouchingParts()
				connection:Disconnect()
				local FurthestEnemyMag = 0
				local FurthestEnemy
				for _, v in pairs(results) do
					if v.Name == "hitbox" and v:IsDescendantOf(workspace.Enemies) then
						local mag = (v.Parent.HumanoidRootPart.Position - start.Position).Magnitude
						if mag > FurthestEnemyMag then
							FurthestEnemyMag = mag
							FurthestEnemy = v
						end
					end
				end
				if not FurthestEnemy then break end
				tower:SetPrimaryPartCFrame(CFrame.lookAt(tower.PrimaryPart.Position, tower.PrimaryPart.Position + ((FurthestEnemy.Parent.PrimaryPart.Position - tower.PrimaryPart.Position).Unit * Vector3.new(1,0,1))))
				FurthestEnemy.Parent:FindFirstChild("health").Value -= tower.info.dmg.Value
				FurthestEnemy = nil
				tower.gunshotfr:Play()
				wait(0.3)
			end
		end
	end)
	loop()
end

Any help is appreciated, as im stuck with this problem for over a week at this point.

one thing I would check is how many times are you calling
function LazerLoopStart(tower, range)

because if it’s more than once, the coroutine variable ‘loop’ is then called regardless if there’s already an active coroutine. Each time LazerLoopStart() is called, a new coroutine starts. something you could do there is create a boolean to check if the tower is already actively firing and if so then return from the LazerLoopStart()

Well the idea is to run the function each time a tower is placed down, so if there are 25 towers placed down, the function will be running 25 different times each 2 seconds. Now that i think about it, that actually sounds very unoptimized.
Also, I just had an idea about how to run the function only 1 time, so I think that would stress way less the server, so thanks.