Skip to content

Commit

Permalink
feat(Weaver): allowing bit packing attributes to work on structs and …
Browse files Browse the repository at this point in the history
…rpcs (#933)

* feat: allowing bit packing attributes to work on structs and rpcs
* docs: doc comments for varint
* fix: order of networkplayer in ServerRpc is no longer required
  • Loading branch information
James-Frowen committed Sep 20, 2021
1 parent 9c1a4e6 commit dca6b54
Show file tree
Hide file tree
Showing 262 changed files with 15,283 additions and 4,247 deletions.
6 changes: 4 additions & 2 deletions Assets/Mirage/Runtime/Serialization/WeaverAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ public class QuaternionPackAttribute : Attribute
}

/// <summary>
/// Tells weaver how many bits to sue for field
/// Tells weaver the max range for small, medium and large values.
/// <para>Allows small values to be sent using less bits</para>
/// <para>Only works with interager fields (byte, int, ulong, enums etc)</para>
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)]
Expand All @@ -110,7 +111,8 @@ public class VarIntAttribute : Attribute


/// <summary>
/// Tells weaver how many bits to sue for field
/// Tells weaver the block size to use for packing int values
/// <para>Allows small values to be sent using less bits</para>
/// <para>Only works with interager fields (byte, int, ulong, enums etc)</para>
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)]
Expand Down
17 changes: 14 additions & 3 deletions Assets/Mirage/Weaver/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,14 +211,25 @@ public static MethodReference MakeHostInstanceGeneric(this MethodReference self,
return self.Module.ImportReference(reference);
}

public static CustomAttribute GetCustomAttribute<TAttribute>(this ICustomAttributeProvider method)
public static bool TryGetCustomAttribute<TAttribute>(this ICustomAttributeProvider method, out CustomAttribute customAttribute)
{
foreach (CustomAttribute ca in method.CustomAttributes)
{
if (ca.AttributeType.Is<TAttribute>())
return ca;
{
customAttribute = ca;
return true;
}
}
return null;

customAttribute = null;
return false;
}

public static CustomAttribute GetCustomAttribute<TAttribute>(this ICustomAttributeProvider method)
{
_ = method.TryGetCustomAttribute<TAttribute>(out CustomAttribute customAttribute);
return customAttribute;
}

public static bool HasCustomAttribute<TAttribute>(this ICustomAttributeProvider attributeProvider)
Expand Down
7 changes: 7 additions & 0 deletions Assets/Mirage/Weaver/MethodExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ public static VariableDefinition AddLocal(this MethodDefinition method, TypeRefe
return local;
}

// todo add documentation
public static Instruction Create(this ILProcessor worker, OpCode code, LambdaExpression expression)
{
MethodReference typeref = worker.Body.Method.Module.ImportReference(expression);
return worker.Create(code, typeref);
}

