Script reaching over 50% Activity in Script Performance

Hi, I’ve been looking to optimise the scripts in a game I’m working on and I read somewhere that all scripts should be less than 3% Activity in the script performance tool in studio. The only script over 3% is this Bot Ai script which is working perfectly except for some reason seems to be causing a TON of lag and constantly in the 38-55% Activity range.

I presume it has something to do with the while wait() do on line 136, however I don’t know how else to have it so it will constantly check but without taking a huge impact on performance?

This is a server sided script btw.

local SearchDistance = 	100000000

local WanderX, WanderZ = 30, 30

function getHumanoid(model)
	for _, v in pairs(model:GetChildren())do
		if v:IsA'Humanoid' then
			return v
		end
	end
end


local Bot = script.Parent
local human = Bot.Zombie
local hroot = Bot.HumanoidRootPart
local zspeed = hroot.Velocity.magnitude
local head = Bot.Head
local vars = script.vars

local pfs = game:GetService("PathfindingService")
local players = game:GetService('Players')

local Monster = script.Parent

Monster.HumanoidRootPart:SetNetworkOwner(nil)

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

local path
local waypoint

local chaseName = nil

function GetTorso(part)
	local chars = game.Workspace:GetDescendants()
	local chaseRoot = nil
	local chaseTorso = nil
	local chasePlr = nil
	local chaseHuman = nil
	local mag = SearchDistance
	for i = 1, #chars do
		chasePlr = chars[i]
		if chasePlr:IsA'Model' and not chasePlr:FindFirstChild("Enemy") and not chasePlr:FindFirstChild("Helper") then
			chaseHuman = getHumanoid(chasePlr)
			chaseRoot = chasePlr:FindFirstChild'HumanoidRootPart'
			if chaseRoot ~= nil and chaseHuman ~= nil and chaseHuman.Health > 0 and not chaseHuman:FindFirstChild("Enemy") and not chasePlr:FindFirstChild("Helper") then
				if (chaseRoot.Position - part).magnitude < mag then
					chaseName = chasePlr.Name
					chaseTorso = chaseRoot
					mag = (chaseRoot.Position - part).magnitude
				end
			end
		end
	end
	return chaseTorso
end

function GetPlayersBodyParts(t)
	local torso = t
	if torso then
		local figure = torso.Parent
		for _, v in pairs(figure:GetChildren())do
			if v:IsA'Part' then
				return v.Name
			end
		end
	else
		return "HumanoidRootPart"
	end
end

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

-- wandering 
spawn(function()
	while vars.Wandering.Value == false and human.Health > 0 do	
		vars.Chasing.Value = false	
		vars.Wandering.Value = true
		local desgx, desgz = hroot.Position.x+math.random(-WanderX,WanderX), hroot.Position.z+math.random(-WanderZ,WanderZ)
		local function checkw(t)
			local ci = 3
			if ci > #t then
				ci = 3
			end
			if t[ci] == nil and ci < #t then
				repeat ci = ci + 1 wait() until t[ci] ~= nil
				return Vector3.new(1,0,0) + t[ci]
			else
				ci = 3
				return t[ci]
			end
		end

		path = pfs:FindPathAsync(hroot.Position, Vector3.new(desgx, 0, desgz))
		waypoint = path:GetWaypoints()
		local connection;

		local direct = Vector3.FromNormalId(Enum.NormalId.Front)
		local ncf = hroot.CFrame * CFrame.new(direct)
		direct = ncf.p.unit
		local rootr = Ray.new(hroot.Position, direct)
		local phit, ppos = game.Workspace:FindPartOnRay(rootr, hroot)

		if path and waypoint or checkw(waypoint) then
			if checkw(waypoint) ~= nil and checkw(waypoint).Action == Enum.PathWaypointAction.Walk then
				human:MoveTo( checkw(waypoint).Position )
				human.Jump = false
			end

			if checkw(waypoint) ~= nil and checkw(waypoint).Action == Enum.PathWaypointAction.Jump then
				connection = human.Changed:connect(function()
					human.Jump = true
				end)
				human:MoveTo( waypoint[4].Position )
			else
				human.Jump = false
			end

			if connection then
				connection:Disconnect()
			end

		else
			for i = 3, #waypoint do
				human:MoveTo( waypoint[i].Position )	
			end
		end
		wait(math.random(4,6))
		vars.Wandering.Value = false
	end
end)

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

