Views, Updates and Keyframes - themeldingwars/Documentation GitHub Wiki

Views and Controllers

A View is a collection of namespace networked variables from the server.
A Controller is much the same but present on the client that owns that entity, and allows that client to send commands to the server about it.

Messages related to these views are communicated on the GSS channels.

Shadow Fields

The state in views are variables referred to as ShadowFields, these are replicated down from the server to the client in Keyframe or Update messages.

Some fields are just a single value, whilst other fields are structs with several values. Some fields are nullable.

The ShadowFields of a view are defined in an order, creating a ShadowFieldIndex value that can be used to refer to them.

A view can have up to 128, ShadowFields, the range -1 to -128 are reserved to unset nullable fields.
So if a update comes in for ShadowFieldIndex 20 then that field should be set to that value. But if an update comes in for ShadowFieldIndex -20 then the ShadowField 20 should be nulled and unset.

View Update Types

The view state can be updated directly through the ShadowFields in two ways.

Keyframe (msg id: 3 or 4)

The keyframe message can be thought of as transmitting the full networkable state of the view. It is used primarily to introduce new entities. Keyframes per entity can be rate limited to 1 every 3 seconds

The format of a keyframe message can be described as:

  • (GUID)
  • (Bitfield)
  • The values of every ShadowField in the order of the ShadowFieldIndex

GUID

The 8 byte player/account GUID is only included for Controller type views, which use message id 4.

Bitfield

If the view has nullable fields, a bitfield will be included that describes which of the nullable fields that are set.

One bit for each nullable field, the bits are used in the same order that the nullable field appears in the ShadowFieldIndex. So first bit is the first nullable field in the index, second bit is the second nullable field in the index, and so on.

If a field is active and present in the data, the value of the corresponding bit in the bitfield is 0. If the field is not active (null) then the value is 1. Bits on the last byte that are not tied to any nullable value will be set to 0.

(For example, if there is only 1 nullable field on a view, then the bitfield is represented by 1 byte with the first bit determining the state of that nullable field and all other bits are 0.)

Values

Its important to note that the 1 byte ShadowFieldIndex values of each field are not included in the Keyframe. The values of each field are just written in the appropriate order.

In regards to the nullable fields, their values will be expected at their appropriate position within the ShadowFieldIndex if they are active. When the nullable field is null, no value at all is printed for that field.

So if a nullable field is in-between two regular fields, the data would be included in-between those two fields only if the nullable field is active.

Update (msg id 1)

An update message is a more light weight way to update view state if only a few values need to be changed.

The format of the update message is any number of the following format:

  • 1 byte ShadowFieldIndex
  • (The new value of that ShadowField in its appropriate format)

When clearing a nullable field, you send the negative index value without any additional data.

Remove Message (id 5, id 6)

The remove message is used to clear up views when they are no longer needed.

If you are removing a Controller view, then you must include the 8 byte Player GUID value discussed in the Keyframe message, and use the message id 5.

Otherwise, you would use the message id 6 and you do not need to provide any data with the message.

Checksum Message (id 2)

The checksum is the CRC32 of its Keyframe data.

TODO: Test how bitfields are accounted for

Routed Multiple Message and RefIdAssign (id 8, id 9)

Structure of RefIdAssign (id 9)

This is a regular message containing a 2 byte ushort value. This value is the RefId that you assign to the view of the entity that you send the message to. (The official name for this concept is likely View Mapping)

Structure of Routed Multiple Message (id 8)

The structure is any number of the following:

  • [VLQ 1-2 byte] Size
  • 2 byte RefId
  • 1 byte MessageId
  • message data

There is a special case. If the 2 byte RefId is 0xFFFF, then it is followed by a regular 8 byte EntityId. This is primarily how RefIdAssign is sent.

⚠️ **GitHub.com Fallback** ⚠️