RPC (client to server) on owning actor not working

I am trying to let a dedicated server print a log message through a RPC on an actor which gets called by a client. The idea is this:

  1. PlayerController sends a RPC to the server to spawn a soldier (this works).
  2. Server checks if soldier is allowed to spawn → spawns it with as owner the PlayerController that made the RPC.
  3. Soldier gets replicated back to the client.
  4. Client “selects” the soldier through blueprint.
  5. Clients PlayerController calls a RPC function on the selected soldier.
  6. Server displays a log message (like the “received soldier spawn” message, see screenshot).

The last log message won’t get displayed and Unreal doesn’t give any warnings/errors (which it does do when I don’t set the ownership in step 2). Now I found out that even after assigning ownership to the PlayerController the role of the actor on the client isn’t set to ROLE_AutonomousProxy (which according to the internet is needed to do these RPCs). How do I set the ownership properly to be able to do these RPCs?

PlayerController.h:

UFUNCTION(Server, WithValidation, Reliable, BlueprintCallable, Category = "BRPlayerController|Raiding", meta = (DisplayName = "Spawn soldiers on Server"))
			void ServerSpawnSoldiers(const TArray<ESoldierTypes>& aSoliderArray, FVector aPosition, APlayerController* aOwner);
		bool ServerSpawnSoldiers_Validate(const TArray<ESoldierTypes>& aSoliderArray, FVector aPosition, APlayerController* aOwner);
		void ServerSpawnSoldiers_Implementation(const TArray<ESoldierTypes>& aSoliderArray, FVector aPosition, APlayerController* aOwner);

PlayerController.cpp:

    void ABasePlayerController::ServerSpawnSoldiers_Implementation(const TArray<ESoldierTypes>& aSoldierArray, FVector aPosition, APlayerController* aOwner)
    {
    	UE_LOG(LogTemp, Warning, TEXT("received soldier spawn"));
    	FActorSpawnParameters tParams;
    	tParams.Owner = aOwner;
    	ABaseSoldier* tSoldier = (ABaseSoldier*)GetWorld()->SpawnActor(mMeleeSoldier, &aPosition, &FRotator::ZeroRotator, tParams); //Spawn a melee soldier for testing purposes
    	//tSoldier->SetAutonomousProxy(true); <-- tried, doesnt change anything
    	//tSoldier->SetReplicates(true); <-- tried, doesnt change anything
    }

void ABasePlayerController::TestOwnership()
{
	if (selectedSoldier->IsOwnedBy(this))
	{
		UE_LOG(LogTemp, Warning, TEXT("selected Soldier is owned by caller"));
	}
	if (selectedSoldier->Role >= ROLE_AutonomousProxy)
	{
		UE_LOG(LogTemp, Warning, TEXT("selected soldier can call SERVER functions"));
	}
}

Soldier.h:

UFUNCTION(Server, WithValidation, Reliable, BlueprintCallable, Category = "Temp functions")
		void ServerCallDebugThingy();
		void ServerCallDebugThingy_Implementation();
		bool ServerCallDebugThingy_Validate();

Soldier.cpp:

void ABaseSoldier::ServerCallDebugThingy_Implementation()
{
	UE_LOG(LogTemp, Warning, TEXT("soldier log message"));
}

Blueprint of the PlayerController:

The spawning of the soldier:

The selecting of the soldier:

The calling of the RPC on the soldier:

The result on the client:

The result on the server:

131779-server+result.png

I found the answer, next to setting the owner of the Actor (in this case tSoldier in the PlayerController.cpp) you have to set the owner of the controller as well.

So the result would be this:

void ABasePlayerController::ServerSpawnSoldiers_Implementation(const TArray<ESoldierTypes>& aSoldierArray, FVector aPosition, APlayerController* aOwner)
     {
         UE_LOG(LogTemp, Warning, TEXT("received soldier spawn"));
         FActorSpawnParameters tParams;
         tParams.Owner = aOwner;
         ABaseSoldier* tSoldier = (ABaseSoldier*)GetWorld()->SpawnActor(mMeleeSoldier, &aPosition, &FRotator::ZeroRotator, tParams);
         tSoldier->GetController()->SetOwner(aOwner);
     }