Server RPC Design Pattern

While programming our game, there seems to be a pattern emerging concern a server’s authority. Most, if not all of our server methods require at least 4 method.

  1. The initial call MyMethod(), which is pretty much the public API to be called in the code. This includes client-side logic whether the method should do certain things.

  2. The same logic, but now replicated on the server: Server_MyMethod_Implementation(). The server is an authority and decides whether the client was right.

  3. Network verification: Server_MyMethod_Validate(). Pretty trivial.

  4. Method that actually does what is requested when the client and server give the go-ahead: DoMyMethod().

My question is, is whether this is an acceptable pattern, and what do other people use for server side authorive RPCs? It seems rather complex and a bit too much for just simple functionality. I’ve put a small snippet of our game code below to give an impression of how this are structured.

// --------------------------------------------------------------\
// CHARGE START                                                  |
// --------------------------------------------------------------/

void AWeapon::ChargeStart()
{
    if (MayShootOrCharge())
    {
        if (Role < ROLE_Authority)
            Server_ChargeStart();
        else
            DoChargeStart();
    }
}

void AWeapon::Server_ChargeStart_Implementation()
{
    if (MayShootOrCharge())
        DoChargeStart();
}

bool AWeapon::Server_ChargeStart_Validate()
{
    return true;
}

void AWeapon::DoChargeStart()
{
    SetCharging(true);
}

So there is nothing wrong with this pattern. In fact, its nice in that it hides the client/server details from the user of the API. However, personally I rarely use this because I prefer to know explicitly who is calling what and, at least in code areas I’m responsible for, I have clear delineations of client/server functionality.

That being said, you aren’t going to get away from _Implementation and _Validate functions. Those are just side effects of UnrealHeaderTool and the way it works.

At Epic, we require all client/server RPCs to start with Client or Server, so it makes the explicit very clear.

So we typically have

//header
ServerDoSomething()

//cpp
ServerDoSomething_Implementation()
ServerDoSomething_Validate

We will still have the Role == Role_Authority checks on functions that might be ambiguous or otherwise sanity check the code.

Kind of a high level answer, if you have further questions, shoot them here and I can get more specific if you’d like.