Skip to content

Commit

Permalink
breaking: Remove TargetRPC & use ClientRPC option instead (#293)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Removed [TargetRpc],  use [ClientR(target=Client.Owner)] instead
  • Loading branch information
Lymdun committed Jul 20, 2020
1 parent ffc44f1 commit 4ace144
Show file tree
Hide file tree
Showing 71 changed files with 486 additions and 669 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,6 @@ static void ProcessMethods(TypeDefinition td)
Weaver.Error($"ClientRpc {md.Name} must be declared inside a NetworkBehaviour", md);
}

if (ca.AttributeType.FullName == Weaver.TargetRpcType.FullName)
{
Weaver.Error($"TargetRpc {md.Name} must be declared inside a NetworkBehaviour", md);
}

string attributeName = ca.Constructor.DeclaringType.ToString();

switch (attributeName)
Expand Down
58 changes: 11 additions & 47 deletions Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ public enum RemoteCallType
{
ServerRpc,
ClientRpc,
TargetRpc,
SyncEvent
}

Expand All @@ -24,11 +23,9 @@ class NetworkBehaviourProcessor
readonly Dictionary<FieldDefinition, FieldDefinition> syncVarNetIds = new Dictionary<FieldDefinition, FieldDefinition>();
readonly List<CmdResult> serverRpcs = new List<CmdResult>();
readonly List<ClientRpcResult> clientRpcs = new List<ClientRpcResult>();
readonly List<MethodDefinition> targetRpcs = new List<MethodDefinition>();
readonly List<EventDefinition> eventRpcs = new List<EventDefinition>();
readonly List<MethodDefinition> serverRpcSkeletonFuncs = new List<MethodDefinition>();
readonly List<MethodDefinition> clientRpcSkeletonFuncs = new List<MethodDefinition>();
readonly List<MethodDefinition> targetRpcSkeletonFuncs = new List<MethodDefinition>();
readonly List<MethodDefinition> eventRpcInvocationFuncs = new List<MethodDefinition>();

readonly TypeDefinition netBehaviourSubclass;
Expand All @@ -42,6 +39,7 @@ public struct CmdResult
public struct ClientRpcResult
{
public MethodDefinition method;
public Client target;
public bool excludeOwner;
}

Expand Down Expand Up @@ -151,8 +149,8 @@ public static bool WriteArguments(ILProcessor worker, MethodDefinition method, R
writer.WriteNetworkIdentity(someTarget);
*/

bool skipFirst = callType == RemoteCallType.TargetRpc
&& TargetRpcProcessor.HasNetworkConnectionParameter(method);
bool skipFirst = callType == RemoteCallType.ClientRpc
&& RpcProcessor.HasNetworkConnectionParameter(method);

// arg of calling function, arg 0 is "this" so start counting at 1
int argNum = 1;
Expand Down Expand Up @@ -214,7 +212,7 @@ public static void MarkAsProcessed(TypeDefinition td)

void GenerateConstants()
{
if (serverRpcs.Count == 0 && clientRpcs.Count == 0 && targetRpcs.Count == 0 && eventRpcs.Count == 0 && syncObjects.Count == 0)
if (serverRpcs.Count == 0 && clientRpcs.Count == 0 && eventRpcs.Count == 0 && syncObjects.Count == 0)
return;

Weaver.DLog(netBehaviourSubclass, " GenerateConstants ");
Expand Down Expand Up @@ -286,11 +284,6 @@ void GenerateConstants()
GenerateRegisterRemoteDelegate(cctorWorker, Weaver.registerRpcDelegateReference, clientRpcSkeletonFuncs[i], clientRpcResult.method.Name);
}

for (int i = 0; i < targetRpcs.Count; ++i)
{
GenerateRegisterRemoteDelegate(cctorWorker, Weaver.registerRpcDelegateReference, targetRpcSkeletonFuncs[i], targetRpcs[i].Name);
}

for (int i = 0; i < eventRpcs.Count; ++i)
{
GenerateRegisterRemoteDelegate(cctorWorker, Weaver.registerEventDelegateReference, eventRpcInvocationFuncs[i], eventRpcs[i].Name);
Expand Down Expand Up @@ -794,8 +787,8 @@ public static bool ReadArguments(MethodDefinition method, ILProcessor worker, Re
CallCmdDoSomething(reader.ReadPackedInt32(), reader.ReadNetworkIdentity());
*/

bool skipFirst = callType == RemoteCallType.TargetRpc
&& TargetRpcProcessor.HasNetworkConnectionParameter(method);
bool skipFirst = callType == RemoteCallType.ClientRpc
&& RpcProcessor.HasNetworkConnectionParameter(method);

// arg of calling function, arg 0 is "this" so start counting at 1
int argNum = 1;
Expand All @@ -815,7 +808,6 @@ public static bool ReadArguments(MethodDefinition method, ILProcessor worker, Re
continue;
}


MethodReference readFunc = Readers.GetReadFunc(param.ParameterType);

if (readFunc == null)
Expand Down Expand Up @@ -894,7 +886,7 @@ static bool ValidateParameter(MethodReference method, ParameterDefinition param,

if (IsNetworkConnection(param.ParameterType))
{
if (callType == RemoteCallType.TargetRpc && firstParam)
if (callType == RemoteCallType.ClientRpc && firstParam)
{
// perfectly fine, target rpc can receive a network connection as first parameter
return true;
Expand Down Expand Up @@ -940,12 +932,6 @@ void ProcessMethods()
break;
}

if (ca.AttributeType.FullName == Weaver.TargetRpcType.FullName)
{
ProcessTargetRpc(names, md, ca);
break;
}

if (ca.AttributeType.FullName == Weaver.ClientRpcType.FullName)
{
ProcessClientRpc(names, md, ca);
Expand All @@ -957,57 +943,35 @@ void ProcessMethods()

void ProcessClientRpc(HashSet<string> names, MethodDefinition md, CustomAttribute clientRpcAttr)
{
if (!RpcProcessor.Validate(md))
{
if (!RpcProcessor.Validate(md, clientRpcAttr))
return;
}

if (names.Contains(md.Name))
{
Weaver.Error($"Duplicate ClientRpc name {md.Name}", md);
return;
}

Client clientTarget = clientRpcAttr.GetField("target", Client.Observers);
bool excludeOwner = clientRpcAttr.GetField("excludeOwner", false);

names.Add(md.Name);
clientRpcs.Add(new ClientRpcResult
{
method = md,
target = clientTarget,
excludeOwner = excludeOwner
});

MethodDefinition userCodeFunc = RpcProcessor.GenerateStub(md, clientRpcAttr);

MethodDefinition skeletonFunc = RpcProcessor.GenerateSkeleton(md, userCodeFunc);
MethodDefinition skeletonFunc = RpcProcessor.GenerateSkeleton(md, userCodeFunc, clientRpcAttr);
if (skeletonFunc != null)
{
clientRpcSkeletonFuncs.Add(skeletonFunc);
}
}

void ProcessTargetRpc(HashSet<string> names, MethodDefinition md, CustomAttribute targetRpcAttr)
{
if (!TargetRpcProcessor.Validate(md))
return;

if (names.Contains(md.Name))
{
Weaver.Error($"Duplicate Target Rpc name {md.Name}", md);
return;
}
names.Add(md.Name);
targetRpcs.Add(md);

MethodDefinition userCodeFunc = TargetRpcProcessor.GenerateStub(md, targetRpcAttr);

MethodDefinition skeletonFunc = TargetRpcProcessor.GenerateSkeleton(md, userCodeFunc);
if (skeletonFunc != null)
{
targetRpcSkeletonFuncs.Add(skeletonFunc);
}
}

void ProcessServerRpc(HashSet<string> names, MethodDefinition md, CustomAttribute serverRpcAttr)
{
if (!ServerRpcProcessor.Validate(md))
Expand Down
87 changes: 82 additions & 5 deletions Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,20 @@
using Mono.Cecil.Cil;
namespace Mirror.Weaver
{
public enum Client { Owner, Observers, Connection }

/// <summary>
/// Processes [Rpc] methods in NetworkBehaviour
/// </summary>
public static class RpcProcessor
{
// helper functions to check if the method has a NetworkConnection parameter
public static bool HasNetworkConnectionParameter(MethodDefinition md)
{
return md.Parameters.Count > 0 &&
md.Parameters[0].ParameterType.FullName == Weaver.INetworkConnectionType.FullName;
}

/// <summary>
/// Generates a skeleton for an RPC
/// </summary>
Expand All @@ -27,7 +36,7 @@ public static class RpcProcessor
/// }
/// </code>
/// </remarks>
public static MethodDefinition GenerateSkeleton(MethodDefinition md, MethodDefinition userCodeFunc)
public static MethodDefinition GenerateSkeleton(MethodDefinition md, MethodDefinition userCodeFunc, CustomAttribute clientRpcAttr)
{
var rpc = new MethodDefinition(
MethodProcessor.SkeletonPrefix + md.Name,
Expand All @@ -43,6 +52,15 @@ public static MethodDefinition GenerateSkeleton(MethodDefinition md, MethodDefin
worker.Append(worker.Create(OpCodes.Ldarg_0));
worker.Append(worker.Create(OpCodes.Castclass, md.DeclaringType));

// NetworkConnection parameter is only required for Client.Connection
Client target = clientRpcAttr.GetField("target", Client.Observers);
if (target == Client.Connection && HasNetworkConnectionParameter(md))
{
//client.connection
worker.Append(worker.Create(OpCodes.Ldarg_0));
worker.Append(worker.Create(OpCodes.Call, Weaver.BehaviorConnectionToServerReference));
}

if (!NetworkBehaviourProcessor.ReadArguments(md, worker, RemoteCallType.ClientRpc))
return null;

Expand All @@ -64,7 +82,7 @@ public static MethodDefinition GenerateSkeleton(MethodDefinition md, MethodDefin
/// <param name="ServerRpcAttr">The attribute that made this an RPC</param>
/// <returns>The method containing the original code</returns>
/// <remarks>
/// Generates code like this:
/// Generates code like this: (Observers case)
/// <code>
/// public void Test (int param)
/// {
Expand All @@ -77,6 +95,36 @@ public static MethodDefinition GenerateSkeleton(MethodDefinition md, MethodDefin
/// // whatever the user did before
/// }
/// </code>
///
/// Generates code like this: (Owner/Connection case)
/// <code>
/// public void TargetTest(NetworkConnection conn, int param)
/// {
/// NetworkWriter writer = new NetworkWriter();
/// writer.WritePackedUInt32((uint)param);
/// base.SendTargetRPCInternal(conn, typeof(class), "TargetTest", val);
/// }
///
/// public void UserCode_TargetTest(NetworkConnection conn, int param)
/// {
/// // whatever the user did before
/// }
/// </code>
/// or if no connection is specified
///
/// <code>
/// public void TargetTest (int param)
/// {
/// NetworkWriter writer = new NetworkWriter();
/// writer.WritePackedUInt32((uint) param);
/// base.SendTargetRPCInternal(null, typeof(class), "TargetTest", val);
/// }
///
/// public void UserCode_TargetTest(int param)
/// {
/// // whatever the user did before
/// }
/// </code>
/// </remarks>
public static MethodDefinition GenerateStub(MethodDefinition md, CustomAttribute clientRpcAttr)
{
Expand All @@ -94,21 +142,36 @@ public static MethodDefinition GenerateStub(MethodDefinition md, CustomAttribute

string rpcName = md.Name;

Client target = clientRpcAttr.GetField("target", Client.Observers);
int channel = clientRpcAttr.GetField("channel", 0);
bool excludeOwner = clientRpcAttr.GetField("excludeOwner", false);

// invoke SendInternal and return
// this
worker.Append(worker.Create(OpCodes.Ldarg_0));

if (target == Client.Connection && HasNetworkConnectionParameter(md))
worker.Append(worker.Create(OpCodes.Ldarg_1));
else if (target == Client.Owner)
worker.Append(worker.Create(OpCodes.Ldnull));

worker.Append(worker.Create(OpCodes.Ldtoken, md.DeclaringType));
// invokerClass
worker.Append(worker.Create(OpCodes.Call, Weaver.getTypeFromHandleReference));
worker.Append(worker.Create(OpCodes.Ldstr, rpcName));
// writer
worker.Append(worker.Create(OpCodes.Ldloc_0));
worker.Append(worker.Create(OpCodes.Ldc_I4, channel));
worker.Append(worker.Create(excludeOwner ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0));
worker.Append(worker.Create(OpCodes.Callvirt, Weaver.sendRpcInternal));

if (target == Client.Observers)
{
worker.Append(worker.Create(excludeOwner ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0));
worker.Append(worker.Create(OpCodes.Callvirt, Weaver.sendRpcInternal));
}
else
{
worker.Append(worker.Create(OpCodes.Callvirt, Weaver.sendTargetRpcInternal));
}

NetworkBehaviourProcessor.WriteRecycleWriter(worker);

Expand All @@ -117,7 +180,7 @@ public static MethodDefinition GenerateStub(MethodDefinition md, CustomAttribute
return rpc;
}

public static bool Validate(MethodDefinition md)
public static bool Validate(MethodDefinition md, CustomAttribute clientRpcAttr)
{
if (md.IsAbstract)
{
Expand All @@ -131,6 +194,20 @@ public static bool Validate(MethodDefinition md)
return false;
}

Client target = clientRpcAttr.GetField("target", Client.Observers);
if (target == Client.Connection && !HasNetworkConnectionParameter(md))
{
Weaver.Error("ClientRpc with Client.Connection needs a network connection parameter", md);
return false;
}

bool excludeOwner = clientRpcAttr.GetField("excludeOwner", false);
if (target == Client.Owner && excludeOwner)
{
Weaver.Error("ClientRpc with Client.Owner cannot have excludeOwner set as true", md);
return false;
}

// validate
return NetworkBehaviourProcessor.ProcessMethodsValidateFunction(md) &&
NetworkBehaviourProcessor.ProcessMethodsValidateParameters(md, RemoteCallType.ClientRpc);
Expand Down

0 comments on commit 4ace144

Please sign in to comment.