Skip to content

Minion Owner Replication and Local Dummy KB

Scope

This document explains the Minions plugin's networking arrangement when a player is granted or spawns a minion:

  • the owning client creates a local dummy minion for responsive local simulation;
  • the server creates the authoritative minion pawn;
  • non-owning clients receive a replicated simulated proxy of the authoritative pawn; and
  • the owning client must never receive that simulated proxy, because it already has the local dummy.

It also documents a misleading failure mode in which the owning client briefly receives both actors, the resulting navigation obstruction, and why IsNetRelevantFor only became effective after construction-time replication was disabled on BP_MinionBase.

Intended network topology

World/connection Expected minion actor Expected local role
Dedicated server Authoritative minion ROLE_Authority
Owning client Locally spawned dummy only ROLE_Authority
Other clients Server-replicated minion proxy ROLE_SimulatedProxy

The locally spawned dummy is intentionally authoritative inside its client process. That does not mean it is server authority or that it can replicate back to the server.

Symptom

The owning client sometimes had both of the following actors for approximately five seconds:

  1. its intended local dummy; and
  2. an unintended simulated proxy of the server minion.

All minions continually navigate toward assigned formation positions. The unintended proxy occupied the target area and obstructed the local dummy's crowd/navigation movement.

Observed variants included:

  • initially, the local dummy was held roughly one full minion-capsule width away from its assigned point;
  • after an intermediate relevancy change, it could approach more closely but was still obstructed by a smaller apparent collision footprint; and
  • after roughly the same delay, it could finally reach the exact assigned point, consistent with the unintended proxy/channel being removed.

The delay made the problem look like slow actor destruction. It was more consistent with an already-created actor channel remaining recently relevant until Unreal's relevancy timeout/cleanup path removed the client proxy.

Why the first relevancy-only change was insufficient

The original minion Blueprint started with Replicates enabled. This allowed the authoritative pawn to enter networking during its initial spawn path, before the owner-exclusion metadata was guaranteed to be useful for the first actor-channel decision.

Later calls to ATankMinionBase::IsNetRelevantFor correctly returned false for the owning connection, but that did not immediately undo an actor channel that had already been created. Consequently, the unintended simulated proxy remained on the owning client for the observed timeout window.

This does not mean IsNetRelevantFor is generally ineffective. It means a negative relevancy result can be too late to prevent an actor that already entered a connection's replication lifecycle.

Working configuration

Replicates is unchecked in BP_MinionBase. The concrete minion children do not override that property and also show the inherited unchecked value.

This gives the pawn a non-replicating initial Blueprint CDO state during construction. The server pawn is subsequently added to networking by Unreal's AI-possession path. At that later point, TankCharacter and the owning-player relationship are available, so the first normal per-connection relevancy evaluation produces the intended split:

  • owning connection: not relevant;
  • every other relevant connection: relevant.

Native constructor versus Blueprint defaults

ATankCharacterBase::ATankCharacterBase sets:

bReplicates = true;

That native-constructor assignment is not necessarily the final value on a Blueprint instance. Unreal applies the Blueprint generated-class defaults afterward. Therefore, an unchecked Replicates value in BP_MinionBase overrides the native constructor default for the spawned Blueprint instance.

Important distinctions:

  • the native constructor establishes the native class default;
  • the Blueprint CDO can override that default;
  • child Blueprints can override it again, but the current concrete minion children do not; and
  • AbilitySystemComponent->SetIsReplicated(true) only enables replication for that component when its owner participates in networking; it does not by itself make the owning actor replicate.

Why the pawn still replicates to other clients

For an AI controller, APawn::PossessedBy executes this branch in UE 5.6:

CopyRemoteRoleFrom(GetDefault<APawn>());

AActor::CopyRemoteRoleFrom then:

  1. copies the native APawn default remote role;
  2. marks RemoteRole dirty; and
  3. when that role is not ROLE_None, calls GetWorld()->AddNetworkActor(this).

The key nuance is that this copies from the native APawn default, not from the BP_MinionBase CDO. AI possession therefore adds the authoritative minion to the network actor list even though its Blueprint began with Replicates unchecked.

This behavior is what allows the unchecked Blueprint default to act as a construction-time gate without permanently suppressing the server proxy on non-owning clients.

Relevant engine locations for UE 5.6:

  • Engine/Source/Runtime/Engine/Private/Pawn.cpp, APawn::PossessedBy
  • Engine/Source/Runtime/Engine/Private/Actor.cpp, AActor::CopyRemoteRoleFrom

Actual lifecycle and timing

For the deferred-spawn and automatic-AI-possession path, the important order is:

SpawnActorDeferred
-> apply ExposeOnSpawn values, including TankCharacter
-> FinishSpawning
-> Blueprint Construction Script
-> PostInitializeComponents
-> SpawnDefaultController
-> AIController::Possess
-> APawn::PossessedBy
-> CopyRemoteRoleFrom
-> AddNetworkActor
-> BeginPlay
-> subsequent network replication update
-> IsNetRelevantFor for each connection

APawn::PossessedBy is normally called before BeginPlay in this automatic possession path, not after it.

AddNetworkActor does not synchronously consult IsNetRelevantFor. It registers the actor with the net driver. A subsequent replication update evaluates the actor independently for each connection and invokes IsNetRelevantFor as part of that work.

