Multiplayer Support
Documentation Unreal Engine AI Multiplayer Replication
Replication architecture, what runs where, and how to use the plugin in listen server and dedicated server games.
The plugin works in both listen server and dedicated server configurations. AI decisions run on the server, and relevant state replicates to clients automatically.
Overview
AI in Unreal Engine is inherently server-authoritative. AI controllers only exist on the server, and all decision-making happens there. The challenge for multiplayer is making sure clients have enough information to display what the AI is doing (animations, VFX, UI indicators) without duplicating the logic.
SoulslikeCombat handles this by replicating output state, not logic. The server runs the full decision pipeline, and lightweight replicated components on the pawn broadcast the results to clients.
Architecture: What Runs Where
Server Only
These components live on the AI controller and only exist on the server:
| Component | Purpose |
|---|---|
SECCombatControllerComponent | AIConfig resolution, combat role handling, sync |
ActionEvaluationComponent | Scores and selects actions |
MovementEvaluatorComponent | Tactical positioning |
ThreatDetectionComponent | Tracks player camera attention |
AICombatRoleSubsystem | Assigns roles across all AI |
This is the brain. Clients never run action evaluation or movement scoring.
SECCombatControllerComponent is the central integration point that connects all these systems together.Replicated to Clients
These components live on the pawn and replicate automatically:
| Component | What Replicates |
|---|---|
SECActionSetComponent | Current action ID, execution state, active ActionSet reference, cooldown state |
SECReactionSetComponent | Current reaction ID, execution state, active ReactionSet reference, cooldown state |
SECCombatRoleComponent | Current combat role tag |
BasicHealthComponent | Current health value |
SECWeaponBase | Actor replication (attachment, visibility) |
SECMeleeTraceComponent | Server-authoritative only (traces run on server, damage applied on server) |
Client-Side Available
Clients can read all replicated state and bind to delegates. This is enough for:
- Health bars and damage numbers
- Action name indicators ("Charging Heavy Attack...")
- Role-based outline colors or overhead icons
- Animation (handled by standard GAS montage replication)
Component Breakdown
Gameplay Abilities
All abilities derived from
GameplayAbilityBase are configured with:NetExecutionPolicy = EGameplayAbilityNetExecutionPolicy::ServerInitiated;
ReplicationPolicy = EGameplayAbilityReplicationPolicy::ReplicateYes;This means:
- Abilities are activated on the server
- GAS replicates the ability state and montage playback to clients
- Clients see the correct animations without any extra work
Melee Trace (SECMeleeTraceComponent)
Melee traces run only on the server. The component's
TickComponent checks for authority before processing traces. Damage is applied server-side via ApplyDamage.Clients see the attack animation (via GAS montage replication) but don't run traces. Hit reactions, damage numbers, and VFX should be driven by the replicated health change or gameplay cues.
Weapons (SECWeaponBase)
Weapons replicate as actors (
bReplicates = true). Attachment to the character skeleton happens on the server and replicates to clients, so weapons are visible on all machines.Health (BasicHealthComponent)
Health is replicated with
OnRep. The OnHealthDecreased delegate fires on both server and clients because it is triggered inside OnRep_Health, not inside DecreaseHealth. This means client-side UI can bind directly:HealthComponent->OnHealthDecreased.AddDynamic(this, &UMyWidget::OnDamaged);
// This fires on both server and clients when health drops.Action State (SECActionSetComponent)
The
SECCombatControllerComponent pushes execution events to the pawn's SECActionSetComponent, which replicates them:// Server-side (automatic, handled by controller):
ActionSetComponent->NotifyActionStarted("HeavyAttack");
ActionSetComponent->NotifyActionCompleted("HeavyAttack", true);
// Client-side (read in widgets, HUD, etc.):
ActionSetComponent->OnActionExecutionStarted.AddDynamic(...);
ActionSetComponent->OnActionExecutionCompleted.AddDynamic(...);
ActionSetComponent->OnActionSetChanged.AddDynamic(...);
// Cooldown tracking (for ability cooldown UI):
ActionSetComponent->OnActionCooldownStarted.AddDynamic(...); // (ActionId, Duration)
ActionSetComponent->OnActionCooldownExpired.AddDynamic(...); // (ActionId)
float Remaining = ActionSetComponent->GetRemainingCooldown("HeavyAttack");
bool bOnCD = ActionSetComponent->IsActionOnCooldown("HeavyAttack");Reaction State (SECReactionSetComponent)
The same bridge pattern applies to reactions. The
SECCombatControllerComponent pushes reaction events to the pawn's SECReactionSetComponent:// Client-side (read in widgets, HUD, etc.):
ReactionSetComponent->OnReactionExecutionStarted.AddDynamic(...);
ReactionSetComponent->OnReactionExecutionCompleted.AddDynamic(...);
ReactionSetComponent->OnReactionSetChanged.AddDynamic(...);
// Cooldown tracking:
ReactionSetComponent->OnReactionCooldownStarted.AddDynamic(...);
ReactionSetComponent->OnReactionCooldownExpired.AddDynamic(...);
float Remaining = ReactionSetComponent->GetRemainingCooldown("BlockReaction");Combat Role (SECCombatRoleComponent)
The role subsystem assigns roles to controllers (server-only). When a role changes, the
SECCombatControllerComponent writes it to the pawn's SECCombatRoleComponent, which replicates the tag:// Client-side:
FGameplayTag Role = CombatRoleComponent->GetCombatRole();
CombatRoleComponent->OnCombatRoleChanged.AddDynamic(...);See Combat Roles - Client-Side Role Visibility for details.
Movement
MovementEvaluatorComponent runs on the server and feeds input to Unreal's CharacterMovementComponent (CMC). The CMC handles replication natively. Position, velocity, and rotation all sync to clients through Unreal's built-in character movement replication. No additional work needed.Setup
If you're already using the plugin in single-player, there's almost nothing to change for multiplayer.
What You Need
- Register combat targets - In multiplayer, register each player pawn as a combat target. The Targeting System handles multi-target distribution automatically.
// In GameMode or Player setup:
UAICombatRoleSubsystem* Subsystem = GetWorld()->GetSubsystem<UAICombatRoleSubsystem>();
Subsystem->RegisterCombatTarget(PlayerPawn, /*bAutoAssignUnassigned=*/ true);-
Drive client UI from replicated state - Use the delegates on
SECActionSetComponent,SECCombatRoleComponent, andBasicHealthComponentfor client-side feedback. -
Damage handling - If you're using custom damage handling (not Unreal's built-in
ApplyDamage), make sure your system is server-authoritative. The melee trace only runs on the server, so all hit events originate there.
What You Don't Need To Do
- No need to configure replication on components - it's set up by default
- No need to manually sync animations - GAS handles montage replication
- No need to replicate movement - CMC does this natively
- No need to run AI logic on clients - everything is server-authoritative
Common Multiplayer Patterns
Co-op with Target Distribution
// Register both players
Subsystem->RegisterCombatTarget(Player1);
Subsystem->RegisterCombatTarget(Player2);
// AI distributes across players using TargetSelectors
// See Targeting System docs for selector optionsClient-Side Enemy HUD
// In your enemy health bar widget:
void UEnemyHUD::Setup(APawn* EnemyPawn)
{
auto* Health = EnemyPawn->FindComponentByClass<UBasicHealthComponent>();
Health->OnHealthChanged.AddDynamic(this, &UEnemyHUD::UpdateHealthBar);
Health->OnHealthDecreased.AddDynamic(this, &UEnemyHUD::FlashDamage);
auto* ActionSet = EnemyPawn->FindComponentByClass<USECActionSetComponent>();
ActionSet->OnActionExecutionStarted.AddDynamic(this, &UEnemyHUD::ShowActionIndicator);
auto* Role = EnemyPawn->FindComponentByClass<USECCombatRoleComponent>();
Role->OnCombatRoleChanged.AddDynamic(this, &UEnemyHUD::UpdateRoleIcon);
}Dedicated Server
No special configuration needed. The plugin is fully compatible with dedicated servers. AI controllers exist on the dedicated server, and all replicated state flows to connected clients.
Integration Points
| System | Multiplayer Relevance |
|---|---|
| Action System | Actions replicate via SECActionSetComponent |
| Combat Roles | Roles replicate via SECCombatRoleComponent |
| Melee Trace | Server-authoritative only, no client traces |
| Targeting System | Multi-target handles co-op player distribution |
| Movement System | Relies on CMC native replication |