Humanoid NPC's lag when I play solo

I’m working on a game that has NPC Customers which spawn and queue up. The max amount of Customers that can appear at a time is 6.

If I test by just clicking Run in studio. The NPC Customers move smoothly.

But when I Play Solo (or any other mode where I spawn in) the NPC’s occasionally teleport forward slightly and for some reason they pause at each Part they walk towards for .5 seconds even though they shouldn’t.

Relevant Code

function Customer.New(Queue, Delay)
	spawn(function()
		if Delay then
			wait(Math:NextInteger(10, 25))
		end
		if RoomInQueue(Queue) then
			local Character = Customer.Create()
			local Root = Character.HumanoidRootPart
			local Humanoid = Character.Humanoid
			
			Root.CFrame = CFrame.new(Entrance.X, Root.Position.Y, Entrance.Z)
			Character.Parent = Queue.Customers
			
			Customer.Move(Humanoid, Vector3.new(Intersection.X, Root.Position.Y, Intersection.Z))
			Customer.Move(Humanoid, Vector3.new(Queue.Start.Position.X, Root.Position.Y, Queue.Start.Position.Z))
			Customer.MoveInQueue(Character)
		end
		Customer.New(Queue, true)
	end)
end
function Customer.Move(Humanoid, Position)
	Humanoid:MoveTo(Position)
	Humanoid.MoveToFinished:Wait()
end
function Customer.MoveInQueue(Character)
	local Queue = Character.Parent.Parent
	local ServePosition = Queue.Serve.Position
	local PositionInQueue = Customer.GetQueuePosition(Character, Queue)
	
	local ZPosition = ServePosition.Z + (Gap * PositionInQueue)
	Customer.Move(Character.Humanoid, Vector3.new(ServePosition.X, Character.HumanoidRootPart.Position.Y, ZPosition))
end

I’m unsure of what the problem is. I attempted to change my whole system by using TweenService to move the NPC’s instead of using Humanoid.MoveTo() by tweening the Position of the HRP. For some odd reason though, only the HRP moved and not the Body Parts welded to it.

IMPORTANT

I used the built-in Roblox recorder to record the videos. The first video shows the NPC's teleporting forward, this doesn't happen when I Run the game.

In the other videos, the teleporting forward doesn’t happen quite so much.

1 Like

Who has network ownership of the BasePart descendants of those NPCs? Considering you don’t seem to have any CFrame setter code aside from when an NPC spawns in, I have a feeling that the jolting is coming from network ownership. I can’t think of any reason why else an NPC would teleport forward when there is no code specifying that to happen.

This is all Server Side code which I forgot to mention so the Network Ownership of the Parts is the Server. There is only one store in the game (like Work at a Pizza Place) so it doesn’t make sense to set the Network Ownership to a Player as the NPC problem will occur for everyone but one player.

Are you just saying that the network ownership of the parts is the server or do you explicitly set the ownership, either via code in-game or in Studio? BaseParts have their ownership defaulted to automatic, regardless of whether they’re created at pre-compile or run time.

Setting the network owner to nil passes it to the server and disables automatic ownership assignment.

The default ownership is the Server. I tested by printing the ownership after I parent the part to the workspace.

I’m not sure if I understand your last two sentences.

If I don’t set the network ownership of a part, then it’ll change between the server or a player depending on if a player is close enough?

The server is the default owner but if automatic assignment is enabled, ownership is passed around to either a nearby client or held by the server. This is done in the backend, of course.

It’d be better to print out the result of GetNetworkOwnershipAuto over GetNetworkOwner (if that’s what you used initially), since this would be the determinant of whether or not automatic assignment is taking place. GetNetworkOwner only returns the owner at the time of the call so it’s not too helpful here.

If you don’t explicitly set the network ownership of a part, it uses automatic assignment by default - you are correct in the statement you made.

As for my last two sentences,

When a BasePart is created, it doesn’t have its network owner assigned when its created, so automatic network ownership is active. This means the network owner of the part is passed between nearby clients or the server by the physics engine.

Some information is available on the SetNetworkOwner documentation and furthermore the article on network ownership. SetNetworkOwner manually forces a network owner and disables automatic assignment. If the server network owns a part, the physics engine will not automatically hand off network ownership to the client.

In terms of unanchored parts and their physics, most often the hopping comes from the window between changing network owners. With SetNetworkOwner, you can ensure a constant network owner. This gets rid of that window, which causes physics hopping (or teleporting).

Setting all the Parts Network Ownership to nil fixed the problems. Thank you!