Custom NPC Service with HumanoidDescription to Dynamically create NPCs

The Implementation

So, Roblox recently added HumanoidDescriptions. And I thought they was pretty cool and useful. So I had the idea. What if I made an NPC from a HumanoidDescription. See, at first it would have been simple. Humanoid:ApplyDescription() but Roblox was like. “We have made it so that you can only use this in the way we like you to” So while I was using a base rig for the NPC it still complained. Causing me to recreate the HumanoidDescription system… well Sorta. I only recreated the ApplyDescription and LoadCharacterWithHumanoidDescription functions. I can still use the Players Service to get anyones description so long as I have the UserId. And I can get applied descriptions off of humanoids.

The Caveats

I combined this NPC Service with the CollectionService and hoping to incorporate events into the service (as roblox doesn’t let me keep my NPC class across events because its not a true object) I’m hoping to Add NPCAdded and CharacterAdded.

The Future

Right now there’s nothing really here but spawning NPCs. But NPCs can be considered a direct copy of Player objects which means they can have friends, chat and even be in builders club. I hope to eventually have relationships between NPCs so that they can hold conversations, as well as be autonomous and choose what to do kinda like the sims. Ofcourse they can still act as zombies. This system just let zombies act in a horde

This is probably an unnecessary approach but do let me know.

16 Likes

Nice job! By CollectionSystem, do you mean CollectionService or something within your code?

If you use Roblox’s CollectionService, I’d think that you’d be able to track whether a tag was added to an object through CollectionService:GetInstanceAddedSignal(tag) , which might be useful for checking whether an NPC has been added!

Seems very promising, keep up the good work!

1 Like

Sorry yeah I meant CollectionService. And NPCs are kinda like players in that they can exist without a Character. So while CollectionService works for the NPC character. They don’t really work out well with NPCAdded which is supposed to be like PlayerAdded where you can nest CharacterAdded within the scope of PlayerAdded. Hope I’m making sense. :smiley:

2 Likes

Haven’t touched this as of yet, since I started focusing on other parts of my game. But the next time I update this it will be with custom pathfinding :wink:

Does it spawn the npc based on the player’s preferred rig type?

It does actually, hypothetically speaking it can spawn R15, Rthro, or R6. But right now Since I built it in Default R15. The rig it uses is R15. And trying to load an R6 means the NPC has to unfortunately die. If I load the R6 rig from the beginning this should fix the issue. It uses the HumanoidDescription system. Since I can’t apply the description to humanoids thanks to Roblox. I simply manually read the values in the description and use the Insert Service to load and parent it to the Character.

It all depends on who’s appearance you are getting. I can’t say it works 100%. Just in cases where R15 is missing from the loaded asset it assumes your rig type is R6.

You may be able to apply descriptions on the npcs if you change the game’s settings to support the rig type you’re currently using.

1 Like

I’ll give it a shot. Everything but the rig type is on player choice. I’ve already implemented my own :ApplyDescription function so I might just keep it. (stubbornly :smiley: )

Not sure I understand why the new description system won’t work on NPCs, I posted in the main thread and someone replied that they should. What about the method :Apply description won’t work on an NPC?

Humanoid::ApplyDescription() cannot be used when the StarterPlayer or Animate 
script has been overriden

It would be that. Maybe I’m not creating the NPC’s character correctly I used to use a rig from the animation editor. But I’ve switched over to a copy of myself with the appearance stripped. Also Animate was a localscript, but due to it being an NPC I had to make it a server script. Which isn’t any issue because Roblox plays the animations locally anyway.

this look’s really cool it would be really useful in a sim’s type game or a game about npc’s living there everyday lives without having to script every single possible outcome

So, It’s been awhile since I touched this script. But with the release of the new Avatar Importer… I couldn’t NOT do so… :grinning:

Here’s the new additions and improvements so far.

I’m looking into adding NPC Behavior VIA a new system I call Druid. Druid associates an NPC with a “Type”. The Behavior for the NPCs are set based on the NPC Type. For instance… NPC’s might move differently based on what type they are. An NPC with the type of “Fish” will move differently from an NPC with the type of “Humanoid”. To accommodate my Kawaii shark.

This shark is able to be a playable character… But, there’ no animations or controller set up for it yet. But this is enough to get started.

