Reducing Humanoid Lag

How would I go about reducing lag for humanoids? For my NPCs, I disabled a lot of states, disabled collisions, and even had each NPC controlled by one script. Doing these things I have helped increase my NPC count without major lag from 40 to about 200. But is there any other ways to help reduce lag further? My main goal is to get around 400 NPCs without substantial lag.

1 Like

Using async programming (coroutines) may be helpful, they are usually a very good solution to lag.

Other possible solutions could be to:

A) Reduce the frequency of operations. For example, zombies are pretty dumb and making them make a decision every heartbeat isn’t necessary.

B) Stagger calculations. Instead of calculating all NPC’s actions at the same time you could constantly calculate a smaller amount of them. Combining this with the previous solution may give you some better performance, since the previous solution would cause a large amount of load every X seconds (or however often you chose).

I haven’t tried these, but these should hopefully give you some form of start.

2 Likes

Could you explain B) with more detail please? I’m kind of confused.

For example, let’s say you chose to implement B) by doing something along the following:

while task.wait(1) do
	-- Decision code
end

This would cause all 400 something NPC’s to calculate their actions at once. What you could do is spread it out over a longer time, for example dividing it into 100 segments and doing one segment every 4th loop.

local npcSegments = {
	[1] = {
		-- Lots of NPC's
	},
	[2] = {
		-- Lots of NPC's
	},
	[3] = {
		-- Lots of NPC's
	},
	[4] = {
		-- Lots of NPC's
	}
}
local currentGroup = nil
while task.wait(.25) do
	currentGroup = next(npcSegments, currentGroup)
	if currentGroup == nil then -- We are past the last one.
		currentGroup = next(npcSegments) -- Get the first one
	end
	makeDecision(npcSegments[currentGroup]) -- Pass in a segment of NPC's
end

This would hopefully cause a little less lag, as a smaller portion of resources is used at a time. Instead of calculating all 400 actions at once you calculate 100 actions. Another solution could be to just do something like this:

local currentNpc = nil
while task.wait() do
	currentGroup = next(npcs, currentGroup) -- npcs is a list of NPC's
	if currentGroup == nil then
		currentGroup = next(npcs)
	end
	makeDecision(npcs[currentNpc])
end

I believe the above should be good enough, since you give the server some breathing room between each NPC. These may not be the best implementation of the idea, but hopefully it gets the idea across.

1 Like

Thanks, I’ll be sure to try that now.

I have done this and the NPC cap was bumped up by about 40, which is pretty good. Thanks.

3 Likes

Yes I’m researching and have done something similar to you my tips would be to consider making the parts of the npcs massless except the humanoidrootpart reducing the collission fidelity of R15 rigs to box, making sure the meshparts are not double sided when not neccessary. and turning off autojump enabled.

You can make the NPC appearance only on the client.

Suphi Kaner made a video about client sided npcs

The Server has information about where the npc should be and the client updates the npc models location to the servers info (either through attribute or server created part)