Permanent UUID System in Unity

UUID

Whenever you’re making a save system or you’re making cross-scene references, you might come across a need for a unique ID for all your GameObjects. You might think Unity offers a solution for this, but there’s no clean solution offered yet.

Internally, each GameObject does have a UUID, but this value changes every run. This basically makes this value unusable.

Unity provides a git repository called guid-based-reference (https://github.com/Unity-Technologies/guid-based-reference) that provides this feature, but this comes with multiple disadvantages.

  1. A prefab instance’s Guid shows up as modified compared to the prefab. If you accidentally apply all changes, then this library will die.
  2. Guids are illegible. Wouldn’t it be better to mention an important GameObject as BossCharacter rather than 2c138012-f543-4caa-bcd4-e4a64bbeb623?
  3. Small memory inefficiencies. There are extra 8 bytes per instance to store a reference to a byte array. The sad part is that this array is only used during Unity’s serialization/deserialization.

The Solution

Here’s how CloudCanard’s UUID system handles these issues.

First, we have a lightweight serializable UUID struct EntityUuid.

Serialization works automatically via FieldOffsets, which make the serializable part share the same memory location as the Guid. This only works because the Guid is also a 16 byte-long struct.

EntityUuid‘s very last bit is used to indicate whether it is Explicit or Procedural.

Procedural UUIDs consist of 127 random bits. Explicit UUIDs spell out a name. The idea is that some GameObjects are too important to have a random bitstring as its ID. CloudCanards has a debug terminal that can target specific GameObjects by their UUID. For some GameObjects like Yanna, typing Yanna is a lot more intuitive than typing random hex.

The complexity of designing a UUID system comes from being able to duplicate GameObjects in the scene. We want the designers to freely copy-paste prefabs around the scene without breaking the rule that no two GameObject share a UUID. At the same time, we want to ensure that the newly duplicated GameObject gets a new UUID and not the previously existing GameObject.

We do this by detecting the (1) that gets appended at the end of a GameObject name. For GameObject with procedural UUIDs, their name format is some name @guid-tostring-value@. If the name is some name or some name @guid-tostring-value@ (1), then it is replaced with some name @some-other-guid@. Note that the GameObject name change is not marked as part of a prefab modification.

Hopefully, you found this helpful! There are some other systems in play here, such as a custom drawer that can edit Explicit UUIDs in prefab mode, but I left them out for brevity.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s