Preventing high activity on character scripts with sanity checks

My game uses a lot of sanity checks on one singular character script which would cause a lot of lag when more players join. (I average 700 ping on join and 250 on regular which SHOULDN’T happen.)


How do I prevent?

--Loop 1
-- Zombie SFXs
task.spawn(function()
	while true do
		task.wait(20)
		if Engine:IsZombie(LocalPlayer) and RisytalEngine:BasicCheck(Character) then
			local sound = Instance.new("Sound")
			sound.SoundId = funnygrowls[math.random(1,3)]
			sound.RollOffMaxDistance = 40
			sound.Name = game:GetService("HttpService"):GenerateGUID(false)
			sound.Volume = 1 
			sound.Parent = Character.Head
			sound:Play()
			game:GetService("Debris"):AddItem(sound, 4)
		end
	end
end)
--Loop 2
--Sanity check for shop FF
task.spawn(function()
	repeat task.wait()
	until LocalPlayer.Character:FindFirstChild("HumanoidRootPart")
	while true do
		game:GetService("RunService").Heartbeat:Wait()
		if Character:FindFirstChildOfClass("Humanoid").Health <= 0 then
			break
		end
		if (Character.HumanoidRootPart.Position - workspace.MAP2122.SHOP11.Magnitude <= 10 then
			Character:FindFirstChildOfClass("ForceField"):Destroy()
		end
	end
end)

There are also loops and repeats that are triggered by events.

	while __CHARSTATS:WaitForChild("__BLEEDING").Value == true do
		task.wait(1)
		__CHARSTATS:WaitForChild("__BLEEDING"):WaitForChild("__BLEEDINGTIME").Value -= 1
		if Humanoid.Health == 2 then
			break
		end
		Humanoid:TakeDamage(4)
		--EventsFolder.BleedEffect:FireClient(game:GetService("Players"):GetPlayerFromCharacter(script.Parent))
		if __CHARSTATS:WaitForChild("__BLEEDING"):WaitForChild("__BLEEDINGTIME").Value <= 0 then
			Character.Health.Enabled = true
			__CHARSTATS:WaitForChild("__BLEEDING").Value = false
			break
		end
	end

Moving this to #help-and-feedback:code-review

You can try making a variable outside of the CHARSTATS while loop.

local __BLEEDING = __CHARSTATS:WaitForChild("__BLEEDING")
local BLEEDINGTIME = __BLEEDING and __BLEEDING:WaitForChild("__BLEEDINGTIME")

while __BLEEDING and __BLEEDING.Value == true and BLEEDINGTIME do
	task.wait(1)
	if not __BLEEDING then break end
	BLEEDINGTIME.Value -= 1
	if Humanoid.Health == 2 then
		break
	end
	Humanoid:TakeDamage(4)
	--EventsFolder.BleedEffect:FireClient(game:GetService("Players"):GetPlayerFromCharacter(script.Parent))
	if __BLEEDING and BLEEDINGTIME and BLEEDINGTIME.Value <= 0 then
		Character.Health.Enabled = true
		__BLEEDING.Value = false
		break
	end
end

You can also make local variables on RunService, Debris, and HttpService.
ex:
local RunService = game.GetService(game, "RunService") (This is a micro-optimization, though it sacrifices readability over speed, by sacrificing readability I mean not being able to reference methods in the service, such as .Heartbeat not appearing when typing it out.

I personally recommend using task.delay instead of Debris, it can still be into 1 line by doing the following:
task.delay(4, sound.Destroy, sound)

The Loop 2 can be improved into:

--Loop 2
--Sanity check for shop FF
local heartbeat = game.GetService(game, "RunService").Heartbeat
local LocalPlayer = game.Players.LocalPlayer
local thread = nil
thread = task.spawn(function()
	--// you can add a timer for this repeat loop, to avoid a client memory leak
	local Character = LocalPlayer.Character
	local hrp = Character and Character:FindFirstChild("HumanoidRootPart")
	repeat 
		if not LocalPlayer.Character then break end
		Character = LocalPlayer.Character
		hrp = Character:FindFirstChild("HumanoidRootPart")
		task.wait()
	until Character and hrp
	
	local hum = Character:FindFirstChildOfClass("Humanoid")
	while hum and hrp and Character do
		heartbeat:Wait()
		if hum.Health <= 0 then
			break
		end
		if hrp and (hrp.Position - workspace.MAP2122.SHOP11.Magnitude <= 10 then
			local forcefield = Character:FindFirstChildOfClass("ForceField")
			if forcefield then forcefield:Destroy() end
		end
	end
	if thread and typeof(thread) == "thread" then task.cancel(thread) end
end)

Please let me know if I did something wrong here, I would gladly change it, hopefully this helped you with the issue you’re having.

1 Like

The thing is the loop is triggered by a bindable event that’s why. But I appreciate the help!
Also it’s a server-script, I just named player LocalPlayer for convenience.

local Character = script.Parent
local LocalPlayer = game:GetService("Players"):GetPlayerFromCharacter(Character)
1 Like