Skip to content

Replication Overview

Summary: Project Eternal uses Unreal's standard replication with FFastArraySerializer for efficient delta replication of collections (Inventory, Map Exploration, POIs). Components replicate via SetIsReplicatedByDefault(true) with RepNotify callbacks for client-side state updates.

Table of Contents


Why This Architecture

Design Philosophy

The replication system is built around three core principles:

  1. Component Autonomy - Each component manages its own replication, reducing coupling and making systems modular
  2. Efficient Collection Sync - Large arrays (inventory, exploration) use delta serialization to minimize bandwidth
  3. Server Authority - All gameplay state changes originate on the server; clients receive updates through replication

When to Use Each Approach

Scenario Approach Why
Simple properties (health, stamina) DOREPLIFETIME Automatic sync, minimal overhead
Large arrays with frequent changes FFastArraySerializer Only changed elements replicate
Nested UObjects (items) Replicated SubObjects Maintains object identity across network
Immediate client feedback Server RPC + NetMulticast Server validates, all clients see result

Replication Flow

+------------------+          +-----------------+          +------------------+
|     SERVER       |          |   NETWORK       |          |     CLIENT       |
|   (Authority)    |          |                 |          | (Simulated Proxy)|
+------------------+          +-----------------+          +------------------+
        |                             |                            |
        |  Property Changes           |                            |
        |  (DOREPLIFETIME)            |                            |
        |---------------------------->|--------------------------->|
        |                             |                            |
        |                             |   OnRep_ Callback Fires    |
        |                             |                            |
        |  FastArray Delta            |                            |
        |  (only changed entries)     |                            |
        |---------------------------->|--------------------------->|
        |                             |   PostReplicatedAdd/Remove |
        |                             |                            |
        |  SubObject Registration     |                            |
        |  (nested UObject sync)      |                            |
        |---------------------------->|--------------------------->|
        |                             |                            |
        |                             |   UI Updates via MVVM      |
        |                             |                            |

Component-Based Replication

Components handle their own replication setup in their constructors:

UItemContainerComponent
    |
    +-- SetIsReplicatedByDefault(true)
    +-- bReplicateUsingRegisteredSubObjectList = true
    +-- InventoryList (FInventoryFastArray)

Property Replication

Standard Pattern

Properties are registered for replication in GetLifetimeReplicatedProps. The macro DOREPLIFETIME handles basic cases, while DOREPLIFETIME_CONDITION_NOTIFY provides more control.

Replication Macros

Macro Use Case Example
DOREPLIFETIME Basic property sync Simple values, references
DOREPLIFETIME_CONDITION Conditional sync Owner-only, skip owner
DOREPLIFETIME_CONDITION_NOTIFY Sync with callback GAS attributes
DOREPLIFETIME_WITH_PARAMS_FAST Push-based control FastArray containers

Condition Types

Condition Behavior
COND_None Always replicate to all connections
COND_OwnerOnly Only to owning connection (private data)
COND_SkipOwner To everyone except owner (visible to others)
COND_InitialOnly Only on initial replication

FFastArraySerializer Pattern

Why FastArray?

Standard TArray replication sends the entire array when any element changes. FastArray solves this by:

  1. Delta Serialization - Only modified entries are sent
  2. Callbacks - PostReplicatedAdd, PreReplicatedRemove, PostReplicatedChange
  3. Dirty Marking - Explicit control over what replicates

FastArray Architecture

+------------------------+
|   FFastArraySerializer |
+------------------------+
         ^
         | inherits
+------------------------+
| FInventoryFastArray    |
| FExplorationFastArray  |
| FPOIFastArray          |
+------------------------+
         |
         | contains
+------------------------+
| FFastArraySerializerItem |
|   - FInventoryEntry      |
|   - FExplorationEntry    |
|   - FMapPOIEntry         |
+------------------------+

FastArray Implementations

FastArray Owner Component Purpose
FInventoryFastArray UItemContainerComponent Item container contents
FExplorationFastArray UMapExplorationComponent Explored map cells
FPOIFastArray UWorldPOIManagerComponent Points of interest

Callback Flow

Server: InventoryList.AddEntry(Item, Index)
        InventoryList.MarkItemDirty(Entry)
                    |
                    v
            Network Delta Sent
                    |
                    v
Client: PostReplicatedAdd(AddedIndices)
            - RegisterSubObject(Item)
            - Item->SetOwningContainer(this)

Replicated SubObjects

