Managing game object IDs

Started by
4 comments, last by ankhd 8 years, 1 month ago

Hi! I wanted to hear your opinions on how to manage game objects IDs, at runtime and in save files or game data. Have in mind I'm talking about a persistent world, RPG, think of any Elder Scrolls game (Oblivion, Skyrim, etc), also single player, so no additional restrictions for network stuff.

Currently my tiny project has only runtime entity ids only for the things currently loaded, which means I create an entity, which has an ID, and use that to fetch its components when I need them. After the program is closed, everything is lost.

Eventually I'll have to move this into some form of persistence, I'd need a way to store entity instances and their IDs, for normal base game data, and do the same for storing player's save files.

Afaik Elder Scrolls games have a couple of "levels" for this data:

  • First is the main game data. This stores the base game data for all things (NPCs, places, quests, etc). All objects have their own ID.
  • Second the "plugin" data. This stores official addons, mods, and that kind of thing. These also have their own IDs.
  • Third is the player data. These are the game files, I'm assuming it kinda works like the other two, storing the IDs of things the player modified from the base game (say, player killed an NPC, solved a quest, looted a dungeon, etc, that stuff will be stored there,), and also the things the player "spawned". Say that you spawn a demon companion, that NPC is new, or say that you crafted a sword, etc.

I'm not quite imagining how to handle such things. For example, if we're going to make a new unique ID for a crafted sword, we need to know all used IDs in the game, even for stuff that isn't loaded so not to step over an existing item. I'm guessing the ID list is either present in memory all the time, managed through an embedded database or memory mapped file maybe.

Thats fine because we know the IDs occupied by the base game and the ones the player modified. But what if the user makes a mod that adds a new item? Or if I release an official addon that adds a new town or something?

Now I'd need to patch up all the IDs of the addon, and/or patch up the IDs of the player's save game and all their references. Moreover, now the load order of the game data matters. If I load up an addon or another before/after they were before in a previous game run, their IDs will be different (ie, run 1: addon a gets loaded before addon b, so addon a IDs are smaller, run2: addon b gets loaded after addon a, addon b IDs are smaller now), and thats a whole different kind of ID patching D:

Any opinions/experiences about this?

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

My journals: dustArtemis ECS framework and Making a Terrain Generator

Advertisement
Disclaimer: Haven’t actually implemented a serialization system.

Here’s what I’m thinking:
1. UUIDs to identify types.
2. Physical memory address for objects IDs, if appropriate, otherwise an integer handle.
3. Serialized data should contain a header.
4. Header should contain a list of UUIDs used in the file. Use indexes into this list rather than full UUIDs.
5. When using physical address as object IDs, collapse to a uint16_t.

One thing you could do is make ID's only unique within the same file, and then give each object a new ID once it's loaded. This solves the problem of having ID collisions between files and reduces the risk of running out of IDs. However, it requires you to have some sort of ID patching system for deserialization, and It complicates cross-file references.

Just one thing to mention here is unless you are really hard up for memory, and this really should not be a place that is eating up memory, using 64 bit values for id's is generally perfectly acceptable. You can generate 100 id's per second for approximately 5.8 billion years without wrapping. As such, I humbly suggest you should not worry about it too much... :)

Its not too much about saving memory but simply how to manage all the ID patching (sounds like cumbersome logic to code), entity to entity references, prefab/template references, etc.

Googling a bit I found how TES handles plugins and player's IDs.

It has 8 bit preffixes: http://www.uesp.net/wiki/Skyrim:Form_ID

Apparently 00 is used for base game stuff, 01 for game patches, and from there and up for addons. Until FF which is used for "dynamically added objects", which is probably all the stuff the player encounters in a playthrough, ie, generated loot, dropped items, crafted items, spawned enemies, etc.

Which is more or less what was suggested. But I'm thinking I'll end up with triple IDs:

  • One ID (UUID or something that works) for base game/addon stuff. These get saved in the game data. Maybe with 8 or 16 bit preffix to indicate from which file they come from.
  • One ID for stuff the player interacted with (npc spawns, item spawns, etc). These get saved in the save file.
  • One ID for runtime entity handling. These are runtime generated as needed.

So for example, if the player spawned a skeleton in X place and left it there, I'd have:

  • Skeleton template ID from which it was spawned.
  • Save file ID which will be used to persist the state of the skeleton across runs.
  • Runtime ID to aggregate the skeleton's components like transforms, mesh, ai, etc (these need to be tiny and coarse since they're used to index into component arrays directly).

Moreover, if the game data load order is changed, that can be maintained in the save file. So if at load time there is some discrepancy at startup, it can repatch the IDs as necessary.

Sounds good? Any better ideas? Maybe I mis-understood something in your answers?

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

My journals: dustArtemis ECS framework and Making a Terrain Generator

all of the above and may be. use the objects ID as the location in memory(Map or some other container). This way if you need to fine the object in memory you can use its ID.

This topic is closed to new replies.

Advertisement