18
\$\begingroup\$

I'm working on an entity system for a networked game and I'm assigning each entity a unique 32-bit integer id that I can use to serialize references to entities and the entities themselves.

Currently I'm just incrementing a counter every time an entity is created. I guess the ids will eventually run out but I don't really expect to have 4 billion entities. Also this avoids the problem if entity #5 is destroyed and we get an id of 5. Is it meant to refer to the new #5 or the old deleted #5?

The problem is that I'm not sure how to handle/avoid collisions. Currently if a client receives an update for an entity with an id higher than it's current "free id" it just bumps it's free id up to past that. But that doesn't seem very robust.

I thought about maybe assigning ranges to each client so they can allocate entities without conflicting (say the top n bits are the player number) but I'm worried about what happens if ranges began to overlap over time.

Is there a better way of handling this? Should I even care about ids overflowing or going past the end of the allowed range? I could add code to detect these cases but what would it do if they happen other than crash.

Another option is to use something with a higher chance of being unique like a 128-bit GUID but that seems really heavyweight for a game that's trying to minimize network traffic. Also, realistically I would never need more entities at one time then would fit into a 32-bit or even 24 bit integer.

Thanks!

\$\endgroup\$
6
  • 1
    \$\begingroup\$ Why don't all clients have the same entities? Are the clients not syncronized? Or is it a large world of some kind where the clients don't all run the same game. \$\endgroup\$
    – Philip
    Commented Oct 22, 2011 at 22:33
  • 2
    \$\begingroup\$ My architecture so far kind of loosely follows the UE3 one (more info here). Basically clients only know about entities that are near them in the world. Also, the clients don't run in lock-step but the server controls most of the logic and can overwrite client data at any time. I guess now that I think about it I could only allow the server to create entities and make clients use RPC to do this. I'm not sure of the best approach. I'm a graphics programmer by day :) \$\endgroup\$
    – Lucas
    Commented Oct 22, 2011 at 22:44
  • 1
    \$\begingroup\$ I think, as you say, it should be handled only by the server if that is at all feasible within your given architecture. Then keep a stack of free entity IDs that exists separate to the entity list / map, so you know what IDs are available. Failing an authoritative server model, then your ranged approach should work okay, in terms of ranges. Four billion is a lot, even to divide amongst 4000 players in an MMO. Then use the same approach to keep track of available IDs as with an auth. server. \$\endgroup\$
    – Engineer
    Commented Oct 22, 2011 at 23:16
  • \$\begingroup\$ @Lucas, your link says "The server identifies the set of "relevant" Actors for each client". This implies the server knows about all entities, and is in a position to enumerate them. \$\endgroup\$
    – Kylotan
    Commented Oct 23, 2011 at 16:11
  • 1
    \$\begingroup\$ Sure, but what if a client creates new entity A but before it can get the creation message the server creates new entity B, they both get assigned the same "free" id. \$\endgroup\$
    – Lucas
    Commented Oct 23, 2011 at 21:22

4 Answers 4

13
\$\begingroup\$

What I have done is make the server do everything. The client(s) can merely ask the server to do something but can't do anything themselves. In this case, the server will always be the one assigning IDs and problem solved.

I have not dealt with client-side prediction while waiting for the server to approve actions like: "Shoot a rocket" or "Make a solar station here". These actions will want to create entities, and entities have IDs. So far, I'm just sitting on my thumb waiting for the server, but I believe what needs to be done is create a temporary entity while you wait for server approval. When you receive server approval, the server will assign an ID and you can either update or overwrite the temporary object.

I also have not dealt with an ID overflow, but if the server is in full control and it detects an overflow, it could do whatever handling you deem necessary (restart at 0, pick from a free stack, crash, etc) and all of the clients won't even know or care. The clients will just accept the IDs handed out by the server.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks for all the good info guys! I ended up going with the server creates all entities approach, but if I find that introduces too much latency I will try Trevor's method. \$\endgroup\$
    – Lucas
    Commented Oct 23, 2011 at 21:29
  • \$\begingroup\$ For client specific ids (needed for prediction while waiting for the server) you could simply use a prefix on the id. \$\endgroup\$
    – danijar
    Commented Dec 15, 2012 at 22:06
7
\$\begingroup\$

When I did this for a commercial multiplayer game, I did exactly what you propose: use a 32-bit GUID integer, where the top eight bits are the player number, and the bottom twenty-four bits contain a locally unique number.

If/when the local number overflows (in my case, it would almost never happen; under normal usage, it would have taken four to five days of continuous playtime in a single network session to cause it to happen), the owner would send a "Resetting all my objects" message, and renumber all still-existing objects starting from zero ago. The message told all peers to discard objects they had received and to query for them again.

A more fancy approach would be a "Object with GUID 'n' is now Object with GUID 'm'" message for every existing object. But in my case, it was unlikely to ever actually happen, and I didn't think people would really mind remote objects vanishing from the world for half a second, after five days nonstop play in a single network session. ;)

\$\endgroup\$
1
  • \$\begingroup\$ That's a good idea for handling overflow. Simple, but I didn't think of it :). "Forgetting" all your entities is nice since it can basically reuse the same codepath the client uses when it joins the game \$\endgroup\$
    – Lucas
    Commented Oct 23, 2011 at 21:30
4
\$\begingroup\$

If your clients can spawn their own entities, I'm guessing you have a peer-to-peer multiplayer game.

If that's the case, you probably don't have too many clients. Certainly not more than 256. And your entity id is guaranteed to fit into 24 bits (16000000+ entities is enough for everyone!). So, just make the highest byte of your id equal to client's id:

entityId = clientId<<24 + (maxEntityIn++)

or something.

And if I'm wrong and you have an authoritative server, just never create new entities on clients.

\$\endgroup\$
1
\$\begingroup\$

I'm using the 'most naive' method (just increment an integer for each new ID) in my persistent multiplayer game and it works fine because I don't let the client create new ID:s.

If you let the client decide (by using a sort of GUID technique explained), the client can also introduce various bugs by assigning an Old ID to a new item (that is just what I thought up on top of my head thinking like 5 seconds, there might be loads of other loopholes).

As usual, to prevent cheating, the server should do ALL creation and validating.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .