Skip to content

Commit

Permalink
fix(RPC): fixing call when type is generic
Browse files Browse the repository at this point in the history
  • Loading branch information
James-Frowen committed Feb 6, 2022
1 parent af4e02e commit 84e2dd6
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 16 deletions.
35 changes: 31 additions & 4 deletions Assets/Mirage/Runtime/RemoteCalls/RemoteCallHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,38 @@ public class RemoteCall
/// </summary>
public string name;

public bool AreEqual(Type invokeClass, RpcInvokeType invokeType, RpcDelegate invokeFunction)
public bool AreEqual(Type declaringType, RpcInvokeType invokeType, RpcDelegate function)
{
return DeclaringType == invokeClass &&
InvokeType == invokeType &&
function == invokeFunction;
if (InvokeType != invokeType)
return false;

if (declaringType.IsGenericType)
return AreEqualIgnoringGeneric(declaringType, function);

return DeclaringType == declaringType
&& this.function == function;
}

bool AreEqualIgnoringGeneric(Type declaringType, RpcDelegate function)
{
// if this.type not generic, then not equal
if (!DeclaringType.IsGenericType)
return false;

// types must be in same assembly to be equal
if (DeclaringType.Assembly != declaringType.Assembly)
return false;

Debug.Assert(declaringType == function.Method.DeclaringType);
Debug.Assert(DeclaringType == this.function.Method.DeclaringType);

// we check Assembly above, so we know these 2 functions must be in same assmebly here
// - we can check Namespace and Name to acount generic check
// - weaver check to make sure method in type have unique hash
// - weaver appends hash to names, so overloads will have different hash/names
return DeclaringType.Namespace == declaringType.Namespace
&& DeclaringType.Name == declaringType.Name
&& this.function.Method.Name == function.Method.Name;
}

internal void Invoke(NetworkReader reader, NetworkBehaviour invokingType, INetworkPlayer senderPlayer = null, int replyId = 0)
Expand Down
20 changes: 20 additions & 0 deletions Assets/Mirage/Weaver/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,26 @@ public static MethodReference MakeHostInstanceGeneric(this MethodReference self,
return self.Module.ImportReference(reference);
}


public static MethodReference MakeHostInstanceSelfGeneric(this MethodReference self)
{
TypeReference type = self.DeclaringType;
if (!type.HasGenericParameters)
{
// if type isn't generic we dont need to do anything
return self;
}
else
{
// make generic instance of type, and give it the generic params as args
var genericType = new GenericInstanceType(type);
foreach (GenericParameter param in type.GenericParameters)
genericType.GenericArguments.Add(param);

return self.MakeHostInstanceGeneric(genericType);
}
}

public static bool TryGetCustomAttribute<TAttribute>(this ICustomAttributeProvider method, out CustomAttribute customAttribute)
{
foreach (CustomAttribute ca in method.CustomAttributes)
Expand Down
5 changes: 3 additions & 2 deletions Assets/Mirage/Weaver/Processors/ClientRpcProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ MethodDefinition GenerateSkeleton(MethodDefinition md, MethodDefinition userCode
ReadArguments(md, worker, readerParameter, senderParameter: null, hasNetworkConnection, paramSerializers);

// invoke actual ServerRpc function
worker.Append(worker.Create(OpCodes.Callvirt, userCodeFunc));
worker.Append(worker.Create(OpCodes.Callvirt, userCodeFunc.MakeHostInstanceSelfGeneric()));
worker.Append(worker.Create(OpCodes.Ret));

return rpc;
Expand Down Expand Up @@ -233,7 +233,7 @@ void InvokeBody(ILProcessor worker, MethodDefinition rpc)
worker.Append(worker.Create(OpCodes.Ldarg, i + 1));
}
}
worker.Append(worker.Create(OpCodes.Callvirt, rpc));
worker.Append(worker.Create(OpCodes.Callvirt, rpc.MakeHostInstanceSelfGeneric()));
}

