# RealtimeModel

A RealtimeModel represents a collection of states to synchronize. A typical RealtimeModel looks like this:

[RealtimeModel]
public class MyModel {
    [RealtimeProperty(1, true )] private string _name;

    [RealtimeProperty(2, true )] private Color _avatarPrimaryColor;
    [RealtimeProperty(3, true )] private Color _avatarAlternateColor;

    [RealtimeProperty(4, false)] private Vector3 _movementVelocity;
}

Each field is required to be a primitive type. Models are designed to synchronize data that can be easily serialized and transmitted to other clients. It is not possible to store a complex object, such as a Material or Texture, in a model. You'll need to pick out the pieces of data you would like to synchronize and use a RealtimeModel to synchronize them. Attempting to synchronize every public property of such an object would require too much bandwidth to do correctly, and in most cases, the values do not change very often.

Tip: If you're new to RealtimeModel, check out the Synchronizing custom data guide, it provides an excellent overview of how to use a RealtimeModel in practice.

# RealtimeModel / RealtimeProperty attributes

The [RealtimeModel] attribute is used to signal to Normcore that this is a model class and that it should be available for model compilation. The [RealtimeProperty] attribute notates how the field should be synchronized.

# PropertyID

The first field is the property ID. This is an identifier used by Normcore to distinguish this property from others when sending data to and from the server. The property ID needs to be unique, but only to this model. It does not have to be unique to the whole project. It's generally a good idea to start numbering property IDs with 1 for each model you create.

If you need to change the type of this property, you can create a new property with a new property ID and deprecate the existing one. This ensures that newer versions of your application can still communicate with older versions. If you would like to delete this field altogether, make sure to retire its property ID so it is not reused for something else. Comment out the field, and leave it in your source code so you can see previously used property IDs.

# Reliable / unreliable

The next option marks whether the property should be synced reliably or unreliably. In general, if you plan to change a property frequently—for instance, when animating a color or moving a transform—you should use an unreliable property. Unreliable updates are not resent if they’re dropped in transit because it’s expected that another update will follow shortly after.

Reliable properties are good for things that you update once and that should therefore be resent if the packet is dropped in transit. This is great for state updates, such as whether your game has started or not. When you change the value, Normcore ensures this value is received by all clients and applied to the datastore in order.

# Change event

The last option is an optional argument that specifies whether you would like a change event added to the model. When this is set to true, a C# event that will fire when a property is changed locally or remotely is added to the model by the model compiler. This is a useful signal to update your scene to match the model.

# Compiling a model

Once a model is written, it can be compiled in the Unity editor by highlighting the class and clicking "Compile Model." It's worth noting that if any script in your project does not compile, Normcore's model compiler will be unable to load any of the state of your model. This will be fixed in a forthcoming Normcore update.

# Tip: Removing / renaming a property without breaking compilation

At the moment, Normcore requires your project to compile for the model compiler to read the [RealtimeProperty] attributes on your model. Unfortunately, this means that removing properties or renaming them breaks references in the code generated by the model compiler. We recommend using the following steps to remove or rename a property without breaking references from the autogenerated model-compiler code:

To remove a property:

  1. Start from a state in which your project compiles successfully.
  2. Remove the [RealtimeProperty] attribute, but leave the field definition in place. At this point your project will still compile.
  3. Recompile the model, which will remove all references to the private field from the autogenerated model code.
  4. Delete the field definition.

To rename a property:

  1. Start from a state in which your project compiles successfully.
  2. Create a new realtime property and field definition with the correct name.
  3. Remove the [RealtimeProperty] attribute from the old definition, but leave the field definition with the old name in place.
  4. Recompile the model, which will remove all references to the old field, and generate a property for the new field.
  5. Delete the field definition for the old name.