Jump to content
  • Advertisement
Vaclav

How to handle a player leaving in a multiplayer game

Recommended Posts

Hello,

This is a general programming architecture question.

In a multiplayer game, what is your approach to handle if one of the players has left?

The problem:

* Let's say there is one Player object that represents this player who has left the game.
* Now every game component that referenced this Player object has to set its references to NULL, so the Player object can be either garbage collected.
* These game components may also have to reset their internal state.
 

Possible approaches:
1. Subscribe all such game components that deal with Player objects class to a "Player Left" event which is broadcasted by the framework.
2. Do not store references to Player objects in any classes, but instead store only a Player ID number. Then the Player object can be received from the framework by the ID, or the framework shall return NULL if the player has already left the game.
3. Any other approach?

So what do you think about 1-3 points?

Share this post


Link to post
Share on other sites
Advertisement

How do you handle if a grenade explodes? Everyone who has a reference to that grenade need to remove that reference. It's the same problem.

Either option works, and they each have benefits and draw-backs. If you don't do a lot of object/object interaction directly, the ID may be easier. If you do a lot of objects-talking-to-objects, then a cached pointer is likely better.

 

Share this post


Link to post
Share on other sites

What language are you using?

In C++ 11 an option might be to use weak_ptr? I don't know if this differs significantly in performance from rolling your own with an ID.

in C# a WeakReference can be used which is similar.

Edit: I haven't really used either and would probably default to using an ID. But I'm facing similar considerations soon so I'll be tagging along for the pros and cons (I'm using C# myself).

 

 

Edited by blackone

Share this post


Link to post
Share on other sites

Thank you both of you.

I don't have much experience with C++ so let's leave the weak_ptr to the experts.

I'm programming in Java. I didn't know Java has WeakReference too.
With C#/Java WeakReference, you don't know when the garbage collector will actually collect the object, it may be done only later. In consequence you would also have to check a player.isConnected() flag before working with the object. This would also bring a kind of non-determinism to your code, which is bad (same principle as Effective Java Item 7: Avoid Finalizers).

I think what I'm going to implement in Java is something like this:

interface PlayerEnteredListener
  entered(player)

interface PlayerLeftListener
  left(player)

class PlayerManager
  entered(Player)
  left(Player)
  addListener(PlayerEnteredListener)
  addListener(PlayerLeftListener)
  removeListener(PlayerEnteredListener)
  removeListener(PlayerLeftListener)
  //other methods:
  List<Player> getAllPlayers()
  Player getPlayer(int ID)

This should be simple and easy to debug.

Edited by Vaclav

Share this post


Link to post
Share on other sites

This would also bring a kind of non-determinism to your code, which is bad

The core problem is that "players disconnecting" is non-deterministic. You don't have control over that.

What you can do in your code is have a clear interface to the non-deterministic parts of the program (player connection/disconnection and player commands) and funnel between non-deterministic and deterministic domains (code modules) in your program at pre-determined times (typically, once every main "tick" or simulation step.)

In many ways "player X disconnected" is no different from "player X walked forward" and is another event that your system needs to react to and do the right thing for. Typically, your network connection handling code will forward events from the connection, which includes things like "player gave a command," and thus also "player disconnected," and the rest of the code simply reacts to those commands. Your world, in turn, typically will emit events such as "bomb B exploded at position C" or "player Q picked up health pack H" or whatever. This will also include "player X disconnected" so that other players and entities who need to know this, find out about it.

Yes, this means that you have to sequence the shutdown of players, because other players will be referencing the original player entity after the network has disconnected but before everything is properly torn down. Typically, you solve this by having "network connection" be different from "player entity" in your object model. And, typically, you actually end up with an even finer granularity because different objects need different lifetimes. For example, "player controller objects" are often as thing, as are "player world effects" (spells, etc) Each of these objects have a carefully managed, well defined lifetime, and the role of the game engine is to make sure that objects live during their lifetime, emit events to those who need to see those events, and then reap the objects when they are supposed to go away.

Share this post


Link to post
Share on other sites

I don't have an opinion on how to implement this in a specific language, but as far as the approach goes, I really like storing ID's to objects instead of using references. One reason I took this approach with my multiplayer game is it translates seamlessly to client-server communications. If a player clicks on another player to select them, I store the player ID in the client UI layer as the 'targetted player' and query the server for the player data. I take the same approach in all the server code, for example if a player has an effect applied by another player, then again I store the ID of that player rather than a reference.

The only downside to this approach is of course the lookup cost when you do need to get the reference to do some work. At the moment I'm just searching arrays for the player so it's O(n), which of course if fine when you don't have many players, but eventually a hashtable will be better. But that'll be one of those "problems that mean you're successful" :)

Good luck!

Edited by redskyforge

Share this post


Link to post
Share on other sites

storing ID's to objects instead of using references

And what do you do when the object that the ID references, no longer exists?

Storing an ID may prevent the dereference of a stale pointer, but it doesn't prevent a bug, and in many ways, the crash from a bad pointer is better than the silent failure of a stale ID, because finding the former so you can fix it, is easier!

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!