public ClientRpcMethod ProcessRpc(MethodDefinition md, CustomAttribute clientRpcAttr)
Expand All @@ -254,6 +254,7 @@ public ClientRpcMethod ProcessRpc(MethodDefinition md, CustomAttribute clientRpc

return new ClientRpcMethod
{
UniqueHash = GetStableHash(md),
stub = md,
target = clientTarget,
excludeOwner = excludeOwner,
Expand Down
11 changes: 10 additions & 1 deletion Assets/Mirage/Weaver/Processors/NetworkBehaviourProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,24 @@ void ProcessRpcs()
{
// copy the list of methods because we will be adding methods in the loop
var methods = new List<MethodDefinition>(netBehaviourSubclass.Methods);
// find ServerRpc and RPC functions

var rpcs = new List<RpcMethod>();
// kept track of hashes to check they are unique
var hash = new Dictionary<int, RpcMethod>();

foreach (MethodDefinition md in methods)
{
try
{
RpcMethod rpc = CheckAndProcessRpc(md);
if (rpc != null)
{
if (hash.ContainsKey(rpc.UniqueHash))
{
logger.Error($"Found 2 methods with same hash {rpc.UniqueHash} (see below).\nMethod1:{rpc.stub}\nMethod2:{rpc.stub}", md);
}

hash.Add(rpc.UniqueHash, rpc);
rpcs.Add(rpc);
}
}
Expand Down
2 changes: 1 addition & 1 deletion Assets/Mirage/Weaver/Processors/RegisterRpc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ static void CallRegister(ILProcessor worker, RpcMethod rpcMethod, RpcInvokeType?

// new delegate
worker.Append(worker.Create(OpCodes.Ldnull));
worker.Append(worker.Create(OpCodes.Ldftn, skeleton));
worker.Append(worker.Create(OpCodes.Ldftn, skeleton.MakeHostInstanceSelfGeneric()));
MethodReference @delegate = CreateRpcDelegate(skeleton);
worker.Append(worker.Create(OpCodes.Newobj, @delegate));

Expand Down
2 changes: 2 additions & 0 deletions Assets/Mirage/Weaver/Processors/RpcMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ public abstract class RpcMethod
public MethodDefinition stub;
/// <summary>Method that receives the call and deserialize parmas</summary>
public MethodDefinition skeleton;
/// <summary>Hash given to method in order to call it over the network. Should be unqiue.</summary>
public int UniqueHash;
}

public class ServerRpcMethod : RpcMethod
Expand Down
12 changes: 4 additions & 8 deletions Assets/Mirage/Weaver/Processors/ServerRpcProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ MethodDefinition GenerateSkeleton(MethodDefinition method, MethodDefinition user
ReadArguments(method, worker, readerParameter, senderParameter, false, paramSerializers);

// invoke actual ServerRpc function
worker.Append(worker.Create(OpCodes.Callvirt, userCodeFunc));
worker.Append(worker.Create(OpCodes.Callvirt, userCodeFunc.MakeHostInstanceSelfGeneric()));
worker.Append(worker.Create(OpCodes.Ret));

return cmd;
Expand All @@ -201,6 +201,7 @@ public ServerRpcMethod ProcessRpc(MethodDefinition md, CustomAttribute serverRpc
MethodDefinition skeletonFunc = GenerateSkeleton(md, userCodeFunc, paramSerializers);
return new ServerRpcMethod
{
UniqueHash = GetStableHash(md),
stub = md,
requireAuthority = requireAuthority,
skeleton = skeletonFunc
Expand All @@ -218,7 +219,7 @@ protected void InvokeBody(ILProcessor worker, MethodDefinition rpc)
// if param is network player, use Server's Local player instead
// in host mode this will be the Server's copy of the the player,
// in server mode this will be null
if (IsNetworkPlayer(param))
if (IsNetworkPlayer(param.ParameterType))
{
worker.Append(worker.Create(OpCodes.Ldarg_0));
worker.Append(worker.Create(OpCodes.Call, (NetworkBehaviour nb) => nb.Server));
Expand All @@ -229,12 +230,7 @@ protected void InvokeBody(ILProcessor worker, MethodDefinition rpc)
worker.Append(worker.Create(OpCodes.Ldarg, param));
}
}
worker.Append(worker.Create(OpCodes.Callvirt, rpc));

bool IsNetworkPlayer(ParameterDefinition param)
{
return param.ParameterType.Resolve().ImplementsInterface<INetworkPlayer>();
}
worker.Append(worker.Create(OpCodes.Callvirt, rpc.MakeHostInstanceSelfGeneric()));
}
}
}

0 comments on commit 84e2dd6

Please sign in to comment.