-
Notifications
You must be signed in to change notification settings - Fork 5
Views, Updates and Keyframes
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.
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.
The view state can be updated directly through the ShadowFields
in two ways.
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 theShadowFieldIndex
The 8 byte player/account GUID is only included for Controller
type views, which use message id 4
.
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
.)
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.
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.
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.
The checksum is the CRC32 of its Keyframe data.
TODO: Test how bitfields are accounted for
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)
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.