The safe timing therefore does not depend on BeginPlay. It depends on the following facts:

  • TankCharacter is an ExposeOnSpawn value and is assigned before FinishSpawning;
  • the pawn is initially excluded from networking by its Blueprint default;
  • AI possession adds it to networking only after construction has advanced far enough; and
  • the first normal connection-specific relevancy evaluation sees valid ownership metadata.

Owner identification nuance

After AI possession, the minion's direct actor owner is the TankCrowdAIController, not the player's ATankPlayerController. Therefore, checking only GetOwner(), GetNetOwner(), or IsOwnedBy(RealViewer) on the minion is insufficient for identifying the player who owns the local dummy.

The stable relationship is the exposed TankCharacter reference:

  • TankCharacter->GetController() identifies the owning player controller;
  • TankCharacter->IsOwnedBy(RealViewer) covers the owning chain; and
  • comparisons against the owning tank/view target provide additional protection during connection-specific relevancy checks.

An unresolved TankCharacter should fail closed for this actor: return not relevant until ownership can be determined. Accidentally suppressing a minion for a later replication update is safer than briefly creating a duplicate on its owning client.

Relevancy decision model

The effective decision should be understood as:

if viewer is the minion's owning player through TankCharacter:
    not relevant
else:
    defer to the superclass relevancy result

Actor ownership can be checked as an early additional guard, but it cannot replace the TankCharacter check because AI possession changes the minion's direct owner.

Log evidence

Diagnostic [MinionRelevancy] logging established the following:

  • the authoritative server minion had ROLE_Authority;
  • the local dummy on its owning client also had ROLE_Authority;
  • the unintended/remote server proxy had ROLE_SimulatedProxy;
  • for the owning player's controller, relevancy returned 0 with Reason=TankOwnership;
  • for the other player's controller, relevancy returned 1 with Reason=Super;
  • after AI possession, ActorOwner was a TankCrowdAIController; and
  • TankCharacter and TankController correctly identified the owning player.

The successful two-client test after unchecking BP_MinionBase.Replicates still showed normal relevancy evaluations and a simulated proxy on the non-owning client. This is expected because AI possession calls AddNetworkActor as described above.

Common incorrect conclusions

"The native constructor sets bReplicates, so the Blueprint checkbox cannot matter"

Incorrect. The Blueprint CDO overrides the native default on Blueprint instances. The unchecked value prevents initial construction-time network participation.

"The Ability System Component is replicated, so it makes the minion actor replicate"

Incorrect. Component replication does not independently create replication for an otherwise non-networked owning actor.

"A false IsNetRelevantFor result immediately destroys an existing proxy"

Incorrect. Relevancy controls connection-specific replication, but an already-open/recently-relevant actor channel can persist until the networking cleanup timeout.

"PossessedBy runs after BeginPlay"

Not for the normal automatic AI-possession path. It occurs from PostInitializeComponents, before BeginPlay.

"AddNetworkActor immediately calls IsNetRelevantFor"

Incorrect. It registers the actor. Relevancy is evaluated later during connection replication updates.

"Unchecking Replicates means no remote client can ever receive the pawn"

Incorrect for this AI pawn path. APawn::PossessedBy restores a remote role from the native APawn default and CopyRemoteRoleFrom adds the pawn to the network actor list.

Debugging checklist

When this symptom returns, verify all of the following:

  1. BP_MinionBase has Replicates unchecked.
  2. Concrete minion children have not introduced a Replicates override.
  3. No Blueprint or C++ path calls SetReplicates(true) before the exposed owner data is assigned.
  4. The server minion is AI-possessed and reaches APawn::PossessedBy.
  5. TankCharacter is assigned through the deferred ExposeOnSpawn path.
  6. The server's first relevancy results are false for the owning controller and true for a non-owning controller.
  7. The owning client has only its local ROLE_Authority dummy.
  8. A non-owning client has exactly one ROLE_SimulatedProxy.
  9. Navigation collision is tested at the exact assigned formation point for longer than the prior five-second failure window.

Useful temporary fields to include in relevancy diagnostics are:

  • minion name and pointer;
  • GetNetMode();
  • local and remote role;
  • GetIsReplicated();
  • RealViewer and ViewTarget;
  • actor owner and net owner;
  • TankCharacter and its controller;
  • ownership-chain comparison results; and
  • the final relevancy result and reason.

Maintenance guidance

  • Keep the unchecked BP_MinionBase.Replicates default documented as intentional. It is a spawn-order gate, not an instruction that minions must never replicate.
  • Preserve the TankCharacter owner-exclusion logic in IsNetRelevantFor.
  • Avoid enabling replication earlier in Construction Script or immediately after SpawnActorDeferred unless ownership is already guaranteed and the initial channel behavior has been retested.
  • Treat engine possession behavior as version-sensitive. Recheck APawn::PossessedBy and AActor::CopyRemoteRoleFrom when upgrading Unreal Engine.
  • Remove or reduce per-update relevancy warning logs after validation because they are extremely noisy.
  • Validate with at least a dedicated server and two clients: one owner and one non-owner.

Summary

The successful behavior relies on two complementary mechanisms:

  1. Construction-time gating: BP_MinionBase begins with Replicates unchecked, preventing a premature actor channel for the owning client.
  2. Connection-specific filtering: AI possession later adds the pawn to networking, after which IsNetRelevantFor excludes the owning connection while allowing other clients to receive the authoritative simulated proxy.

Neither mechanism is sufficient by itself. Early replication can outrun owner resolution, while permanently disabling network participation would prevent other clients from seeing the minion.