Iris Networking UE5.7+ with FastArray Example

UE 5.7 (Source/Dist) Configuration

The following steps are needed to use Iris:

In unreal editor enable Iris Networking (Beta) Plugin ( Restart)

Update UProject

Check that the plugin has been added to uproject file

"Plugins": [
...
{
"Name": "Iris",
"Enabled": true
}
}

Build.cs Modules

For each module using replication in the project add the following to the build.cs file.

public VirtuosoWorlds(ReadOnlyTargetRules Target) : base(Target)
{
SetupIrisSupport(Target);
...
}

DefaultEngine.ini

[SystemSettings]
net.SubObjects.DefaultUseSubObjectReplicationList=1
net.Iris.UseIrisReplication=1
[Core.Log]
LogIris=VeryVerbose
LogIrisReplication=VeryVerbose

Confirmation

The following shows a successful startup of Iris in the Server Logs

[2025.12.12-09.12.34:996][ 0]LogPluginManager: Mounting Engine plugin Iris
...
[2025.12.12-09.12.34:997][ 0]LogConfig: Set CVar [[net.Iris.UseIrisReplication:1]]
...
[2025.12.12-09.12.48:764][904]LogCsvProfiler: Display: Metadata set : iris="1"

Fast Arrays

In traditional Unreal replication:

  • TArray replication sends the entire array every time something changes.

  • Large arrays (inventory items, projectiles, etc.) are inefficient and generate a lot of network traffic.

Iris Fast Arrays solve this:

  • Server authoritative by default ( Replicate from server to client )

  • They replicate changes incrementally instead of the whole array.

  • They track added, removed, and modified elements automatically.

Why MarkItemDirty() Exists

  • FFastArraySerializer tracks which items changed since the last network update.

  • Without marking an item dirty, Iris has no way of knowing it was modified, so it won’t replicate that change.

  • This is how Iris sends only incremental changes, rather than the whole array.

Purpose of operator==

  • Iris/FFastArraySerializer uses operator== internally to check if an item has changed since the last replication.

  • If the item appears “equal” to the old version, it won’t be replicated.

  • If the item is different, Iris marks it for replication.

Without operator==, Iris has no reliable way to detect changes, and you may see updates not being sent to clients.

Inspector Properties Support

To ensure that the fast array shows up in the inspector details we do the following

# InventoryItem.h
UPROPERTY(EditAnywhere, meta=(ShowOnlyInnerProperties))
TArray<FInventoryItem> Items;
...
# MeshActor.h
UPROPERTY(Replicated, EditAnywhere)
FInventoryArray Inventory;

# InventoryItem.h
#pragma once
#include "Net/Serialization/FastArraySerializer.h"
#include "InventoryItem.generated.h"
USTRUCT()
struct FInventoryItem : public FFastArraySerializerItem
{
GENERATED_BODY()
UPROPERTY()
int32 ItemID;
UPROPERTY()
int32 Quantity;
// Checks if an item has changed since last replication
bool operator==(const FInventoryItem& Other) const
{
return ItemID == Other.ItemID && Quantity == Other.Quantity;
}
};
USTRUCT()
struct FInventoryArray : public FFastArraySerializer
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, meta=(ShowOnlyInnerProperties))
TArray<FInventoryItem> Items;
bool NetDeltaSerialize(FNetDeltaSerializeInfo& DeltaParms)
{
return FastArrayDeltaSerialize(
Items, DeltaParms, *this
);
}
// Helper functions to safely add items
void AddItem(FInventoryItem NewItem)
{
Items.Add(NewItem);
MarkItemDirty(Items.Last());
}
void UpdateItem(int32 Index, int32 NewQuantity)
{
if (Items.IsValidIndex(Index))
{
Items[Index].Quantity = NewQuantity;
MarkItemDirty(Items[Index]);
}
}
};
# MeshActor.h
#pragma once
#include "CoreMinimal.h"
#include "InventoryItem.h"
#include "GameFramework/Actor.h"
#include "Net/UnrealNetwork.h"
#include "MeshActor.generated.h"
UCLASS()
class AMeshActor : public AActor
{
GENERATED_BODY()
public:
UPROPERTY(Replicated)
int32 ItemID;
UPROPERTY(Replicated)
float Durability;
UPROPERTY(Replicated, EditAnywhere)
FInventoryArray Inventory;
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AMeshActor, ItemID);
DOREPLIFETIME(AMeshActor, Durability);
DOREPLIFETIME(AMeshActor, Inventory);
}
};

How clients can “update” the server safely

Use Server RPCs (UFUNCTION(Server, Reliable)):

UFUNCTION(Server, Reliable)
void ServerAddItem(int32 ItemID, int32 Quantity);

Implementation:

void AVWPlayerCharacter::ServerAddItem_Implementation(int32 ItemID, int32 Quantity)
{
FInventoryItem NewItem;
NewItem.ItemID = ItemID;
NewItem.Quantity = Quantity;
Inventory.AddItem(NewItem); // MarkItemDirty called internally
}

  • Client calls ServerAddItem(ItemID, Quantity)

  • Server adds the item and marks it dirty

  • Iris replicates the change to all clients, including the one that requested it

:white_check_mark: This is the correct server-authoritative flow.