I am currently working on a round based game that requires about 36 NPCS that randomly chooses from about 45000 different part to walk to with pathfinding, but their script causes lag, waits a little bit after walking to each waypoint, and also cause wait() to wait a lot more longer than it should. I've tried making one script that controls the NPCS globally and also cloning 2 scripts into each NPC(one for the movement and the other for restarting the movement script if the NPC have been stuck for more than 2 seconds) but it causes even more lag. I've also tried adding a script to the client that hides all NPCS far away from their character and show the ones that are close
This is the movement script
local PathFindingService = game:GetService("PathfindingService")
local npc = script.Parent
local Humanoid = npc:WaitForChild("Humanoid")
local Torso = npc:WaitForChild("HumanoidRootPart")
local Left = npc:WaitForChild("Left Leg")
local Right = npc:WaitForChild("Right Leg")
local height = npc.Head.size.Y + npc.Torso.size.Y + npc["Left Leg"].size.Y
local diameter = npc["Left Arm"].size.X + npc.Torso.size.X + npc["Right Arm"].size.X
local pathParams = {
["AgentHeight"] = math.ceil(height) ,
["AgentRadius"] = math.ceil(diameter/2),
["AgentCanJump"] = true
}
while true do
local path = PathFindingService:CreatePath(pathParams)
path:ComputeAsync(npc.Torso.Position, game.ReplicatedStorage.paths_folder.paths:GetChildren()[math.random(1, #game.ReplicatedStorage.paths_folder.paths:GetChildren())].Position)
local waypoints = path:GetWaypoints()
if path.Status == Enum.PathStatus.Success then
for i = 1, #waypoints do
cur_path = i
if waypoints[i].Action == Enum.PathWaypointAction.Jump then
Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
end
Humanoid:MoveTo(waypoints[i].Position)
Humanoid.MoveToFinished:Wait()
end
end
end
This is the script that detects when the NPC has stopped moving for more than 2 second
local npc = script.Parent
local root = npc.HumanoidRootPart
local max_stop_time = 2
local function check(pos)
local amount = max_stop_time / 0.1
while true do
amount -= 1
wait(0.1)
if root.Position ~= pos then
break
elseif amount <= 0 and root.Position == pos then
if npc:FindFirstChild("npc_ai") then
npc.npc_ai.Disabled = true
wait(0.1)
npc.npc_ai.Disabled = false
end
end
end
end
while wait(2) do
spawn(function()
check(root.Position)
end)
end
Client code that makes all NPCS far away invisible
local npcs = workspace:WaitForChild("npcs",5)
local camera = workspace.CurrentCamera
local maxdistance = 120
camera:GetPropertyChangedSignal("CFrame"):Connect(function()
if #workspace.npcs:GetChildren() > 0 and camera.CameraSubject and game.Players:GetPlayerFromCharacter(camera.CameraSubject.Parent) and camera.CameraSubject.Parent:FindFirstChild("Head") then
for _,a in pairs(workspace.npcs:GetChildren()) do
local child = a
if child:IsA("Model") then
local humanoid = child:FindFirstChild("Humanoid")
local rootP = child:FindFirstChild("HumanoidRootPart")
local animate = child:FindFirstChild("Animate")
if humanoid and rootP and animate then
if (rootP.Position - camera.CameraSubject.Parent.Head.Position).Magnitude > maxdistance then
for _,v in pairs(child:GetDescendants()) do
if v:IsA("BasePart") or v:IsA("Decal") then
v.Transparency = 1
end
end
else
for _,v in pairs(child:GetDescendants()) do
if (v:IsA("BasePart") and v.Name ~= "HumanoidRootPart") or (v:IsA("Decal")) then
v.Transparency = 0
end
end
end
end
end
end
end
end)
All I want is for the NPCS to move to random parts from a folder with pathfinding and not cause that much of a lag on the server
If I didn't make any sense please tell me, its my first post.

2 comments
One way I suppose is to 1. Don't use NPCs, 2. Following that, code your own pathfinding AI.
Another way is to nest tables in tables. Maybe partsTable[section].Number; with each section containing a thousand parts.