Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

The Cavrnus system primarily consists of a set of spaces, each an individual environment a user can join, participate within, create, or modify.

The Journal

The data that defines a space is called its Journal.

The Journal consists of a linear sequence of Operations. Operations are never deleted, the journal only ever moves forward. Think of the journal as a log of everything that ever occurred within the space, which when replayed, reconstructs the space in its current state.

When connected to a space, a user can submit an Operation to be included in the journal. These become part of the permanent journal. Common operations include:

...

Instantiating objects

...

Updating property values

...

Cancelling previous operations

...

At the core of the Cavrnus platform are the Operations and Transients that are written to the Journal.

Operations

Operation are the updates performed within a Cavrnus Space that are synchronized to all connected users. These operations can be triggered by multiple commands and functions within the Cavrnus Spatial Connector, for example:

  • Post X Property

  • Bind X Property Value

  • Begin Transient X Property Update

  • Finalize (X)

The above examples are function calls specific, with multiple overloaded examples for the various datatypes that Cavrnus supports. In each example, the X refers to the specific data type supported by the overloaded function.

  • Transform

  • Boolean

  • Float

  • Integer

  • String

  • etc.

  • Color Vector

Transients

A Transient, is a communication sent by a user which is not permanently stored in the journal. Transient communications involve either temporary or unsynchronized state changes. When a new user joins the space, they will not be transmitted updated with any historical transient information; they only receive and process the permanent journal. This simplifies the data history in the Journal

Common transients include:

...

Lastly, transient events are often echoed locally; they take effect immediately within the executing client’s application. Operations require guaranteed ordering, so they only ever are applied after a round trip to the Cavrnus API server. Since latency makes for bad UX, transients are applied locally immediately. The journalling system will ensure that the correct synchronized state is reached despite a potential order difference when multiple users manipulate the same fields simultaneously.

In short:

Operations are permanent changes.

Transients are temporary state transmissions and coordination systems.

An journal example:

For example, consider the following sequence of abstract operations:

  1. Create a Sphere called 'A'.

  2. Move 'A' to (10,1,0).

  3. Create a Box called 'B'.

This results in a space with two objects, A and B. If we wish to remove 'B' from the space, rather than delete anything from the journal, we instead:

4. Cancel operation #3.

Which will result in 'B' not being present, as its creation is now ignored.

Consider a user wishing to ‘Undo’ the move of 'A', operation #2. In this case, we just:

5. Cancel operation #2.

Rather than track previous location and update it, we simply mark the operation as ‘cancelled’.

Oops, now we want to redo that operation!

6. Cancel operation #5.

Now the cancellation is cancelled. Operation #2 is now live once again.

A more thorough transient example:

Consider a user ‘A' dragging a slider for ‘x' from 0, through 1, then releasing on 2. What events occur for user 'A’ and 'B’?

...

'A': Local transient: Update 'x' to 0

...

'A': Send transient: Update 'x' to 0

...

‘B' only: Recv and apply transient: Update 'x' to 0 (client 'A’ will ignore this update as it knows it has already been applied)

...

'A': Local transient: Update 'x' to 1

...

'A': Send transient: Update ‘x' to 1

...

‘B' only: Recv and apply transient: Update 'x' to 1. Client 'A’ will ignore this update as it knows it has already been applied.

...

'A': Local transient: Update 'x' to 2

...

'A': Send transient: Update ‘x' to 2

...

‘B' only: Recv and apply transient: Update 'x' to 1. Client 'A’ will ignore this update as it knows it has already been applied.

...

'A': Send operation: Update 'x' to 2, noting this operation concludes the above transient sequence

...

In the Cavrnus Spatial Connector, transients are temporary or ephemeral objects that exist in a shared scene only as long as they’re needed, without permanently altering the persistent state of that environment. Below is an overview of how they work and why they’re used:

Example Transient Sequence:

Consider a user ‘A' dragging a slider for X to update a float value starting at 0 then releasing on 2.

  1. User A: The local value of their interface changes consistently from 0 to 2 at the refresh rate of the application.

  2. The Journal: Update operations are posted to the Journal from 0 to 2. This update occurs as fast as the network can handle, posting transient updates to the Journal. These values are marked in the Journal with a “T”.

  3. User B: While the change is occuring, User B witnesses the updates live while connected to the Space copresent to User A.

  4. User A: Releases the controller, and no longer actively changes the value. At this point, the system “Finalizes” the value at 2.

  5. User B: Sees the final state of the value at 2.

  6. User C: Logs into the Space after the property value is finalized. The Transient values are not visible. Only the final state of the property is visible.

Client applications will mark the transient events completed and reorder them to match the operation’s ordering, determined by the API server. In most cases, the live state will not need to be updated, as it is already correct.

Implementing Transient Updates in Unreal Blueprints:

Once your data sync requirements have been established, properties that require transient behavior will be traced using a different workflow from direct posting, or binding. General implementation of Transients in Unreal Engine occurs in 3 stages

  • Begin Transient Property updates

  • Update with New Data

  • Finalize the Data

Workflow

The following workflow uses Unreal Engine to demonstrate implementation, however this workflow applies for Unity, Twinmotion, and NodeJS or .NET implementation as well.

...

In the Unreal Examples project, available on the Epic Marketplace (FAB.com), there are a variety of sample stands to test interaction with different datatypes. The image above shows sample stand 1.D from the “ExampleProjectWelcome” map. A physical asset model in the scene serves as an Interactive Slider to change the texture resolution of the button on the floor. Dragging the slider changes the resolution in real time.

  1. Identify the point in the interactive code (C++, C#, or Blueprints) where the user interaction for the data property begins. This could be a mouse capture, keypress, or other continuous input cycle.

  2. Find the event graph where the UI element is initial captured for editing. Then, call the corresponding Begin Transient X Property Update, where 'X' refers to the datatype of the property.

    1. In the example below, a “Begin Transient FLOAT Property Update” is bound to the Mouse Capture for the UI element.

    2. The relative location of the slider component on blueprint asset is passed into the function to be stored as a TRANSIENT property.

    3. The output from the “Begin Transient X Property Update” function produces a Live X Updater object, which is used as a reference to continuously update the Journal while the UI is captured.

      image-20250130-222833.pngImage Added

  3. A “value change” event triggers a call to update the Journal with new data. The Live Value Updater variable created in the previous step provides a reference to connect the data update with the corresponding Transient entry in the Journal.

    1. image-20250130-212321.pngImage Added

  4. Add a “Finalize” blueprint function call to the end of the even graph where the UI element is released.

    1. This deletes the reference created in the “Live Value Updater” variable, and adds a persistent entry in the Journal with the latest value.

    2. In the example below, the relative location of the slider is stored in the Journal to be synchronized with other users in the Space.

...

Output

The image below displays the live output in the Journal for the connected Space. Notice the “T” icon on the left of each line representing the transient data update, followed by a corresponding finalized entry. When the user exits the Space, those Transient entries will be purged, and the finalized entries will remain as persistent Operations in the Journal history.

  • In some cases the Transient updates will be frequent, with only one finalized update.

  • Frequency of finalization is determined by the User Interface and the frequency of finalized calls.

...