Seeking opinions on NPC Client/Server Distribution!

So, I have a game where players can buy up to 12 NPC “pets” that follow them around and attack whatever the player attacks. As I script these pets, what is the best way to divide up the work between the server and client?

Option 1: A single server script controls movement and animations for all pet NPCs of a given kind. (This is how I have it now. No problems with the few people I have tested with (less than 50 pets at a time.) Not sure if I will run into problems at higher pet numbers, tho. I have one server script per pet kind.

Options 2: Server runs movement from place to place and client runs all animations. (The classic approach. But I hesitate because a pet plays an animation every few seconds and so the client would have to do a loop search over all the pets every few seconds for every pet in the game in order to find the right pet to play the right animation. I could limit this to players within a given range or line of sight. But that is also costly. I would have to be running these functions on the server constantly for every pet (then why not just move and animate them on the server?)

Options 3: Client runs both movements and animations. I could have the client spawn in the pet and move and animate it, then just tell all the other players where and what the pet is doing so each client could make its own copy. This uses the least server power, obviously, but that is A LOT of work for the client (especially with lots of pets.) The client could be trying to move and animate lots of pets all by itself. Seems like a lot of work for one client.

Please give me your opinion (and reasoning) behind which of these three options is best. Thank you!!

The best option here would be to clump the pets together. So if you have 12 pets, then 2 groups of pets would be 6 per group. Or 3 groups of pets with each group containing 4 pets. Then the “group director” would tell the 4 pets what to do.

Hypothetically speaking with this implementation it should be like having 4 pets or 3 pets. As far as server / client boundaries go. It would be best for the server to tell the clients what pets the client have. Then let each client render its own groups. The server should only see a basepart with data attached.

At the end of the day, the client is going to be the one to render the pets. Not the server. Let the server handle the data, and the client handle the pets. To handle high number of pets it would be best to have a pool. Stream out pets that are irrelevant, stream in pets that are relevant.

2 Likes

A few questions on this solution. So your suggestion would be:

  1. server spawns in pet substitute part (a sphere)
  2. server moves substitute part from place to place. sends location data to client.
  3. clients divide up the work with each player controlling its own pets and then informing the other players

Is this basically right? I am not sure what you mean by “streaming” pets in and out or by “group director”. Have I understood you correctly?

Let’s assume that the sphere is using attributes. And the server is setting those attributes. Then you wouldn’t really need to “send data”. Since this would be done for you.

At that point the client could parse that data, and determine the positions of other pets based on the location attribute the sphere contains. The client can then tell it’s 4 pets that it has control over to follow those determined positions. (Some interpolation may be needed here.)

In this case, the other clients would also be creating and interpolating… So it is possible that depending on the implementation pets may be in different locations on each client. Though depending on the gameplay if that’s not a hard issue then it should be usable. If the pets location is required for your gameplay, then I’d recommend syncing that through the sphere as well.

The biggest changes to the implementation would be the server determining the positions for each pet in the group and adding that to the sphere as attributes. This way a player can’t say his pet is 50 miles away and attacking other players.

Okay, I see now. And the calculations done in each sphere would be server tho, right? Not sure that would save much power if all the spheres are running these functions constantly.

If you had to pick a second best, and easier, solution, what would you recommend?

What is the approximate upper limit for (say) option 2?

As Tony said, I’ve done this in the past and it seems like the best option! As for the question about position. If we know that the pets follow a player a certain way why not just have the pet follow the player on another client once the pet has started to move?

Player => Gets Pet => Server => Tells other clients this pet has been spawned => The other clients wait for this pet to move => then the other clients moves the pet right back to the position next to the player?

Meaning all you would have to do is spawn in the pet…?

2 Likes

Trying to think of a better way in order to fully calculate where the pet is, but attributes seem like the best way.

But then again the pets have to be close to the player, so why don’t we just check the magnitude between the player and what he/she is attacking…?

Interesting. By attribute do you mean something like an IntValue or StringValue in the sphere?

Well just made a quick edit, we can generally just check the magnitude between player and NPC (I guess…?) (On the server) <= this is when we try to attack an NPC, then we have the pets move towards it. We have the server know which NPC we have started attacking…?

So, client1 calculates pet movements/animations and sends the data to all the other clients who then create the relevant image. Is getting/processing information on a client a significantly less power intensive operation than calculating a magnitude and sending the data to server? If not, then I am not sure that this system actually saves the client much power. If player x just did all of the work for a given set of NPCs then it would be doing the calculating and sending. I find your system idea really intellectually interesting, but I question the overall load/power savings. Seems like the savings would likely be relatively small for a great deal more complexity. Am I missing something?

Client1, Client2, Client3

Client1 => spawns pet => {Client2, Client3} initialize movement on that pet meaning whenever the pet starts moving we load an animation or whatever until it has gone stationary. Whenever the client wants to attack an NPC we request to the server and ask where about the player is in reference to the NPC (checking the magnitude) if we find that the player is within reach then we tell the other clients => Client1’s pet is attacking Brian (NPC Name) we then have each client move Client1’s pet to Brian. And we start the process of attacking. Keeping in mind we have the server knowing what pets Client1 has and what NPC he/she is attacking. We then start draining health from the NPC.

1 Like

Whenever the Client1 leaves the NPC (takes away the pets from the NPC) we tell the server we are done. So that means while the pets are on this NPC as we know since from above we can drain health by knowing what pets Client1 is using we can essentially do damage depending on pets.

1 Like

Really interesting, but perhaps too complex for my limited scripting talents. Let me play around and see what I can do. Thank you for your thoughts?

Among the simpler solutions listed above, is 3 best? :slight_smile:

Yes, as long as you make magnitude and sanity checks it should be fine.

1 Like

Are there any other opinions out there? I would really like to hear what everyone who has scripted NPCs before thinks. Thank you!