// todo add documentation
public static Instruction Create(this ILProcessor worker, OpCode code, Expression<Action> expression)
{
Expand Down
27 changes: 14 additions & 13 deletions Assets/Mirage/Weaver/Processors/ClientRpcProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using Mirage.RemoteCalls;
using Mirage.Serialization;
using Mirage.Weaver.Serialization;
using Mono.Cecil;
using Mono.Cecil.Cil;

Expand Down Expand Up @@ -46,13 +47,13 @@ public ClientRpcProcessor(ModuleDefinition module, Readers readers, Writers writ
/// }
/// </code>
/// </remarks>
MethodDefinition GenerateSkeleton(MethodDefinition md, MethodDefinition userCodeFunc, CustomAttribute clientRpcAttr)
MethodDefinition GenerateSkeleton(MethodDefinition md, MethodDefinition userCodeFunc, CustomAttribute clientRpcAttr, ValueSerializer[] paramSerializers)
{
MethodDefinition rpc = md.DeclaringType.AddMethod(
SkeletonPrefix + md.Name,
MethodAttributes.Family | MethodAttributes.HideBySig);

_ = rpc.AddParam<NetworkReader>("reader");
ParameterDefinition readerParameter = rpc.AddParam<NetworkReader>("reader");
_ = rpc.AddParam<INetworkPlayer>("senderConnection");
_ = rpc.AddParam<int>("replyId");

Expand All @@ -62,7 +63,7 @@ MethodDefinition GenerateSkeleton(MethodDefinition md, MethodDefinition userCode

// NetworkConnection parameter is only required for Client.Connection
RpcTarget target = clientRpcAttr.GetField("target", RpcTarget.Observers);
bool hasNetworkConnection = target == RpcTarget.Player && HasNetworkConnectionParameter(md);
bool hasNetworkConnection = target == RpcTarget.Player && HasNetworkPlayerParameter(md);

if (hasNetworkConnection)
{
Expand All @@ -73,8 +74,7 @@ MethodDefinition GenerateSkeleton(MethodDefinition md, MethodDefinition userCode
worker.Append(worker.Create(OpCodes.Call, (NetworkClient nb) => nb.Player));
}

if (!ReadArguments(md, worker, hasNetworkConnection))
return rpc;
ReadArguments(md, worker, readerParameter, senderParameter: null, hasNetworkConnection, paramSerializers);

// invoke actual ServerRpc function
worker.Append(worker.Create(OpCodes.Callvirt, userCodeFunc));
Expand Down Expand Up @@ -136,7 +136,7 @@ MethodDefinition GenerateSkeleton(MethodDefinition md, MethodDefinition userCode
/// }
/// </code>
/// </remarks>
MethodDefinition GenerateStub(MethodDefinition md, CustomAttribute clientRpcAttr)
MethodDefinition GenerateStub(MethodDefinition md, CustomAttribute clientRpcAttr, ValueSerializer[] paramSerializers)
{
MethodDefinition rpc = SubstituteMethod(md);

Expand All @@ -154,8 +154,7 @@ MethodDefinition GenerateStub(MethodDefinition md, CustomAttribute clientRpcAttr
worker.Append(worker.Create(OpCodes.Stloc, writer));

// write all the arguments that the user passed to the Rpc call
if (!WriteArguments(worker, md, writer, RemoteCallType.ClientRpc))
return rpc;
WriteArguments(worker, md, writer, paramSerializers, RemoteCallType.ClientRpc);

string rpcName = md.Name;

Expand All @@ -167,7 +166,7 @@ MethodDefinition GenerateStub(MethodDefinition md, CustomAttribute clientRpcAttr
// this
worker.Append(worker.Create(OpCodes.Ldarg_0));

if (target == RpcTarget.Player && HasNetworkConnectionParameter(md))
if (target == RpcTarget.Player && HasNetworkPlayerParameter(md))
worker.Append(worker.Create(OpCodes.Ldarg_1));
else if (target == RpcTarget.Owner)
worker.Append(worker.Create(OpCodes.Ldnull));
Expand Down Expand Up @@ -255,7 +254,7 @@ bool Validate(MethodDefinition md, CustomAttribute clientRpcAttr)
}

RpcTarget target = clientRpcAttr.GetField("target", RpcTarget.Observers);
if (target == RpcTarget.Player && !HasNetworkConnectionParameter(md))
if (target == RpcTarget.Player && !HasNetworkPlayerParameter(md))
{
logger.Error("ClientRpc with Client.Connection needs a network connection parameter", md);
return false;
Expand Down Expand Up @@ -294,7 +293,7 @@ void GenerateRegisterRemoteDelegate(ILProcessor worker, MethodDefinition func, s
worker.Append(worker.Create(OpCodes.Call, () => RemoteCallHelper.RegisterRpcDelegate(default, default, default)));
}

public void ProcessClientRpc(MethodDefinition md, CustomAttribute clientRpcAttr)
public void ProcessRpc(MethodDefinition md, CustomAttribute clientRpcAttr)
{
if (!ValidateRemoteCallAndParameters(md, RemoteCallType.ClientRpc))
{
Expand All @@ -307,9 +306,11 @@ public void ProcessClientRpc(MethodDefinition md, CustomAttribute clientRpcAttr)
RpcTarget clientTarget = clientRpcAttr.GetField("target", RpcTarget.Observers);
bool excludeOwner = clientRpcAttr.GetField("excludeOwner", false);

MethodDefinition userCodeFunc = GenerateStub(md, clientRpcAttr);
ValueSerializer[] paramSerializers = GetValueSerializers(md);

MethodDefinition skeletonFunc = GenerateSkeleton(md, userCodeFunc, clientRpcAttr);
MethodDefinition userCodeFunc = GenerateStub(md, clientRpcAttr, paramSerializers);

MethodDefinition skeletonFunc = GenerateSkeleton(md, userCodeFunc, clientRpcAttr, paramSerializers);
clientRpcs.Add(new ClientRpcMethod
{
stub = md,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,5 @@ public bool HasManualDeserializeOverride()
{
return TypeDefinition.GetMethod(DeserializeHelper.MethodName) != null;
}

public FieldDefinition AddPackerField<T>(string name)
{
return TypeDefinition.AddField<T>($"{name}__Packer", FieldAttributes.Private | FieldAttributes.Static);
}
}
}
47 changes: 29 additions & 18 deletions Assets/Mirage/Weaver/Processors/NetworkBehaviourProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,25 +106,9 @@ void ProcessRpcs()
// find ServerRpc and RPC functions
foreach (MethodDefinition md in methods)
{
bool rpc = false;
foreach (CustomAttribute ca in md.CustomAttributes)
{
if (ca.AttributeType.Is<ServerRpcAttribute>())
{
serverRpcProcessor.ProcessServerRpc(md, ca);
rpc = true;
break;
}
bool isRpc = CheckAndProcessRpc(md);

if (ca.AttributeType.Is<ClientRpcAttribute>())
{
clientRpcProcessor.ProcessClientRpc(md, ca);
rpc = true;
break;
}
}

if (rpc)
if (isRpc)
{
if (names.Contains(md.Name))
{
Expand All @@ -137,6 +121,33 @@ void ProcessRpcs()
RegisterRpcs();
}

private bool CheckAndProcessRpc(MethodDefinition md)
{
try
{
if (md.TryGetCustomAttribute<ServerRpcAttribute>(out CustomAttribute serverAttribute))
{
if (md.HasCustomAttribute<ClientRpcAttribute>()) throw new RpcException("Method should not have both ServerRpc and ClientRpc", md);

// todo make processRpc return the found Rpc instead of saving it to hidden list
serverRpcProcessor.ProcessRpc(md, serverAttribute);
return true;
}
else if (md.TryGetCustomAttribute<ClientRpcAttribute>(out CustomAttribute clientAttribute))
{
// todo make processRpc return the found Rpc instead of saving it to hidden list
clientRpcProcessor.ProcessRpc(md, clientAttribute);
return true;
}
}
catch (RpcException e)
{
logger.Error(e);
}

return false;
}

/// <summary>
/// Adds code to static Constructor
/// <para>
Expand Down

0 comments on commit dca6b54

Please sign in to comment.