Multiplayer Gatherer AI: The Ownership and Replication Spine
Why resource-gathering AI in Unreal Engine must be spawned and owned by the player: beginning an assignment is a Server RPC, so the client has to own the minion. The full ownership chain from player to minion to resource to carried actor, plus the replicated state that keeps clients in sync.
The single rule that makes this system multiplayer-ready, and the one that trips people up, is ownership. Beginning a gather order is a Server RPC, and in Unreal a client may only call a server RPC on an actor it owns. Get the ownership chain right and the same code runs in single player and across the network. This card traces that chain end to end. It is part of Resource Gathering AI in Unreal Engine and underpins every other card.

The rule: order is a Server RPC
TryBeginAssignment is declared Server, Reliable:
UFUNCTION(BlueprintCallable, Server, Reliable, Category = "Resource Gathering")
void TryBeginAssignment(const FGameplayTag& AssignmentTag, FVector HomeLocation);
A client calling that function on a minion it does not own does nothing; Unreal drops the call. So you cannot just drag a minion into the level and command it. The player has to spawn it and become its owner first. Spawning, too, belongs on the server.

Step one: spawn, possess, own
In the player Blueprint, on begin play (server side), spawn the minion, spawn an AI controller and possess the minion with it, then set the player’s controller as the minion’s Owner:


That SetOwner is the link that makes the next line legal. With ownership in place, the
player calls TryBeginAssignment with the order tag, and the server runs the loop:

This is demonstration plumbing. In a real game you start assignments however your design calls for it (a command UI, a build order, a job queue), but the ownership requirement does not change.
Step two: the chain passes down
Ownership does not stop at the minion. The Gatherer extends the same chain to the actors it touches, so they can take part in server-authoritative play.
When the worker overlaps a resource, the Gatherer makes itself the resource’s owner:
void UGathererComponent::OnOverlapBegin(/* ... */ AActor* OtherActor /* ... */)
{
if (!GetOwner()->HasAuthority() || OverlappingResourceActor) return;
if (OtherActor->FindComponentByClass<UResourceComponent>())
{
OtherActor->SetOwner(GetOwner()); // resource inherits the ownership chain
OverlappingResourceActor = OtherActor;
}
}
and clears it again on overlap end. When it spawns the carried item, it sets that item’s owner to its own owner, the player’s controller:
SpawnedExtractedResource->SetOwner(GetOwner()->GetOwner()); // the player controller
SpawnedExtractedResource->SetReplicates(true);
SpawnedExtractedResource->SetReplicateMovement(true);
So the whole cast (minion, resource, carried item) hangs off one player controller, and every server RPC in the loop is legal.
Step three: replicated state does the rest
With the logic pinned to the server, the only thing left is to reflect results on clients, which a few replicated properties handle:
EGathererState CurrentGatheringStateon the Gatherer drives animation on every client (see the Gatherer component).ExtractionsRemainingon the Resource component isReplicatedUsingan OnRep that destroys the actor on clients when it hits zero (see the Resource component).GathererOwneron the Extracted Resource component is replicated so the carried item knows who made it.
Every method that mutates the world opens with the same guard, which is the habit that keeps the whole thing honest:
if (!GetOwner()->HasAuthority()) return;
Single player is the same path
Because the one machine in single player is the server, all of the above runs unchanged offline. There is no separate single-player code path to maintain, and no surprise when you turn networking on later. Building server-first is free when you are alone and decisive when you are not.
What to take away
TryBeginAssignmentis a Server RPC, so the calling client must own the minion. Spawn it on the server, possess it, andSetOwnerto the player controller.- The Gatherer passes ownership down the chain: it owns the resource it overlaps and makes the player controller own the carried item.
- Replicated state (gather state, extraction count, carried-item back-reference) reflects the
server’s loop on every client.
HasAuthority()guards every mutation.
Continue to The drop-off pile for where the hauls land, or revisit the architecture overview. The packaged, replicated system is Resource Gathering Minions on FAB.
Frequently asked questions
- Why must the player spawn and own the minion?
- Because TryBeginAssignment is a Server Reliable RPC. In Unreal, a client can only call a server RPC on an actor it owns. So the player spawns the minion on the server, possesses it with an AI controller, and sets the player's controller as the minion's owner. Drag-placing a minion in the level leaves it unowned and the order silently does nothing on clients.
- Does the gather loop work in single player?
- Yes, identically. The whole loop is server-authoritative and guarded by HasAuthority(), and in single player the one machine is the server, so the same code path runs. Building it server-first costs nothing offline and means multiplayer just works.
- How does the resource get extracted if the worker does not own it?
- When the worker's capsule overlaps a resource actor, the Gatherer sets itself as that actor's owner, so the resource inherits the ownership chain up to the player's controller and can take part in server-authoritative extraction. On overlap end it clears the owner again.
- What state actually replicates?
- Three things: the Gatherer's EGathererState (for animation), the Resource component's ExtractionsRemaining (so the actor destroys on every client when depleted), and the Extracted Resource component's reference to its Gatherer. Everything else is derived on the server and reflected through these.