Unfortunately I have a game in which I need hundreds of NPCs. It is an RTS style game. What I found is that just having hundreds of humanoids slows down my hefty 1.5k computer (NVMe, gaming ram, 1050 card, 7th gen I7). Looking at the profiler I found that it is the physics updates. What I’m going to have to do is make the NPCs be local to each client, anchored or can collide = false, no humanoid (maybe a AnimationController), and send updates only when required like when they start following a new path. Each client can then update the NPC’s CFrame as often as their frame rate allows using a simple start time and velocity along a path of points. What is nice about NPCs is that they only move where you tell them, so you don’t need to worry about them walking through walls as long as you don’t tell them to. xD But if you were to do this for regular player humanoids, you would need collision detection for walls and other obstacles.
The way I got a ton of NPCs was by creating a single part on the server to represent a AI entity. Rather than using bodyObjects, I Update their CFrames every 0.25 seconds (running through a table of entities). Using Pathfinding, I just CFramed the entities to each point while the client associates a character model (no humanoid and using animation controller) then tweens to the part associated with the model. Syncing the CFrame intervals along with the Tweening intervals enabled some very smooth results. Not to forget, it allowed me to reach some high npc counts (more than 125 running with impressive results). I use :GetPropertyChangedSignal() a ton with this, perhaps this would be of use?