Right now all NPCs have a default movement type of “Velocity”. So I’ll just apply a Velocity in a direction and the NPC will walk interpolate its animations towards it based on the velocity… As well as auto rotate towards the direction it’s moving.

Optimizations

So this new iteration I wanted NPCs to be local, but have an entity worth showing it exists on the server. This means the server remains authoritative for the NPC… but the NPC puts no load on the server because it only exists locally on the client. As pictured here. Not only does this provide improvements for the server, but it allows the local player to experience the game in a better fashion. I can allow the client to tell the server when they damaged the NPC. I can then run some server side checks and either allow the hit or reject it.

Server
image

Client
image

The only thing the client will handle, is telling the humanoid to walk towards it’s associated Entity.
The server will set the position of that entity. Of course this will not work on NPCs without a Humanoid. And I’m also looking into whether I should do away with the Humanoid all together. I keep the same workflow as any script working with any part in the workspace in all of my simulated objects. So If I were to remove it, ‘NPC.Humanoid’ is likely to still be a thing for consistency. All other Non Humanoid NPCs will strictly do Velocity movement.

Some of the script performance increase that came from this new method of spawning was more so inside of LoadCharacter and LoadCharacterWithHumanoidDescription. However I haven’t tested HumanoidDescription yet, as I use a custom implementation that loads each asset individually through Insert Service.

Which brings me to the next Caveat. As you know Roblox removed the ability to load Assets from Insert Service on the client. And even if they didn’t it would’ve still replicated to other clients. So when the server spawns a NPC… it is never added to the Workspace… and instead added to a Cache. This means performance improvements.

The client uses the CollectionService to listen for a NPC Entity added to the Workspace. It then looks into the cache and spawns the NPC locally.

That’s it for this small update.

3 Likes

Is this open source? I’d like to possibly mess around with it and try to fix some bugs with NPC lag spikes in my game if so.

There’s a previous version that’s uncopylocked in my inventory. The new changes that allow 300 NPCs hasn’t been uploaded yet however.

Awesome, thanks. I’ll check it out in the next couple of days and see if maybe it will help me with my problem & if so I might port my system to use this. :smiley:

For the version that’s up, it only handles NPC spawning . Just like to reiterate on that part. When I update it next, there won’t be any visual changes. I am removing bits of the player service API that is unneeded as this is a direct copy of that.

If it’s difficult to setup do let me know which parts you found difficult. :slight_smile:

2 Likes

Updated this after like a year or two. Refactored the code a bit. I’m not sure if there are any performance gains. It’s more class-based now and should be a bit more natural to programming like a natural Roblox Service.

Bits of the Player Service API that I copied was removed. Relevant bits remained. If anyone is still interested do let me know if there are any issues.

Example
-- Modules
local NPCService = require(script:FindFirstChild("Service"))

local NPC = NPCService.new("T0ny")
NPC.CharacterAppearanceId = 379535
NPC.SpawnLocation = Vector3.new(0, 5, 0)
NPC:LoadCharacter()

image

2 Likes

Your NPC Service is quite interesting. I’d like to use it in a current project of mine in order to spawn large amounts of enemy zombies using the server part method that you use above. Is this specific version open source? The asset you linked is the version that only create NPCs and apply Humanoid Descriptions (among a few other methods). If you are willing to send me a copy of the past version that allowed for large humanoid counts, please let me know. I’m interested in your Druid system as well.

Thanks!

P.S. If neither of these systems are open source, are there any other resources you would recommend me to explore?

I actually don’t have a version that uses the server entity. I fiddled around with it, but even today I’m still debating on whether or not that’s the best way to go about NPCs. It’s just that with all this talk from Roblox about evolutionizing avatars and doing away with humanoids for a more flexible character controller using state machines. I’m just not sure which direction I should take.

I’m still working on this service. I have added Pathfinding, but I’m still ironing out the bugs so I haven’t updated it with the new version yet. As far as getting what you’d like. I’d recommend maybe rolling out your own implementation. You’re free to use NPC Service as a base if you’d like. It is uncopylocked.

As of this moment, I don’t have any intentions of going the client/server route, My goal is to optimize humanoids as much as possible to hold off until the new character controller is released. If you have any questions let me know!

2 Likes