Client can't call RPC Server even with a valid NetOwner.

For client to server RPCs, the Owner must be the client attempting to call the RPC.

In general, actors that are placed in a level (such as doors) are never owned by any particular player.

I see you are attempting to SetOwner from the Interact function, but the Owner cannot be set from client-side, it has to be set from Authority, so it has no effect there. It may appear to work (ie. when you print owner after calling SetOwner it will show) but since the Owner is not modified on server-side it will not accept the RPC.

Instead of trying to modify the Owner of level-placed actors, you should rework your code a bit to route the RPCs through a real player-owned class (such as Character), then forward to actor code once you’re on server side.

You can adjust your code pretty easily to do so.

  1. AInteractiveActor does not do the RPC, it just needs an entry point
UFUNCTION()
virtual void OnInteract(APawn* Sender)
{
    if (HasAuthority())
    {
        // server interaction
    }
    else
    {
        // client interaction (optional - can be used for prediction)
    }
}
  1. Move the RPC logic to your Character class instead
UFUNCTION(Server, Reliable, WithValidation)
virtual void ServerInteract(AInteractiveActor* Target);
virtual void ServerInteract_Implementation(AInteractiveActor* Target);
virtual void ServerInteract_Validate(AInteractiveActor* Target);

// in function Interact()
    if (Hit.GetActor()->IsA(AInteractiveActor::StaticClass()))
    {
        AInteractiveActor* InteractiveActor = Cast<AInteractiveActor>(Hit.GetActor());

        if (!HasAuthority())
            InteractiveActor->OnInteract(this);  //optional, can be used for prediction
        
        ServerInteract(InteractiveActor);
    }
// end function Interact

void AEscapeGameCharacter::ServerInteract_Implementation(AInteractiveActor* Target)
{
    if (Target)
        Target->OnInteract(this);
}
1 Like