RPC client/server execution

Hey folks,

I’m just starting to play around with RPCs and wanted some clarification on the difference between the Client and Server keywords that you can use when defining the replicated function.

The engine documentation says that the ‘Server’ keyword can be used to “To declare a function as an RPC that will be called on the client, but executed on the server”.

I’ve made a small modification to the 3rd person template and added a replicated function in to the main player actor:



// this is an example of a function replication
// Reliable:		high priority network message, won't be dropped (unreliable for things like material changes, reliable for gameplay events)
// Server:			keyword indicates that it will be called on client but executed on the server
// WithValidation:	arguments get checked before the server is called
UFUNCTION( Reliable, Server, WithValidation )
void MyServerFunction();
void MyServerFunction_Implementation();	
bool MyServerFunction_Validate();


And the implementation:



// the actual work done by the replicated function
void ANetworkingTutorialCharacter::MyServerFunction_Implementation()
{
	GEngine->AddOnScreenDebugMessage( -1, 5.0f, FColor::Red, TEXT("Client called, server executed!!") );
}

// returns whether the replicated function is allowed to execute
bool ANetworkingTutorialCharacter::MyServerFunction_Validate()
{
	return true;
}


Then in my character-move function:



void ANetworkingTutorialCharacter::MoveForward(float Value)
{
	if ((Controller != NULL) && (Value != 0.0f))
	{
		// test the replicated function
		MyServerFunction();

                ...
        }
}


So from my understanding of how replication works, if the client moves forward the server should execute the ‘implementation’ version of MyServerFunction and the debug text will be displayed on the Server screen.

However when calling this I’m getting debug messages coming up on both Server and Client so clearly I’m missing something (it doesn’t look like AddOnscreenDebugMessage is a replicated function).

Any ideas why calling MyServerFunction on the client would display my debug text?

Thanks!

The reason that the code is running from the client and then running on both the server and the client is that in a “Server” RPC method, the code is actually run on both the server and the client that owns the actor if it is the calling client. Where does this come from? Here are the docs for client-server execution flows for RPCs: https://docs.unrealengine.com/latest/INT/Gameplay/Networking/Actors/RPCs/#rpcinvokedfromtheserver And here is more on Net roles in UE4: https://docs.unrealengine.com/latest/INT/Gameplay/Networking/Actors/Roles/index.html, finally, here is some more on ownership: https://docs.unrealengine.com/latest/INT/Gameplay/Networking/Actors/OwningConnections/index.html

One thing that must be pointed out - when an RPC is called, it will always run on the INVOKING client, whether it owns that actor or not. It will only call the SERVER side method if the calling client that invoked the method is the owner of the actor. So, how to make sure that RPC code is only implemented on a server? Well, if you look at the first person shooter game example, you will see a lot of this in the server RPC definitions:


void MyActorBasedClass::MyFunction()
{
    if(Role < ROLE_Authority)
    {
         // ... sometimes you will see cosmetic code here like animation updates or particle effects ...
         ServerMyFunction();
    }
    else
    {
        // ... code goes here that is executed on the server ...
    }
}

void MyActorBasedClass::ServerMyFunction_Implementation()
{
    MyFunction(); // because we are in the context of a server, it will call the else block of code
}

Hi smartyMarty,

Thanks for the clarification, it makes sense that the invoking client would have the code execute locally.

Given the following code I’m still seeing the debug text displayed on the client when I move the Actor on the server forward (moving forward on the client has no effect); I guess that must be because the ‘MoveForward’ function is bound to the InputComponent, which is replicating the movement of the server’s Actor:



void ANetworkingTutorialCharacter::MoveForward(float Value)
{
	if ((Controller != NULL) && (Value != 0.0f))
	{
		// test the replicated function, restrict execution to the sever
		if( Role == ROLE_Authority )
		{
			MyServerFunction();
		}

                ....
        }
}


Thanks for your help!

It should be like this:


void MyActorBasedClass::MyFunction()
{
    if(Role < ROLE_Authority)
    {
         // ... sometimes you will see cosmetic code here like animation updates or particle effects ...
         ServerMyFunction();
    }
    else
    {        
        // ... code goes here that is executed on the server ...
    }
}

void MyActorBasedClass::ServerMyFunction_Implementation()
{
    ServerMyFunction();
  // because we are in the context of a server, it will call the else block of code
}

Yeah I figured the function name was just a typo :slight_smile:

Shouldn’t that if/else check use an equality operator, that or the call to ServerMyFunction should be in the else block (if we only want Actors with Role_Authority to execute it).

If you want actors with Role_Authority to execute it then you can change the function like this:

void MyActorBasedClass::MyFunction()
{
    if (HasAuthority())
    {
         //...execute code if this actor is server
    }
}

Ah right, of course… just got sidetracked by the call to *ServerMyFunction *in the if block.

Thanks!

Thanks for that quick fix :smiley: