The Gatherer Component: Driving an Unreal Behavior Tree Loop
How the Gatherer component turns an AI character into an autonomous worker in Unreal Engine: a Server RPC to begin an assignment, a replicated state enum for animation, and a Blueprint-callable API that Behavior Tree tasks call to find, extract, carry, and drop.
The Gatherer component is the worker’s brain. Add UGathererComponent to an AI character
and it can take an order, find a resource, harvest it, carry the result home, and drop it,
all sequenced by a Behavior Tree. This card is about that component and how the tree drives
it. It is one card in
Resource Gathering AI in Unreal Engine; the
architecture overview shows where it sits.

What the component sets up
The component is BlueprintSpawnableComponent, so you add it in the editor like any other.
At BeginPlay it does its wiring only on the server, because the whole loop is
server-authoritative:
void UGathererComponent::BeginPlay()
{
Super::BeginPlay();
if (GetOwner()->HasAuthority())
{
CurrentGatheringState = EGathererState::Idle;
if (auto OwnerCapsule = Cast<ACharacter>(GetOwner())->GetCapsuleComponent())
{
OwnerCapsule->OnComponentBeginOverlap.AddDynamic(this, &UGathererComponent::OnOverlapBegin);
OwnerCapsule->OnComponentEndOverlap.AddDynamic(this, &UGathererComponent::OnOverlapEnd);
}
WoodPileMaker = NewObject<UResourceStackingUtility>(this);
}
}
Two things start here that matter later: it listens to its own capsule’s overlaps (that is how it knows it has reached a resource, covered in The Resource component), and it builds the helper that lays out the drop pile (covered in The drop-off pile).
Beginning an assignment
The player kicks the loop off by calling TryBeginAssignment. It is a Server, Reliable
RPC, so it always executes on the server:
UFUNCTION(BlueprintCallable, Server, Reliable, Category = "Resource Gathering")
void TryBeginAssignment(const FGameplayTag& AssignmentTag, FVector HomeLocation);
The implementation clears any work in progress, resolves the tag against the assignment
data asset, runs that assignment’s Behavior Tree, and decides where “home” is. If you pass
FVector::ZeroVector, it traces straight down from the character’s feet and uses the
ground it hits:
if (!HomeLocation.IsZero())
{
CharacterHomeLocation = HomeLocation;
}
else
{
FVector Start = GetOwner()->GetActorLocation();
FVector End = Start - FVector(0, 0, 10000);
FHitResult HitResult;
FCollisionQueryParams QueryParams;
QueryParams.AddIgnoredActor(GetOwner());
if (GetWorld()->LineTraceSingleByChannel(HitResult, Start, End, ECC_Visibility, QueryParams))
CharacterHomeLocation = HitResult.Location;
}
Because this is a server RPC, the calling client has to own the minion, which is the single most important rule in the system. The multiplayer card covers why and how.
A replicated state for animation
The component carries a small enum that says what the worker is doing right now:
UENUM(BlueprintType)
enum class EGathererState : uint8 { Idle, Extracting, Carrying };
UPROPERTY(BlueprintReadOnly, Replicated, Category = "Resource Gathering")
EGathererState CurrentGatheringState;
It is Replicated and registered in GetLifetimeReplicatedProps, so when the server moves
the loop from Idle to Extracting to Carrying, every client sees the change. Each
client’s Animation Blueprint reads it and plays the right animation (swinging an axe,
shouldering a log) with no per-frame networking of its own.
The Behavior Tree calls the API
The component does not run the loop itself; it exposes the moves and lets a tree call them.
The public, BlueprintCallable surface is short:
TryFindClosestResourceActor(AActor*& Out): the nearest resource whose tag matches and that is actually reachable.TryBeginExtractingOverlappingActor(): start harvesting the resource the worker is standing in.TrySpawnExtractedResourceAndAttachToCharacter(): spawn the carryable item and snap it to a socket.DetachExtractedResourceFromCharacter(): drop the item onto the pile.
Each Behavior Tree task is a thin wrapper around one of these. The tree is a flat sequence, so the order reads top to bottom:


Data passes through the Blackboard
The tree’s tasks share three Blackboard keys: SelfActor, ResourceLocation, and
HomeLocation. The find task writes the resource’s location, the move-to node reads it,
the set-home task writes HomeLocation from CharacterHomeLocation, and the second
move-to reads that.

The find task is a good example of the pattern, calling one component function and storing the result for the next node:

The search itself ranks every actor that has a UResourceComponent whose tag matches the
active assignment, keeps only those inside ResourceSearchRadius (2500 units by default),
and discards any it cannot path to:
if (ActorResourceComponent->ResourceTag != ActiveAssignment.ResourceTag) continue;
const float Distance = FVector::Dist(CharacterHomeLocation, Actor->GetActorLocation());
if (Distance >= ResourceSearchRadius || Distance >= ClosestDistance) continue;
if (!IsNavigablePath(GetOwner()->GetActorLocation(), Actor->GetActorLocation())) continue;
That reachability check is why a worker never fixates on a resource it can never walk to.
What to take away
- The Gatherer component is a server-authoritative actor component: it wires up on authority only, begins jobs through a Server RPC, and replicates one state enum for animation.
- It owns capabilities, not order. The Behavior Tree sequences
TryFindClosestResourceActor,TryBeginExtractingOverlappingActor, spawn-and-attach, andDetachExtractedResourceFromCharacter. - Tasks communicate through Blackboard keys, and the extract task waits on a delegate because harvesting takes real time.
Next, see how one order becomes many in Assignments and Gameplay Tags, or jump to The Resource component for the other half of the overlap-and-extract handshake. The finished system is Resource Gathering Minions on FAB.
Frequently asked questions
- How does the Gatherer component start a job?
- Through TryBeginAssignment, a Server Reliable RPC that takes a Gameplay Tag. It cancels any in-progress extraction, looks the tag up in the assignment data asset, sets the home location (the value you pass, or a line trace straight down from the character if you pass zero), runs the assignment's Behavior Tree, and optionally spawns a home marker actor.
- How does the Behavior Tree talk to the component?
- Each task calls one BlueprintCallable function on the Gatherer: BTT_Find_Resource_Location calls TryFindClosestResourceActor, BTT_Try_Extract calls TryBeginExtractingOverlappingActor, BTT_Drop_Extracted_Resource calls DetachExtractedResourceFromCharacter. The tree owns the order; the component owns the capabilities. Results pass through Blackboard keys.
- How do gather animations stay in sync over the network?
- The component holds a Replicated EGathererState (Idle, Extracting, Carrying). The server sets it as the loop progresses and it replicates to every client, so each client's Animation Blueprint reads the same state and plays the matching animation without any extra RPCs.
- Why does the Behavior Tree task for extraction wait instead of finishing instantly?
- Extraction takes real time (the resource sets its own duration), so BTT_Try_Extract starts the timer and then keeps executing until the OnGathererExtractionComplete delegate fires. Finishing the task immediately would let the worker walk off before it had actually harvested anything.