while wait() do
	local nrstt = GetTorso(hroot.Position)
	if nrstt ~= nil and human.Health > 0 then -- if player detected	
		vars.Wandering.Value = false
		vars.Chasing.Value = true
		local function checkw(t)
			local ci = 3
			if ci > #t then
				ci = 3
			end
			if t[ci] == nil and ci < #t then
				repeat ci = ci + 1 wait() until t[ci] ~= nil
				return Vector3.new(1,0,0) + t[ci]
			else
				ci = 3
				return t[ci]
			end
		end

		path = pfs:FindPathAsync(hroot.Position, nrstt.Position)
		waypoint = path:GetWaypoints()
		local connection;

		local direct = Vector3.FromNormalId(Enum.NormalId.Front)
		local ncf = hroot.CFrame * CFrame.new(direct)
		direct = ncf.p.unit
		local rootr = Ray.new(hroot.Position, direct)
		local phit, ppos = game.Workspace:FindPartOnRay(rootr, hroot)

		if path and waypoint or checkw(waypoint) then
			if checkw(waypoint) ~= nil and checkw(waypoint).Action == Enum.PathWaypointAction.Walk then
				human:MoveTo( checkw(waypoint).Position )
				human.Jump = false
			end

			if checkw(waypoint) ~= nil and checkw(waypoint).Action == Enum.PathWaypointAction.Jump then
				connection = human.Changed:connect(function()
					human.Jump = true
				end)
				human:MoveTo( waypoint[4].Position )
			else
				human.Jump = false
			end

			if connection then
				connection:Disconnect()
			end

		else
			for i = 3, #waypoint do
				human:MoveTo( waypoint[i].Position )	
			end
		end
		path = nil
		waypoint = nil
	elseif nrstt == nil then
		vars.Wandering.Value = true
		vars.Chasing.Value = false
		CchaseName = nil
		path = nil
		waypoint = nil
		human.MoveToFinished:Wait()
	end
end

Any suggestions would be greatly appreciated,

Thanks, Aidan

You could check where the player is with a local script run service and if they get to close then fire a remote which calls a bot although this could get broken by hackers.

Yeah It realistically needs to be server sided, sorry

Maybe its the connection variable? I doubt it since not too long after it should be disconnected. But, if it isn’t being disconnected I could see how activity shoots up since you could have like a crap ton of connections running at once.

Also I doubt its the while wait() loop causing this. I have my NPC’s running in a .Stepped event constantly. While they aren’t that complex, (no waypoints just purely MoveTo) the activity never even reaches 1%.

did you get this script from the toolbox? Because I remember a script similar to this one that i got from a nextbot in the toolbox.

There’s a small problem with the getHumanoid function, using pairs instead of :FindFirstChild is bad practice unless you’re trying to get more than 1 humanoid.

what the :FindFirstChildOfClass function does here is that it looks for any instance under the model that is the class “Humanoid”.

-- from
function getHumanoid(model)
	for _, v in pairs(model:GetChildren())do
		if v:IsA'Humanoid' then
			return v
		end
	end
end

-- to

function getHumanoid(model) 
	return model:FindFirstChildOfClass("Humanoid")
end

One of the co-developers said they followed a tutorial. It seems to work at under 3% in a basic baseplate place, but as soon as we load it into our map it goes sky high

surely if it’s looking for only humanoid with the name “Humanoid” (Since it’s only searching for players characters)?

Edit: Ah I see what you mean now, yes that makes sense! Thanks.

I didn’t read through the code, but you probably don’t need to check so often…

You could keep the target an check every 0.5 or 1 seconds to see if there is anyone closer nearby.
This may significantly reduce activity, but I’m not sure.

What I’m trying to get across is, while wait() do is changed to while task.wait(0.5) do
I’m not sure if the script will work this way, because I didn’t fully read it, but it doesn’t really hurt to try.

Sorry if I’m not understanding correctly.

Would it be better to wait using run service (heartbeat) do you think?

I believe heartbeat runs on every frame, which would not be good for this case. However, I don’t use it very often, so I’m not sure. It would definitely increase script activity.

if i was to loop a RunService.Heartbeat:Wait() a few times, would that be better than using task.wait(1)?

It would be easier to just do

while task.wait(0.05)

Currently with your setup it waits 0.01 seconds in the loop, as that is the minimum time for task.wait()

1 Like

ok I’ll try them both, thanks :slight_smile: