RpcProcessor.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. using Mono.CecilX;
  2. using Mono.CecilX.Cil;
  3. namespace Mirror.Weaver
  4. {
  5. // Processes [Rpc] methods in NetworkBehaviour
  6. public static class RpcProcessor
  7. {
  8. public static MethodDefinition ProcessRpcInvoke(WeaverTypes weaverTypes, Writers writers, Readers readers, Logger Log, TypeDefinition td, MethodDefinition md, MethodDefinition rpcCallFunc, ref bool WeavingFailed)
  9. {
  10. MethodDefinition rpc = new MethodDefinition(
  11. Weaver.InvokeRpcPrefix + md.Name,
  12. MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig,
  13. weaverTypes.Import(typeof(void)));
  14. ILProcessor worker = rpc.Body.GetILProcessor();
  15. Instruction label = worker.Create(OpCodes.Nop);
  16. NetworkBehaviourProcessor.WriteClientActiveCheck(worker, weaverTypes, md.Name, label, "RPC");
  17. // setup for reader
  18. worker.Emit(OpCodes.Ldarg_0);
  19. worker.Emit(OpCodes.Castclass, td);
  20. if (!NetworkBehaviourProcessor.ReadArguments(md, readers, Log, worker, RemoteCallType.ClientRpc, ref WeavingFailed))
  21. return null;
  22. // invoke actual command function
  23. worker.Emit(OpCodes.Callvirt, rpcCallFunc);
  24. worker.Emit(OpCodes.Ret);
  25. NetworkBehaviourProcessor.AddInvokeParameters(weaverTypes, rpc.Parameters);
  26. td.Methods.Add(rpc);
  27. return rpc;
  28. }
  29. /*
  30. * generates code like:
  31. public void RpcTest (int param)
  32. {
  33. NetworkWriter writer = new NetworkWriter ();
  34. writer.WritePackedUInt32((uint)param);
  35. base.SendRPCInternal(typeof(class),"RpcTest", writer, 0);
  36. }
  37. public void CallRpcTest (int param)
  38. {
  39. // whatever the user did before
  40. }
  41. Originally HLAPI put the send message code inside the Call function
  42. and then proceeded to replace every call to RpcTest with CallRpcTest
  43. This method moves all the user's code into the "CallRpc" method
  44. and replaces the body of the original method with the send message code.
  45. This way we do not need to modify the code anywhere else, and this works
  46. correctly in dependent assemblies
  47. */
  48. public static MethodDefinition ProcessRpcCall(WeaverTypes weaverTypes, Writers writers, Logger Log, TypeDefinition td, MethodDefinition md, CustomAttribute clientRpcAttr, ref bool WeavingFailed)
  49. {
  50. MethodDefinition rpc = MethodProcessor.SubstituteMethod(Log, td, md, ref WeavingFailed);
  51. ILProcessor worker = md.Body.GetILProcessor();
  52. NetworkBehaviourProcessor.WriteSetupLocals(worker, weaverTypes);
  53. // add a log message if needed for debugging
  54. //worker.Emit(OpCodes.Ldstr, $"Call ClientRpc function {md.Name}");
  55. //worker.Emit(OpCodes.Call, WeaverTypes.logErrorReference);
  56. NetworkBehaviourProcessor.WriteCreateWriter(worker, weaverTypes);
  57. // write all the arguments that the user passed to the Rpc call
  58. if (!NetworkBehaviourProcessor.WriteArguments(worker, writers, Log, md, RemoteCallType.ClientRpc, ref WeavingFailed))
  59. return null;
  60. string rpcName = md.Name;
  61. int channel = clientRpcAttr.GetField("channel", 0);
  62. bool includeOwner = clientRpcAttr.GetField("includeOwner", true);
  63. // invoke SendInternal and return
  64. // this
  65. worker.Emit(OpCodes.Ldarg_0);
  66. worker.Emit(OpCodes.Ldtoken, td);
  67. // invokerClass
  68. worker.Emit(OpCodes.Call, weaverTypes.getTypeFromHandleReference);
  69. worker.Emit(OpCodes.Ldstr, rpcName);
  70. // writer
  71. worker.Emit(OpCodes.Ldloc_0);
  72. worker.Emit(OpCodes.Ldc_I4, channel);
  73. // includeOwner ? 1 : 0
  74. worker.Emit(includeOwner ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
  75. worker.Emit(OpCodes.Callvirt, weaverTypes.sendRpcInternal);
  76. NetworkBehaviourProcessor.WriteRecycleWriter(worker, weaverTypes);
  77. worker.Emit(OpCodes.Ret);
  78. return rpc;
  79. }
  80. }
  81. }