How to keep the NPC following the player without ending the pathfinding service?

How to keep creating waypoints without the pathfinding ending, so that it keeps following the player?

Functionality: Any npc with a dinosaurRootPart will follow the player if it’s inside the sphere, which is a hitbox welded to the player initiated only when the player walks.

local script

local player = game.Players.LocalPlayer

local RunService = game:GetService("RunService")
local PhysicsService = game:GetService("PhysicsService")

local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local humanoidRootPart = character:WaitForChild("HumanoidRootPart")

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local assets = ReplicatedStorage.Assets
local walkSphere = assets["Walk sphere"]
local runSphere = assets["Run sphere"]

local dinosaurMainNPC = workspace:WaitForChild("main NPC2")

local dinosaurWalkToRemote = ReplicatedStorage.dinosaurWalkTo

local weldConstraint1 = Instance.new("WeldConstraint")
weldConstraint1.Part0 = humanoidRootPart
weldConstraint1.Part1 = runSphere

local weldConstraint2 = Instance.new("WeldConstraint")
weldConstraint2.Part0 = humanoidRootPart
weldConstraint2.Part1 = walkSphere

weldConstraint1.Parent = workspace
weldConstraint2.Parent = workspace

walkSphere.CFrame = humanoidRootPart.CFrame
runSphere.CFrame = humanoidRootPart.CFrame

local isCharacterHoldingBreath = false
local sphereType = "none"
local activeSphere = nil
local isPlayerMoving = false

-- detect if the character is walking or running with humanoidDirection
RunService.Stepped:Connect(function()
	if humanoid.MoveDirection.Magnitude > 0 then
		-- if character is walking
		if not isPlayerMoving then -- Only print when state changes
			print("player is walking")
			isPlayerMoving = true
		end
		walkSphere.Parent = workspace
		sphereType = "walkSphere"
		activeSphere = walkSphere
	else
		if isPlayerMoving then -- Only print when state changes
			print("player stopped moving")
			isPlayerMoving = false
		end
		walkSphere.Parent = assets
		runSphere.Parent = assets
		sphereType = "none"
		activeSphere = nil
	end
end)

local overlapParams = OverlapParams.new()
overlapParams.FilterDescendantsInstances = {workspace}
overlapParams.FilterType = Enum.RaycastFilterType.Include

local function dinosaurInsideSphere()
	-- Return false immediately if no sphere is active
	if not activeSphere or sphereType == "none" then
		print("No active sphere")
		return false
	end

	-- Also check if the active sphere is actually in workspace
	if activeSphere.Parent ~= workspace then
		print("Active sphere not in workspace")
		return false
	end

	local foundDinosaurs = {}
	local timeElapsed = 0
	local connection
	local result = nil
	local finishedChecking = false

	connection = RunService.Heartbeat:Connect(function(deltaTime)
		timeElapsed = timeElapsed + deltaTime

		-- Double-check the sphere is still valid before using it
		if not activeSphere or activeSphere.Parent ~= workspace then
			connection:Disconnect()
			result = false
			finishedChecking = true
			return
		end

		local success, hitParts = pcall(function()
			return workspace:GetPartsInPart(activeSphere, overlapParams)
		end)

		if not success then
			print("Error in GetPartsInPart:", hitParts)
			connection:Disconnect()
			result = false
			finishedChecking = true
			return
		end

		for _, part in hitParts do
			if part.Name == "DinosaurRootPart" then
				local enemyChar = part.Parent
				-- Ensure it's a valid character model with a Humanoid
				if enemyChar:IsA("Model") and enemyChar:FindFirstChildOfClass("Humanoid") then
					foundDinosaurs[enemyChar] = true
				end
			end
		end

		if timeElapsed >= 0.3 or next(foundDinosaurs) then
			connection:Disconnect()
			if not next(foundDinosaurs) then
				result = false
			else
				local dinosaurList = {}
				for dinoChar, _ in foundDinosaurs do
					table.insert(dinosaurList, dinoChar)
				end
				result = dinosaurList
			end
			finishedChecking = true
		end
	end)

	-- Wait until the check is complete
	repeat
		task.wait(0.01)
	until finishedChecking

	return result
