-
Notifications
You must be signed in to change notification settings - Fork 457
Description
Completely separate [ServerRpc] and [ClientRpc] instead of a shared configurable [Rpc] is leading to a lot of verbose, nuisance code patterns. I will provide both examples of how things work now and an example of how I'd like things to work.
Client-side authority is something we strive for whenever possible because waiting for the round trip confirmation from the server is a real bummer for player feel. With these client authority situations you often want to execute the state code immediately and then tell the server that will send it to everybody else. (And, as host, you may also be the server.)
Current Methods
Here is one way we must currently do this:
// client-authoritative
void StopDoingThing()
{
if (m_thing != null)
{
SomeOtherStateChange();
m_thing.Stop();
m_thing = null;
StopDoingThing_ServerRpc();
}
}
[ServerRpc(RequireOwnership = false)]]
void StopDoingThing_ServerRpc()
{
StopDoingThing_ClientRpc();
}
[ClientRpc]
void StopDoingThing_ClientRpc()
{
// will also run again on originating client unless we do something with ClientRpcParams/ServerRpcParams/a client id argument passed through this chain of methods
StopDoingThing();
}
And an alternative way we must do this:
// client-authoritative
void StopDoingThing()
{
if (m_thing != null)
{
SomeOtherStateChange();
m_thing.Stop();
m_thing = null;
// or IsHost if you prefer, point being a client can also be the server
if (IsServer) StopDoingThing_ClientRpc(m_clientRpcParamsThatExcludeServerClientId);
else StopDoingThing_ServerRpc();
}
}
[ServerRpc]
void StopDoingThing_ServerRpc()
{
StopDoingThing();
// Exclude host client id and also the originating client id here
// Otherwise our code would execute a second time on those clients
ClientRpcParams params = new ClientRpcParams etc etc;
StopDoingThing_ClientRpc(params);
}
[ClientRpc]
void StopDoingThing_ClientRpc(ClientRpcParams clientRpcParams = default)
{
StopDoingThing();
}
Desired Methods
I'd love something that works like this:
// client-authoritative
// Configurable [Rpc] attribute creates a single method that any client or server can call directly
[Rpc(
// Targets.All = Run this Rpc on all clients. If you are a client, this RPC would run on the server and then the server would broadcast to all clients.
// Targets.Others = Same as All but exclude me when running this RPC on clients
// Targets.Server = Only run on server
Targets = Targets.All,
// Whether this RPC should execute immediately on this computer/client or if it should wait until the RPC message is received.
// If Targets is Targets.Others and RunImmediateLocal is true, an exception should be thrown because the RPC would never run on this client, so RunImmediateLocal cannot be set to true.
// If Targets is Targets.All and RunImmediateLocal is true, the RPC should NOT run a second time on this client.
RunImmediateLocal = true
)]
void StopDoingThing_Rpc()
{
if (m_thing != null)
{
SomeOtherStateChange();
m_thing.Stop();
m_thing = null;
}
}
I think it's pretty clear why I want this functionality and how it reduces verbosity.