2
\$\begingroup\$

Using a DOD approach, what is the typical way to handle dealing with the actual IDs of game objects?

Obviously, each entity has a unique entity_id that is generated in-game. And using the component system, the game (server side at least) can determine if the entity is an item, an NPC, a player, etc. My question concerns handling the 'data' ID, as in the ID of the item/npc stored in the database.

The first approach I can think of, is just having one gigantic 'entities' table, with columns that can represent what that entity actually is. In this approach, all entities will have a unique ID (ie, the primary key in the database).

The second approach is to have an Items table, an NPC table, a Vegetation table, etc. But assuming on how one designs the table, there can be an item with an ID of 1, and NPC with an ID of 1, and a Tree with an ID of 1.

Because its an MMO, its inefficient to send all data concerning the entity to the player through a packet. Instead, the client side would have the same data set, so that when one of these pre-defined entites spawns in, the packet can simply tell the ID and location, then the client can look up the ID and construct the entity itself.

Would it then be best to have seperate packet types per entity type? This would be necessary if using the second approach, as there can be entities with the same 'data ID'; IE, a 'NPC spawned' packet, an 'Item spawned' packet. But at the same time, I would also need to include a bit of extra data, the entity_id generated in-game, so the server can confirm which entity the player attacked/picked up, etc. This of course means slightly more bandwidth usage.

The first approach would simply mean I have a single packet type, 'entity spawned', with the data ID and location. Because the first approach is guaranteed to have 'unique' data IDs, would I even need to send the 'entity_id', assuming the entity_id is the same as the data ID?

Sorry if this question isn't too clear. I guess the tldr version is: Whats the best way to design the data tables to hold entities, and whats the best way to design the packets that 'send' that entity to the client?

\$\endgroup\$

3 Answers 3

3
\$\begingroup\$

I would generally not put entity IDs and type IDs into the same number-space. That just leads to confusion about whether a specific ID refers to an entity type or an unique instance of that type.

The entity with the ID 1831347 can be the player with the ID 157 ("Bob"), a mob of type 157 ("Goblin Elite Archer"), an NPC of type 157 ("Potion vendor") or a resource node of type 157 ("Acacia Tree"). The same applies to the entity with the ID 1831348 which appears on the map a second later.

So when you spawn a new entity, then the client doesn't know what kind of entity it is. So the "New entity spawned" packet would include:

  • EntityID
  • Type
  • TypeID
  • All the information relevant to an entity of this type (cosmetic options for player-characters, hit points for mobs, resources left for resource nodes...)

You could also go a bit further with the Entity - Component - System philosophy and also expose components in the netcode. In that case the packet would still begin with the entity ID, but instead of having just one type ID it would have a list of components with their component IDs and component-specific data. So for example a player-spawned packet would look like this:

  • EntityID
  • Position component:
    • x
    • y
  • Combatant component:
    • HP
    • MP
  • PlayerCharacter component:
    • Name
    • Class
    • Level
  • Cosmetics component:
    • hair type and color
    • armor type and color
    • pants type and color
    • ...

While a mob would look like this:

  • EntityID
  • Position component:
    • x
    • y
  • Combatant component:
    • HP
    • MP
  • Mob component
    • Mob type ID

Or a resource node would look like this:

  • EntityID
  • Position component:
    • x
    • y
  • Resource Node component
    • Resource type ID
    • amount left
\$\endgroup\$
1
\$\begingroup\$

The first approach I can think of, is just having one gigantic 'entities' table, with columns that can represent what that entity actually is. In this approach, all entities will have a unique ID (ie, the primary key in the database).

The second approach is to have an Items table, an NPC table, a Vegetation table, etc. But assuming on how one designs the table, there can be an item with an ID of 1, and NPC with an ID of 1, and a Tree with an ID of 1.

You could also use a hybrid approach where you leverage the discriminator pattern. This idea is heavily biased around the notion of Discriminated Inheritance from JPA.

The idea is you have a base table, called entities that holds several key columns and all attributes that are shared across all entity-types. That table could look something like:

ENTITY_ID (PK) | DISCRIMINATOR (INDEXED) | ATTRIB1 | ATTRIB2 | ATTRIB3 | ... 

The discriminator is basically a special column that designates which join is applicable for that row, such that if the value equates to NPC, then that row joined with the npcs table based on the entity_id would yield a complete snapshot of what that entity is composed of.

Since most queries are often interested in a very specific type of entity given the context, this separation of the in this way could offer great performance.

So you can imagine a query for all items with a given id would yield

SELECT e.*, i.*
  FROM entities e, items i
 WHERE e.entity_id = ?
   AND e.discriminator = ?
   AND i.entity_id = e.entity_id

Instead, the client side would have the same data set, so that when one of these pre-defined entites spawns in, the packet can simply tell the ID and location, then the client can look up the ID and construct the entity itself.

I think that depends on the game & context to some degree.

Lets assume the server sends the client some archetype_id that the client can use to lookup in its data files and determine exactly how to spawn that entity. The archetype defines the model, components, and other static attributes that describe how the entity should be constructed.

But what happens if the definition of that archetype is wrong under certain conditions? Is it permissible to ask the client to apply a patch to fix such things as a "hotfix" or does company policy mandate that a full build and release cycle be involved for that type of change?

The benefit of the server sending the archetype definition in the packet is that the client is simply a renderer of that information. If a specific entity is being rendered as an Orc but should be an Elf, a quick server hotfix can be made and immediately the client will update how it renders the entities accordingly without ever having to ask the client to update.

\$\endgroup\$
0
\$\begingroup\$

Typically what is done is the server creates an entity in game and assigns it a unique ID (you could just start counting from 0). Upon its spawning, the server then sends a packet to its clients, instructing them to create this new entity with all its attributes and with this ID. After that, packets can just use the entity's ID to reference actions that happen to the entity and what not. The clients and server can easily just keep track of data tables as you said. Perhaps one that dynamically grows and is indexed by id, or use a hashmap as entities and their IDs are destroyed. (:

\$\endgroup\$

You must log in to answer this question.

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