end

local pathFindingService = game:GetService("PathfindingService")
local path = pathFindingService:CreatePath({})

while true do
	task.wait(0.1)

	-- Only check for dinosaurs if player is actually moving
	if isPlayerMoving and activeSphere then
		local dinosaurs = dinosaurInsideSphere()
		print("Checking for dinosaurs. Result:", dinosaurs)

		if type(dinosaurs) == "table" and #dinosaurs > 0 then
			for index, dinosaurNPC in dinosaurs do
				print("Following dinosaur:", dinosaurNPC.Name)
				dinosaurWalkToRemote:FireServer(dinosaurNPC)
			end
		else
			print("No dinosaurs found")
		end
	else
		print("Player not moving, skipping dinosaur check")
	end
end

server script:
(The actual pathfinding here)

local RunService = game:GetService("RunService")

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local dinosaurMainNPC = workspace["main NPC2"]

local overlapParams = OverlapParams.new()
overlapParams.FilterDescendantsInstances = {workspace}
overlapParams.FilterType = Enum.RaycastFilterType.Include
-- Detects a hit from the player using GetPartsInPart. Documentation for GetPartsInPart: https://devforum.roblox.com/t/how-do-i-use-getpartsinpart/1555768

local dinosaurWalkToRemote = ReplicatedStorage.dinosaurWalkTo

local pathFindingService = game:GetService("PathfindingService")

local path = pathFindingService:CreatePath({
})

local function dinosaurWalkTo(npc, startingPos, endingPos)

	path:ComputeAsync(startingPos, endingPos)

	if path.Status ~= Enum.PathStatus.Success then
		warn("Failed to compute path for", npc.Name)
		return
	end

	local wayPoints = path:GetWaypoints()
	if #wayPoints < 2 then
		warn("Too few waypoints for", npc.Name)
		return
	end

	npc.Humanoid.PlatformStand = false
	npc.Humanoid:ChangeState(Enum.HumanoidStateType.Running)

	local waypoint = 2

	local moveToConnection
	
	moveToConnection = npc.Humanoid.MoveToFinished:Connect(function(reached)
		if reached and waypoint <= #wayPoints then
			waypoint += 1
			if wayPoints[waypoint] then
				npc.Humanoid:MoveTo(wayPoints[waypoint].Position)
			end
		else
			moveToConnection:Disconnect()
		end
	end)

	npc.Humanoid:MoveTo(wayPoints[2].Position)
end

--dinosaurWalkTo(dinosaurMainNPC, dinosaurMainNPC.HumanoidRootPart.Position, humanoidRootPart.Position)
--dinosaurHumanoid:MoveTo(dinosaurNPC.HumanoidRootPart.Position, humanoidRootPart)
dinosaurWalkToRemote.OnServerEvent:Connect(function(player, dinosaurNPC)
	local character = player.Character
	local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
	
	local dinosaurHumanoid = dinosaurNPC:FindFirstChild("Humanoid")
	
	--dinosaurHumanoid:MoveTo(dinosaurNPC.HumanoidRootPart.Position, humanoidRootPart)
	dinosaurWalkTo(dinosaurMainNPC, dinosaurMainNPC.HumanoidRootPart.Position, humanoidRootPart.Position)
	
end)


Note: You can run the scripts by adding a remotevent named “dinosaurWalkTo” in ReplicatedStorage and any npc(For instance Roblox default Rig) in workspace with a dinosaurRootPart(renamed duplicate HumanoidRootPart of the npc).

To clarify, you want to keep computing waypoints to follow a target player?

If so, you can periodically compute a new path in a separate thread from the one moving to the waypoints, and use the latest waypoints to move to the target.
At the end of the path, you can also specify a target part with Humanoid:MoveTo(), which will keep the NPC moving towards the player even if there are no more waypoints available.