Sync Items
Sync Items are synchronized Actor Components (URedwoodSyncComponent
) that can be attached to Actors to synchronize transform, state, and miscellaneous data. The synchronization is server-to-server via Redis; clients do not receive direct sync state from Redis but rather via UE replication of their connected server.
Not every Actor should be a Sync Item. This implementation isn't full, robust server meshing, but rather a tool to use as needed.
Some examples of Sync Items are:
- Various game state data (i.e. time of day, overall scores, etc)
- Battle Royale Circle/"Play Zone"
- Supply airdrop
- Limited-supply resource (to prevent cross-shard farming)
- You could theoretically sync player characters and vehicles (so you can see them across zone boundaries), but note this isn't tested and you might need to do a bit of work to support this. Need extra support implementing this? Reach out for a custom license.
Setup
Backend
You need to configure your Game Profile to specify how a zone should subscribe to sync items from other zones; synchronization is only automatically enabled for these situations:
- Synchronizing between shards in the same zone
- World Data, which is just a Persistent Sync Item with the special
proxy
ID
Unreal
We recommend checking out the B_Fence
Blueprint class in the RPG Template as an example of how this is set up.
-
Create a new Data Asset that inherits from
URedwoodSyncItemAsset
(i.e.DA_CommunityChest
). -
Create an Actor that will represent what's spawned in the world for this Sync Item (i.e.
B_CommunityChest
). -
Create a struct that will represent the structure of the data for the Sync Item (i.e.
S_CommunityChestData
). -
In the data asset you created (i.e.
DA_CommunityChest
), set theRedwoodTypeId
string to some unique identifier for this type of persistent item (i.e.community-chest
). Set theActorClass
to the Actor you created (i.e.B_CommunityChest
).noteThe word
proxy
is a reservedRedwoodTypeId
meant to be used to define the asset for World Data. -
In your Actor (i.e.
B_CommunityChest
), attach an instance of the Actor ComponentURedwoodSyncComponent
; it can have any name. -
For the Actor Component you just created, change the "Default" values in the Details panel accordingly:
- We recommend keeping
Store Data in Actor
enabled; if you disable this, you'll need to create a child class ofURedwoodSyncComponent
to add the data variable. - Leave the
Redwood Id
empty here in the class; this will be a unique identifier used for every instance of the Sync Item type. - By default you must manually call
MarkMovementDirty()
on the sync component to synchronize the transform, but you can change the value ofMovement Sync Interval Seconds
to a non-negative value to let Redwood automatically synchronize movement on some interval. Setting this to0
will sync
- We recommend keeping
-
In your Actor (i.e.
B_CommunityChest
), add a variable with the nameData
(unless you changed the name in the Data Asset) with the type being the struct you created (i.e.S_CommunityChestData
). -
NOTE: If you want the data to replicate, you must enable replication manually for your Actor and the
Data
variable. -
In your struct (i.e.
S_CommunityChestData
), you need to add a variable namedSchemaVersion
of typeInteger
. -
Add any other serializable variables to your struct that you'd like synchronized.
Sync Frequency
Redwood checks all Sync Items efficiently on tick to see if their state, movement, or data constructs are dirty. You can mark them dirty with the corresponding URedwoodSyncComponent::Mark<...>Dirty()
functions. The only exception to this is if you set Movement Sync Interval Seconds
to a non-negative value in the Sync Component as described above.
All dirty sync information is batched together in a single API call to the sidecar, which then relays that directly to Redis (which other sidecars subscribe to).
Subscribed sidecars will individually receive messages from the sidecar for each item change ASAP, but note there will be some latency. There currently is no clock synchronization/rewind behavior built into the system.
Persisted Sync Items are persisted separately in a separate batch API call at the DatabasePersistenceInterval
interval.
Traveling Between Zones
Currently, there's no mechanism for moving a Sync Item to a different zone.
Persistent Items
Sync Items can optionally be persisted to the database. Persisted Sync Items (sometimes called Persistent Items) are loaded from the database when a shard in the corresponding zone is started.
Not every Sync Item should be persisted; if the state doesn't need to be persisted (aka saved to the database and state restored when a shard boots up for a zone), you shouldn't use this option
Some examples of Persistent Items are:
- Player bases/UGC that is persisted in the open world area
- A persistent ferry between areas on the map that players can upgrade
- Community storage chests
- Anything that persists in the world, but requires a more modular approach than using world data
Enabling Persistence
In the URedwoodSyncComponent
that you attach to the actor, check the Persist Changes
box in the Details panel (bPersistChanges
in C++).
Design-time Persistent Items
All Sync Items can be placed in the Level Editor at design-time, but if you want that item to persist, you need to change some variables on the instance you place:
- Place your Actor (i.e.
B_CommunityChest
) into the level - Click on the Actor instance in the Outliner panel or in the viewport
- In the Details panel click on the
URedwoodSyncComponent
Actor Component instance (by default just calledRedwoodSync
) - Change the value of
Redwood Id
to something unique for this instance (i.e.community-chest-village-blacksmith
) - Change the value of
Zone Name
to the name of the zone this item is located in (i.e.village
); Redwood can't automatically determine this.
Data Persistence
Read all about data how data persistence (loading, saving, migrations when your structure changes) in player data docs. Everything there is common (including the same DatabasePersistenceInterval
variable being used and how migration functions work). You will call the MarkDataDirty()
function on the URedwoodPersistenceComponent
Actor Component attached to your Actor class when you need to save to the database.