Archetypes

This document explains how Archetypes work internally. If you're looking for how Level of Detail works in coherence with CoherenceSync, see this page instead.

Basics

Level of Detail (or LOD-ing, for short) is a technique to optimize the amount of data being sent from the Replication Server to each Client. Often a Client doesn't need to get as much information about an Entity if it's far away. The way this is achieved when working with coherence is by using Archetypes.

Archetypes let you group components together and create distinct "levels of detail". Each such level must have a distance threshold, and a list of components that should be present at that distance. Optionally it can also contain per-field overrides that make the primitive data types in the components take up less space (at the cost of less precision.)

To define an Archetype, use the archetype keyword in your schema, then list the LODs in ascending order. Notice that LOD 0 does not need a distance, since it always starts at 0. Here's an example of a simple Archetype:

archetype Enemy
  lod 0
    WorldPosition
    WorldOrientation
    Health
    AnimationState
    
  lod 1 [distance "10"]
    WorldPosition
    WorldOrientation
    
  lod 2 [distance "200"]
    WorldPosition

In this example, any Enemy Entity that is 200 or more units away from the LiveQuery of a particular Client will only get updates for the WorldPosition. Any client with a distance of 10 – 200 will get WorldPosition and WorldOrientation, and anything closer than that will get the full Entity.

Given one or more Archetype definitions in your schema, you will have access to a few different data types and methods in your project (these will be generated when you run the Protocol Code Generator.)

  • ArchetypeComponent – this component has a field index that keeps track of which one of the Archetypes in your schema that is being used. If you add the ArchetypeComponent yourself you have to use the static constants in the Coherence.Generated.Archetype to set the index. These all have the name "Archetype name" + "Index", e.g. EnemyIndex in the example above.

  • An individual "tag" component (with no fields) called "Archetype name" + "Archetype", e.g. EnemyArchetype in the example above. This component can be used to create optimized ForEach queries for a specific Archetype.

  • LastObservedLod – this component holds the current LOD for the Entity. This can be used to detect when the Entity changes LOD, if that's something you want to react to. Note that this component is not networked, since the exact LOD for an Entity is unique for each Client.

  • Static helper methods on the Archetype class to instantiate the Archetype in a usable state. These are named "Instantiate" + "Archetype name", e.g. InstantiateEnemy in the example above.

Field overrides

If a component isn't present at a certain LOD, no updates will be sent for that component. This is a great optimization, but sometimes a little too extreme. We might actually need the information, but be OK with a slightly less fine-grained version of it.

To achieve this, you can use the same field settings that are available when defining components, but use them as overrides on specific LOD's instead.

Here's an example of the syntax to use:

archetype NPC
  lod 0
    WorldPosition
      value [bits "24"]
      
  lod 1 [distance "100"]
    WorldPosition
      value [bits "16"]
      
  lod 2 [distance "1000"]
    WorldPosition
      value [bits "8"]

Notice that the settings are exactly the same as when defining components. To override a field, you must know its name (value in this case.) Any field that is not overridden will use the settings of the LOD above, or the original component if at LOD 0.

Priority

Each component in an Archetype can also override the default priority for that component. Just add the priority meta data after the component, like this:

archetype NPC
  lod 0
    WorldPosition [prio "high"]

To read more about priority, see the page about Field settings.