Hi there, I know using infinite while () loops isn’t a good idea but I’m not sure how else I’d go about doing this with the desired effect?
Script:
while wait() do
local distance = 10
for _, v in pairs (game.Workspace:GetChildren()) do
if v:IsA("Model") and v.Name ~= "Dummy" then
for _, npc in pairs (NPCs:GetChildren()) do
if npc:IsA("Model") and npc:FindFirstChild("Humanoid").Health > 0 then
local humanRP = v:WaitForChild("HumanoidRootPart")
if (npc.HumanoidRootPart.Position - humanRP.Position).magnitude < distance then
npc.Humanoid:MoveTo(humanRP.Position)
end
end
end
end
end
end
local humanRP = v:WaitForChild("HumanoidRootPart")
WaitForChild means if any of them don’t have and never will have a root part, then this loop will lock up forever.
Instead, just ignore anything that doesn’t contain a rootpart (does not :FindFirstChild(“HumanoidRootPart”), or, slightly better yet, does not have a Model.PrimaryPart.
For that matter, why are you finding v’s HumanoidRootPart multiple times? It doesn’t change between loops. Move the line with humanRP 2 lines upward. No change in behavior whatsoever, but an appreciable increase in performance.
A NPC may find that two different vs are within 10 studs of them. If so, it will MoveTo twice. Flip the loops so that NPCs are looking for vs to move to, instead of having vs look for NPCs that should move to them. This will also let you look for the closestv, instead of sometimes abandoning closer targets to ones that randomly happen to be later in the workspace’s child list.
If v is supposed to be player characters, then just iterate over players instead, which lets you avoid iterating over everything in workspace.
The algorithmic time this loop takes to run is (m*n), where m is players (I assume) and n is NPCs. If there are few of one and few or many of the other, you’re fine. But if there are many of both, then you’re in big trouble.
e.g. 1 player and 50 NPCs is 50 checks. Add one more player and you get 100 checks. 5 players, 250 checks. It adds up extremely fast.
There’s no “simple” way to solve this, you’d have to split the world into rooms/regions/octrees/whatever positional data structure to avoid checking players/NPCs that obviously aren’t near each other.
I suggest renaming v to target for clarity
If you keep the NPCs model clean of anything that isn’t a NPC, then you can turn if npc:IsA("Model") and npc:FindFirstChild("Humanoid").Health > 0 then
into if npc.Humanoid.Health > 0 then
because anything in that model is guaranteed to be an NPC.
Ignore the people arguing about RunService, it does not matter at all.
That is false, RunService can be used on both states except that you can’t use RunService.RenderStepped as it is client only.
@Friendly4Crafter No, there is no need for that unless you care about high precision. wait() should be responsive as long as you have good performance on the server and not a lot of yielded threads that need to be resumed.
@Eestlane771 Your first point isn’t 100% valid, it could be very well that the character was just loaded and the root part may not have been created fast enough on the server, since character is dynamically created.
Better alternative, it uses WaitForChild with a timeout. After 15 seconds, if there is still no humanoid root part, it’s very very likely because the exploiter deleted their humanoid root part as soon as it was added.
local primaryPart = character.PrimaryPart or character:WaitForChild("HumanoidRootPart", 15)