Why SubObjects?

Items are UObjects that need to maintain identity across the network. SubObject replication ensures:

  1. Object Persistence - Same UObject instance on server and client
  2. Property Sync - Item properties replicate automatically
  3. Pointer Validity - References stay valid after replication

SubObject Lifecycle

+-------------+     +--------------+     +----------------+
|  Add Item   | --> | Register     | --> | Replicate      |
|  to Array   |     | SubObject    |     | to Clients     |
+-------------+     +--------------+     +----------------+
                          |
                          v
              AddReplicatedSubObject(Item)

+-------------+     +--------------+     +----------------+
| Remove Item | --> | Unregister   | --> | Remove from    |
| from Array  |     | SubObject    |     | Clients        |
+-------------+     +--------------+     +----------------+
                          |
                          v
             RemoveReplicatedSubObject(Item)

Registration Requirements

Condition Method
Check if ready IsUsingRegisteredSubObjectList()
Check replication state IsReadyForReplication()
Validate object IsValid(SubObj)

RepNotify Patterns

Pattern Types

Pattern Use Case Implementation
Simple Synchronization point Empty callback body
With Old Value Delta comparison GAS attributes
FastArray Collection sync Rebuild derived state
Interpolated Smooth corrections Movement, transforms

RepNotify Flow

Server: Property = NewValue
            |
            v
       Replication
            |
            v
Client: OnRep_Property() fires
            |
            +-- Update local state
            +-- Broadcast delegates
            +-- Trigger UI refresh

Common RepNotify Uses

Component Property RepNotify Purpose
UItemContainerComponent InventoryList Rebuild grid, broadcast change
UEternalAttributeSet Health GAS attribute prediction
AEternalCharacter ReplicatedServerPosition Movement interpolation
UCombatComponent AvailableCombatMontages Sync montage data

RPC Types

Server RPC (Client to Server)

Used for gameplay-critical operations where the server must validate and execute.

Client Request          Server Validation         Result
      |                       |                     |
      v                       v                     v
Server_SwapItems() --> Validate Items --> Execute + Replicate
                   --> Validate Space
                   --> Validate Owner

NetMulticast (Server to All Clients)

Used when all clients need immediate notification of an event.

Reliability Use Case Example
Reliable Critical state changes Death, equipment changes
Unreliable Visual effects Hit particles, audio

RPC Decision Matrix

Need RPC Type Reliability
Client wants action Server RPC Reliable
All see result immediately NetMulticast Reliable
Visual-only feedback NetMulticast Unreliable
Owner-only feedback Client RPC Reliable

Source References

Property Replication

  • UItemContainerComponent::GetLifetimeReplicatedProps - Source/ProjectEternal/Private/Inventory/Components/ItemContainerComponent.cpp:45
  • UEquipmentComponent::GetLifetimeReplicatedProps - Source/ProjectEternal/Private/EquipmentManagement/Components/EquipmentComponent.cpp:32
  • UEternalAttributeSet::GetLifetimeReplicatedProps - Source/ProjectEternal/Private/AbilitySystem/EternalAttributeSet.cpp:15

FastArray Implementations

  • FInventoryFastArray - Source/ProjectEternal/Public/Inventory/FastArray/FastArray.h:12
  • FExplorationFastArray - Source/ProjectEternal/Public/Automap/AutomapTypes.h:45
  • FPOIFastArray - Source/ProjectEternal/Public/Automap/AutomapTypes.h:78

SubObject Registration

  • UItemContainerComponent::AddRepSubObj - Source/ProjectEternal/Private/Inventory/Components/ItemContainerComponent.cpp:156
  • FInventoryFastArray::PostReplicatedAdd - Source/ProjectEternal/Private/Inventory/FastArray/FastArray.cpp:28

RepNotify Callbacks

  • UItemContainerComponent::OnRep_InventoryList - Source/ProjectEternal/Private/Inventory/Components/ItemContainerComponent.cpp:89
  • AEternalCharacter::OnRep_ReplicatedServerPosition - Source/ProjectEternal/Private/Character/EternalCharacter.cpp:234


Recent Changes

Date Change Reason
- Initial documentation Document existing replication architecture

Future Considerations

Enhancement Benefit Complexity
Replication Relevancy Reduce bandwidth for distant actors Medium
Conditional Replication Owner-only private data Low
Replication Graph O(1) actor relevancy checks High
Property Compression Quantized floats for bandwidth Medium