コード例 #1
0
        /*
         *  // generates code like:
         *  public void CmdThrust(float thrusting, int spin)
         *  {
         *      NetworkWriter networkWriter = new NetworkWriter();
         *      networkWriter.Write(thrusting);
         *      networkWriter.WritePackedUInt32((uint)spin);
         *      base.SendCommandInternal(cmdName, networkWriter, cmdName);
         *  }
         *
         *  public void CallCmdThrust(float thrusting, int spin)
         *  {
         *      // whatever the user was doing before
         *  }
         *
         *  Originally HLAPI put the send message code inside the Call function
         *  and then proceeded to replace every call to CmdTrust with CallCmdTrust
         *
         *  This method moves all the user's code into the "Call" method
         *  and replaces the body of the original method with the send message code.
         *  This way we do not need to modify the code anywhere else,  and this works
         *  correctly in dependent assemblies
         */
        public static MethodDefinition ProcessCommandCall(TypeDefinition td, MethodDefinition md, CustomAttribute ca)
        {
            MethodDefinition cmd = new MethodDefinition("Call" + md.Name,
                                                        MethodAttributes.Public | MethodAttributes.HideBySig,
                                                        Weaver.voidType);

            // add parameters
            foreach (ParameterDefinition pd in md.Parameters)
            {
                cmd.Parameters.Add(new ParameterDefinition(pd.Name, ParameterAttributes.None, pd.ParameterType));
            }

            // move the old body to the new function
            MethodBody newBody = cmd.Body;

            cmd.Body = md.Body;
            md.Body  = newBody;

            ILProcessor cmdWorker = md.Body.GetILProcessor();

            NetworkBehaviourProcessor.WriteSetupLocals(cmdWorker);

            if (Weaver.GenerateLogErrors)
            {
                cmdWorker.Append(cmdWorker.Create(OpCodes.Ldstr, "Call Command function " + md.Name));
                cmdWorker.Append(cmdWorker.Create(OpCodes.Call, Weaver.logErrorReference));
            }

            // NetworkWriter writer = new NetworkWriter();
            NetworkBehaviourProcessor.WriteCreateWriter(cmdWorker);

            // write all the arguments that the user passed to the Cmd call
            if (!NetworkBehaviourProcessor.WriteArguments(cmdWorker, md, false))
            {
                return(null);
            }

            string cmdName = md.Name;
            int    index   = cmdName.IndexOf(CmdPrefix);

            if (index > -1)
            {
                cmdName = cmdName.Substring(CmdPrefix.Length);
            }

            // invoke internal send and return
            cmdWorker.Append(cmdWorker.Create(OpCodes.Ldarg_0));                                 // load 'base.' to call the SendCommand function with
            cmdWorker.Append(cmdWorker.Create(OpCodes.Ldtoken, td));
            cmdWorker.Append(cmdWorker.Create(OpCodes.Call, Weaver.getTypeFromHandleReference)); // invokerClass
            cmdWorker.Append(cmdWorker.Create(OpCodes.Ldstr, cmdName));
            cmdWorker.Append(cmdWorker.Create(OpCodes.Ldloc_0));                                 // writer
            cmdWorker.Append(cmdWorker.Create(OpCodes.Ldc_I4, NetworkBehaviourProcessor.GetChannelId(ca)));
            cmdWorker.Append(cmdWorker.Create(OpCodes.Call, Weaver.sendCommandInternal));

            NetworkBehaviourProcessor.WriteRecycleWriter(cmdWorker);

            cmdWorker.Append(cmdWorker.Create(OpCodes.Ret));

            return(cmd);
        }
コード例 #2
0
ファイル: RpcProcessor.cs プロジェクト: skymeson/MirrorNG
        /// <summary>
        /// Replaces the user code with a stub.
        /// Moves the original code to a new method
        /// </summary>
        /// <param name="td">The class containing the method </param>
        /// <param name="md">The method to be stubbed </param>
        /// <param name="ServerRpcAttr">The attribute that made this an RPC</param>
        /// <returns>The method containing the original code</returns>
        /// <remarks>
        /// Generates code like this: (Observers case)
        /// <code>
        /// public void Test (int param)
        /// {
        ///     NetworkWriter writer = new NetworkWriter();
        ///     writer.WritePackedUInt32((uint) param);
        ///     base.SendRPCInternal(typeof(class),"RpcTest", writer, 0);
        /// }
        /// public void UserCode_Test(int param)
        /// {
        ///     // 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)
        {
            MethodDefinition rpc = MethodProcessor.SubstituteMethod(md);

            ILProcessor worker = md.Body.GetILProcessor();

            NetworkBehaviourProcessor.WriteSetupLocals(worker);

            NetworkBehaviourProcessor.WriteCreateWriter(worker);

            // write all the arguments that the user passed to the Rpc call
            if (!NetworkBehaviourProcessor.WriteArguments(worker, md, RemoteCallType.ClientRpc))
            {
                return(null);
            }

            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, WeaverTypes.getTypeFromHandleReference));
            worker.Append(worker.Create(OpCodes.Ldstr, rpcName));
            // writer
            worker.Append(worker.Create(OpCodes.Ldloc_0));
            worker.Append(worker.Create(OpCodes.Ldc_I4, channel));

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

            NetworkBehaviourProcessor.WriteRecycleWriter(worker);

            worker.Append(worker.Create(OpCodes.Ret));

            return(rpc);
        }
コード例 #3
0
        /* generates code like:
         * public void CallTargetTest (NetworkConnection conn, int param)
         * {
         *  NetworkWriter writer = new NetworkWriter ();
         *  writer.WritePackedUInt32 ((uint)param);
         *  base.SendTargetRPCInternal (conn, typeof(class), "TargetTest", val);
         * }
         *
         * or if optional:
         * public void CallTargetTest (int param)
         * {
         *  NetworkWriter writer = new NetworkWriter ();
         *  writer.WritePackedUInt32 ((uint)param);
         *  base.SendTargetRPCInternal (null, typeof(class), "TargetTest", val);
         * }
         */
        public static MethodDefinition ProcessTargetRpcCall(TypeDefinition td, MethodDefinition md, CustomAttribute ca)
        {
            MethodDefinition rpc = new MethodDefinition("Call" + md.Name, MethodAttributes.Public |
                                                        MethodAttributes.HideBySig,
                                                        Weaver.voidType);

            // add parameters
            foreach (ParameterDefinition pd in md.Parameters)
            {
                rpc.Parameters.Add(new ParameterDefinition(pd.Name, ParameterAttributes.None, pd.ParameterType));
            }

            ILProcessor rpcWorker = rpc.Body.GetILProcessor();

            NetworkBehaviourProcessor.WriteSetupLocals(rpcWorker);

            NetworkBehaviourProcessor.WriteCreateWriter(rpcWorker);

            // NetworkConnection parameter is optional
            bool hasNetworkConnection = HasNetworkConnectionParameter(md);

            // write all the arguments that the user passed to the TargetRpc call
            // (skip first one if first one is NetworkConnection)
            if (!NetworkBehaviourProcessor.WriteArguments(rpcWorker, md, hasNetworkConnection))
            {
                return(null);
            }

            string rpcName = md.Name;
            int    index   = rpcName.IndexOf(TargetRpcPrefix);

            if (index > -1)
            {
                rpcName = rpcName.Substring(TargetRpcPrefix.Length);
            }

            // invoke SendInternal and return
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldarg_0)); // this
            if (HasNetworkConnectionParameter(md))
            {
                rpcWorker.Append(rpcWorker.Create(OpCodes.Ldarg_1)); // connection
            }
            else
            {
                rpcWorker.Append(rpcWorker.Create(OpCodes.Ldnull)); // null
            }
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldtoken, td));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Call, Weaver.getTypeFromHandleReference)); // invokerClass
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldstr, rpcName));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldloc_0));                                 // writer
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldc_I4, NetworkBehaviourProcessor.GetChannelId(ca)));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Callvirt, Weaver.sendTargetRpcInternal));

            NetworkBehaviourProcessor.WriteRecycleWriter(rpcWorker);

            rpcWorker.Append(rpcWorker.Create(OpCodes.Ret));

            return(rpc);
        }
コード例 #4
0
        /* generates code like:
         *  public void TargetTest (NetworkConnection conn, int param)
         *  {
         *      NetworkWriter writer = new NetworkWriter ();
         *      writer.WritePackedUInt32 ((uint)param);
         *      base.SendTargetRPCInternal (conn, typeof(class), "TargetTest", val);
         *  }
         *  public void CallTargetTest (NetworkConnection conn, int param)
         *  {
         *      // whatever the user did before
         *  }
         *
         *  or if optional:
         *  public void TargetTest (int param)
         *  {
         *      NetworkWriter writer = new NetworkWriter ();
         *      writer.WritePackedUInt32 ((uint)param);
         *      base.SendTargetRPCInternal (null, typeof(class), "TargetTest", val);
         *  }
         *  public void CallTargetTest (int param)
         *  {
         *      // whatever the user did before
         *  }
         *
         *  Originally HLAPI put the send message code inside the Call function
         *  and then proceeded to replace every call to TargetTest with CallTargetTest
         *
         *  This method moves all the user's code into the "Call" method
         *  and replaces the body of the original method with the send message code.
         *  This way we do not need to modify the code anywhere else,  and this works
         *  correctly in dependent assemblies
         *
         */
        public static MethodDefinition ProcessTargetRpcCall(TypeDefinition td, MethodDefinition md, CustomAttribute ca)
        {
            MethodDefinition rpc = MethodProcessor.SubstituteMethod(td, md, "Call" + md.Name);

            ILProcessor rpcWorker = md.Body.GetILProcessor();

            NetworkBehaviourProcessor.WriteSetupLocals(rpcWorker);

            NetworkBehaviourProcessor.WriteCreateWriter(rpcWorker);

            // NetworkConnection parameter is optional
            bool hasNetworkConnection = HasNetworkConnectionParameter(md);

            // write all the arguments that the user passed to the TargetRpc call
            // (skip first one if first one is NetworkConnection)
            if (!NetworkBehaviourProcessor.WriteArguments(rpcWorker, md, hasNetworkConnection))
            {
                return(null);
            }

            string rpcName = md.Name;
            int    index   = rpcName.IndexOf(TargetRpcPrefix);

            if (index > -1)
            {
                rpcName = rpcName.Substring(TargetRpcPrefix.Length);
            }

            // invoke SendInternal and return
            // this
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldarg_0));
            if (hasNetworkConnection)
            {
                // connection
                rpcWorker.Append(rpcWorker.Create(OpCodes.Ldarg_1));
            }
            else
            {
                // null
                rpcWorker.Append(rpcWorker.Create(OpCodes.Ldnull));
            }
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldtoken, td));
            // invokerClass
            rpcWorker.Append(rpcWorker.Create(OpCodes.Call, Weaver.getTypeFromHandleReference));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldstr, rpcName));
            // writer
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldloc_0));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldc_I4, ca.GetField("channel", 0)));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Callvirt, Weaver.sendTargetRpcInternal));

            NetworkBehaviourProcessor.WriteRecycleWriter(rpcWorker);

            rpcWorker.Append(rpcWorker.Create(OpCodes.Ret));

            return(rpc);
        }
コード例 #5
0
ファイル: CommandProcessor.cs プロジェクト: omeryuksel/Mirror
        /*
         *  // generates code like:
         *  public void CmdThrust(float thrusting, int spin)
         *  {
         *      NetworkWriter networkWriter = new NetworkWriter();
         *      networkWriter.Write(thrusting);
         *      networkWriter.WritePackedUInt32((uint)spin);
         *      base.SendCommandInternal(cmdName, networkWriter, cmdName);
         *  }
         *
         *  public void CallCmdThrust(float thrusting, int spin)
         *  {
         *      // whatever the user was doing before
         *  }
         *
         *  Originally HLAPI put the send message code inside the Call function
         *  and then proceeded to replace every call to CmdTrust with CallCmdTrust
         *
         *  This method moves all the user's code into the "Call" method
         *  and replaces the body of the original method with the send message code.
         *  This way we do not need to modify the code anywhere else,  and this works
         *  correctly in dependent assemblies
         */
        public static MethodDefinition ProcessCommandCall(TypeDefinition td, MethodDefinition md, CustomAttribute commandAttr)
        {
            MethodDefinition cmd = MethodProcessor.SubstituteMethod(td, md, "Call" + md.Name);

            ILProcessor worker = md.Body.GetILProcessor();

            NetworkBehaviourProcessor.WriteSetupLocals(worker);

            if (Weaver.GenerateLogErrors)
            {
                worker.Append(worker.Create(OpCodes.Ldstr, "Call Command function " + md.Name));
                worker.Append(worker.Create(OpCodes.Call, Weaver.logErrorReference));
            }

            // NetworkWriter writer = new NetworkWriter();
            NetworkBehaviourProcessor.WriteCreateWriter(worker);

            // write all the arguments that the user passed to the Cmd call
            if (!NetworkBehaviourProcessor.WriteArguments(worker, md, false))
            {
                return(null);
            }

            string cmdName = md.Name;
            int    index   = cmdName.IndexOf(CmdPrefix);

            if (index > -1)
            {
                cmdName = cmdName.Substring(CmdPrefix.Length);
            }

            int  channel         = commandAttr.GetField("channel", 0);
            bool ignoreAuthority = commandAttr.GetField("ignoreAuthority", false);


            // invoke internal send and return
            // load 'base.' to call the SendCommand function with
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Ldtoken, td));
            // invokerClass
            worker.Append(worker.Create(OpCodes.Call, Weaver.getTypeFromHandleReference));
            worker.Append(worker.Create(OpCodes.Ldstr, cmdName));
            // writer
            worker.Append(worker.Create(OpCodes.Ldloc_0));
            worker.Append(worker.Create(OpCodes.Ldc_I4, channel));
            worker.Append(worker.Create(ignoreAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0));
            worker.Append(worker.Create(OpCodes.Call, Weaver.sendCommandInternal));

            NetworkBehaviourProcessor.WriteRecycleWriter(worker);

            worker.Append(worker.Create(OpCodes.Ret));

            return(cmd);
        }
コード例 #6
0
        /*
         * generates code like:
         *
         *  public void RpcTest (int param)
         *  {
         *      NetworkWriter writer = new NetworkWriter ();
         *      writer.WritePackedUInt32((uint)param);
         *      base.SendRPCInternal(typeof(class),"RpcTest", writer, 0);
         *  }
         *  public void CallRpcTest (int param)
         *  {
         *      // whatever the user did before
         *  }
         *
         *  Originally HLAPI put the send message code inside the Call function
         *  and then proceeded to replace every call to RpcTest with CallRpcTest
         *
         *  This method moves all the user's code into the "Call" method
         *  and replaces the body of the original method with the send message code.
         *  This way we do not need to modify the code anywhere else,  and this works
         *  correctly in dependent assemblies
         */
        public static MethodDefinition ProcessRpcCall(TypeDefinition td, MethodDefinition md, CustomAttribute ca)
        {
            MethodDefinition rpc = new MethodDefinition("Call" + md.Name, MethodAttributes.Public |
                                                        MethodAttributes.HideBySig,
                                                        Weaver.voidType);

            // add paramters
            foreach (ParameterDefinition pd in md.Parameters)
            {
                rpc.Parameters.Add(new ParameterDefinition(pd.Name, ParameterAttributes.None, pd.ParameterType));
            }

            // move the old body to the new function
            MethodBody newBody = rpc.Body;

            rpc.Body = md.Body;
            md.Body  = newBody;

            ILProcessor rpcWorker = md.Body.GetILProcessor();

            NetworkBehaviourProcessor.WriteSetupLocals(rpcWorker);

            NetworkBehaviourProcessor.WriteCreateWriter(rpcWorker);

            // write all the arguments that the user passed to the Rpc call
            if (!NetworkBehaviourProcessor.WriteArguments(rpcWorker, md, false))
            {
                return(null);
            }

            string rpcName = md.Name;
            int    index   = rpcName.IndexOf(RpcPrefix);

            if (index > -1)
            {
                rpcName = rpcName.Substring(RpcPrefix.Length);
            }

            // invoke SendInternal and return
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldarg_0));                                 // this
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldtoken, td));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Call, Weaver.getTypeFromHandleReference)); // invokerClass
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldstr, rpcName));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldloc_0));                                 // writer
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldc_I4, NetworkBehaviourProcessor.GetChannelId(ca)));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Callvirt, Weaver.sendRpcInternal));

            NetworkBehaviourProcessor.WriteRecycleWriter(rpcWorker);

            rpcWorker.Append(rpcWorker.Create(OpCodes.Ret));

            return(rpc);
        }
コード例 #7
0
        /*
         * generates code like:
         *
         *  public void RpcTest (int param)
         *  {
         *      NetworkWriter writer = new NetworkWriter ();
         *      writer.WritePackedUInt32((uint)param);
         *      base.SendRPCInternal(typeof(class),"RpcTest", writer, 0);
         *  }
         *  public void CallRpcTest (int param)
         *  {
         *      // whatever the user did before
         *  }
         *
         *  Originally HLAPI put the send message code inside the Call function
         *  and then proceeded to replace every call to RpcTest with CallRpcTest
         *
         *  This method moves all the user's code into the "Call" method
         *  and replaces the body of the original method with the send message code.
         *  This way we do not need to modify the code anywhere else,  and this works
         *  correctly in dependent assemblies
         */
        public static MethodDefinition ProcessRpcCall(TypeDefinition td, MethodDefinition md, CustomAttribute clientRpcAttr)
        {
            MethodDefinition rpc = MethodProcessor.SubstituteMethod(td, md, "Call" + md.Name);

            ILProcessor worker = md.Body.GetILProcessor();

            NetworkBehaviourProcessor.WriteSetupLocals(worker);

            if (Weaver.GenerateLogErrors)
            {
                worker.Append(worker.Create(OpCodes.Ldstr, "Call ClientRpc function " + md.Name));
                worker.Append(worker.Create(OpCodes.Call, Weaver.logErrorReference));
            }

            NetworkBehaviourProcessor.WriteCreateWriter(worker);

            // write all the arguments that the user passed to the Rpc call
            if (!NetworkBehaviourProcessor.WriteArguments(worker, md, RemoteCallType.ClientRpc))
            {
                return(null);
            }

            string rpcName = md.Name;
            int    index   = rpcName.IndexOf(RpcPrefix);

            if (index > -1)
            {
                rpcName = rpcName.Substring(RpcPrefix.Length);
            }

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

            // invoke SendInternal and return
            // this
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Ldtoken, td));
            // 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));

            NetworkBehaviourProcessor.WriteRecycleWriter(worker);

            worker.Append(worker.Create(OpCodes.Ret));

            return(rpc);
        }
コード例 #8
0
        /* generates code like:
         *  public void TargetTest (NetworkConnection conn, int param)
         *  {
         *      NetworkWriter writer = new NetworkWriter ();
         *      writer.WritePackedUInt32 ((uint)param);
         *      base.SendTargetRPCInternal (conn, typeof(class), "TargetTest", val);
         *  }
         *  public void CallTargetTest (NetworkConnection conn, int param)
         *  {
         *      // whatever the user did before
         *  }
         *
         *  or if optional:
         *  public void TargetTest (int param)
         *  {
         *      NetworkWriter writer = new NetworkWriter ();
         *      writer.WritePackedUInt32 ((uint)param);
         *      base.SendTargetRPCInternal (null, typeof(class), "TargetTest", val);
         *  }
         *  public void CallTargetTest (int param)
         *  {
         *      // whatever the user did before
         *  }
         *
         *  Originally HLAPI put the send message code inside the Call function
         *  and then proceeded to replace every call to TargetTest with CallTargetTest
         *
         *  This method moves all the user's code into the "CallTargetRpc" method
         *  and replaces the body of the original method with the send message code.
         *  This way we do not need to modify the code anywhere else,  and this works
         *  correctly in dependent assemblies
         *
         */
        public static MethodDefinition ProcessTargetRpcCall(TypeDefinition td, MethodDefinition md, CustomAttribute targetRpcAttr)
        {
            MethodDefinition rpc = MethodProcessor.SubstituteMethod(td, md);

            ILProcessor worker = md.Body.GetILProcessor();

            NetworkBehaviourProcessor.WriteSetupLocals(worker);

            NetworkBehaviourProcessor.WriteCreateWriter(worker);

            // write all the arguments that the user passed to the TargetRpc call
            // (skip first one if first one is NetworkConnection)
            if (!NetworkBehaviourProcessor.WriteArguments(worker, md, RemoteCallType.TargetRpc))
            {
                return(null);
            }

            string rpcName = md.Name;

            // invoke SendInternal and return
            // this
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            if (HasNetworkConnectionParameter(md))
            {
                // connection
                worker.Append(worker.Create(OpCodes.Ldarg_1));
            }
            else
            {
                // null
                worker.Append(worker.Create(OpCodes.Ldnull));
            }
            worker.Append(worker.Create(OpCodes.Ldtoken, td));
            // invokerClass
            worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getTypeFromHandleReference));
            worker.Append(worker.Create(OpCodes.Ldstr, rpcName));
            // writer
            worker.Append(worker.Create(OpCodes.Ldloc_0));
            worker.Append(worker.Create(OpCodes.Ldc_I4, targetRpcAttr.GetField("channel", 0)));
            worker.Append(worker.Create(OpCodes.Callvirt, WeaverTypes.sendTargetRpcInternal));

            NetworkBehaviourProcessor.WriteRecycleWriter(worker);

            worker.Append(worker.Create(OpCodes.Ret));

            return(rpc);
        }
コード例 #9
0
        public static MethodDefinition ProcessEventCall(TypeDefinition td, EventDefinition ed, CustomAttribute syncEventAttr)
        {
            MethodReference  invoke = Resolvers.ResolveMethod(ed.EventType, Weaver.CurrentAssembly, "Invoke");
            MethodDefinition evt    = new MethodDefinition("Call" + ed.Name, MethodAttributes.Public |
                                                           MethodAttributes.HideBySig,
                                                           Weaver.voidType);

            // add paramters
            foreach (ParameterDefinition pd in invoke.Parameters)
            {
                evt.Parameters.Add(new ParameterDefinition(pd.Name, ParameterAttributes.None, pd.ParameterType));
            }

            ILProcessor evtWorker = evt.Body.GetILProcessor();
            Instruction label     = evtWorker.Create(OpCodes.Nop);

            NetworkBehaviourProcessor.WriteSetupLocals(evtWorker);

            NetworkBehaviourProcessor.WriteServerActiveCheck(evtWorker, ed.Name, label, "Event");

            NetworkBehaviourProcessor.WriteCreateWriter(evtWorker);

            // write all the arguments that the user passed to the syncevent
            if (!NetworkBehaviourProcessor.WriteArguments(evtWorker, invoke.Resolve(), false))
            {
                return(null);
            }

            // invoke interal send and return
            // this
            evtWorker.Append(evtWorker.Create(OpCodes.Ldarg_0));
            evtWorker.Append(evtWorker.Create(OpCodes.Ldtoken, td));
            // invokerClass
            evtWorker.Append(evtWorker.Create(OpCodes.Call, Weaver.getTypeFromHandleReference));
            evtWorker.Append(evtWorker.Create(OpCodes.Ldstr, ed.Name));
            // writer
            evtWorker.Append(evtWorker.Create(OpCodes.Ldloc_0));
            evtWorker.Append(evtWorker.Create(OpCodes.Ldc_I4, syncEventAttr.GetField("channel", 0)));
            evtWorker.Append(evtWorker.Create(OpCodes.Call, Weaver.sendEventInternal));

            NetworkBehaviourProcessor.WriteRecycleWriter(evtWorker);

            evtWorker.Append(evtWorker.Create(OpCodes.Ret));

            return(evt);
        }
コード例 #10
0
        /*
         * generates code like:
         *
         *  public void RpcTest (int param)
         *  {
         *      NetworkWriter writer = new NetworkWriter ();
         *      writer.WritePackedUInt32((uint)param);
         *      base.SendRPCInternal(typeof(class),"RpcTest", writer, 0);
         *  }
         *  public void CallRpcTest (int param)
         *  {
         *      // whatever the user did before
         *  }
         *
         *  Originally HLAPI put the send message code inside the Call function
         *  and then proceeded to replace every call to RpcTest with CallRpcTest
         *
         *  This method moves all the user's code into the "CallRpc" method
         *  and replaces the body of the original method with the send message code.
         *  This way we do not need to modify the code anywhere else,  and this works
         *  correctly in dependent assemblies
         */
        public static MethodDefinition ProcessRpcCall(WeaverTypes weaverTypes, Writers writers, Logger Log, TypeDefinition td, MethodDefinition md, CustomAttribute clientRpcAttr, ref bool WeavingFailed)
        {
            MethodDefinition rpc = MethodProcessor.SubstituteMethod(Log, td, md, ref WeavingFailed);

            ILProcessor worker = md.Body.GetILProcessor();

            NetworkBehaviourProcessor.WriteSetupLocals(worker, weaverTypes);

            // add a log message if needed for debugging
            //worker.Emit(OpCodes.Ldstr, "Call ClientRpc function " + md.Name);
            //worker.Emit(OpCodes.Call, WeaverTypes.logErrorReference);

            NetworkBehaviourProcessor.WriteCreateWriter(worker, weaverTypes);

            // write all the arguments that the user passed to the Rpc call
            if (!NetworkBehaviourProcessor.WriteArguments(worker, writers, Log, md, RemoteCallType.ClientRpc, ref WeavingFailed))
            {
                return(null);
            }

            string rpcName      = md.Name;
            int    channel      = clientRpcAttr.GetField("channel", 0);
            bool   includeOwner = clientRpcAttr.GetField("includeOwner", true);

            // invoke SendInternal and return
            // this
            worker.Emit(OpCodes.Ldarg_0);
            worker.Emit(OpCodes.Ldtoken, td);
            // invokerClass
            worker.Emit(OpCodes.Call, weaverTypes.getTypeFromHandleReference);
            worker.Emit(OpCodes.Ldstr, rpcName);
            // writer
            worker.Emit(OpCodes.Ldloc_0);
            worker.Emit(OpCodes.Ldc_I4, channel);
            // includeOwner ? 1 : 0
            worker.Emit(includeOwner ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
            worker.Emit(OpCodes.Callvirt, weaverTypes.sendRpcInternal);

            NetworkBehaviourProcessor.WriteRecycleWriter(worker, weaverTypes);

            worker.Emit(OpCodes.Ret);

            return(rpc);
        }
コード例 #11
0
        /* generates code like:
         *  public void TargetTest (NetworkConnection conn, int param)
         *  {
         *      NetworkWriter writer = new NetworkWriter ();
         *      writer.WritePackedUInt32 ((uint)param);
         *      base.SendTargetRPCInternal (conn, typeof(class), "TargetTest", val);
         *  }
         *  public void CallTargetTest (NetworkConnection conn, int param)
         *  {
         *      // whatever the user did before
         *  }
         *
         *  or if optional:
         *  public void TargetTest (int param)
         *  {
         *      NetworkWriter writer = new NetworkWriter ();
         *      writer.WritePackedUInt32 ((uint)param);
         *      base.SendTargetRPCInternal (null, typeof(class), "TargetTest", val);
         *  }
         *  public void CallTargetTest (int param)
         *  {
         *      // whatever the user did before
         *  }
         *
         *  Originally HLAPI put the send message code inside the Call function
         *  and then proceeded to replace every call to TargetTest with CallTargetTest
         *
         *  This method moves all the user's code into the "CallTargetRpc" method
         *  and replaces the body of the original method with the send message code.
         *  This way we do not need to modify the code anywhere else,  and this works
         *  correctly in dependent assemblies
         *
         */
        public static MethodDefinition ProcessTargetRpcCall(WeaverTypes weaverTypes, Writers writers, Logger Log, TypeDefinition td, MethodDefinition md, CustomAttribute targetRpcAttr, ref bool WeavingFailed)
        {
            MethodDefinition rpc = MethodProcessor.SubstituteMethod(Log, td, md, ref WeavingFailed);

            ILProcessor worker = md.Body.GetILProcessor();

            NetworkBehaviourProcessor.WriteSetupLocals(worker, weaverTypes);

            NetworkBehaviourProcessor.WriteCreateWriter(worker, weaverTypes);

            // write all the arguments that the user passed to the TargetRpc call
            // (skip first one if first one is NetworkConnection)
            if (!NetworkBehaviourProcessor.WriteArguments(worker, writers, Log, md, RemoteCallType.TargetRpc, ref WeavingFailed))
            {
                return(null);
            }

            // invoke SendInternal and return
            // this
            worker.Emit(OpCodes.Ldarg_0);
            if (HasNetworkConnectionParameter(md))
            {
                // connection
                worker.Emit(OpCodes.Ldarg_1);
            }
            else
            {
                // null
                worker.Emit(OpCodes.Ldnull);
            }
            // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions
            worker.Emit(OpCodes.Ldstr, md.FullName);
            // writer
            worker.Emit(OpCodes.Ldloc_0);
            worker.Emit(OpCodes.Ldc_I4, targetRpcAttr.GetField("channel", 0));
            worker.Emit(OpCodes.Callvirt, weaverTypes.sendTargetRpcInternal);

            NetworkBehaviourProcessor.WriteRecycleWriter(worker, weaverTypes);

            worker.Emit(OpCodes.Ret);

            return(rpc);
        }
コード例 #12
0
        /*
         * generates code like:
         *
         *  public void RpcTest (int param)
         *  {
         *      NetworkWriter writer = new NetworkWriter ();
         *      writer.WritePackedUInt32((uint)param);
         *      base.SendRPCInternal(typeof(class),"RpcTest", writer, 0);
         *  }
         *  public void CallRpcTest (int param)
         *  {
         *      // whatever the user did before
         *  }
         *
         *  Originally HLAPI put the send message code inside the Call function
         *  and then proceeded to replace every call to RpcTest with CallRpcTest
         *
         *  This method moves all the user's code into the "Call" method
         *  and replaces the body of the original method with the send message code.
         *  This way we do not need to modify the code anywhere else,  and this works
         *  correctly in dependent assemblies
         */
        public static MethodDefinition ProcessRpcCall(TypeDefinition td, MethodDefinition md, CustomAttribute ca)
        {
            MethodDefinition rpc = MethodProcessor.SubstituteMethod(md, "Call" + md.Name);

            ILProcessor rpcWorker = md.Body.GetILProcessor();

            NetworkBehaviourProcessor.WriteSetupLocals(rpcWorker);

            NetworkBehaviourProcessor.WriteCreateWriter(rpcWorker);

            // write all the arguments that the user passed to the Rpc call
            if (!NetworkBehaviourProcessor.WriteArguments(rpcWorker, md, false))
            {
                return(null);
            }

            string rpcName = md.Name;
            int    index   = rpcName.IndexOf(RpcPrefix);

            if (index > -1)
            {
                rpcName = rpcName.Substring(RpcPrefix.Length);
            }

            // invoke SendInternal and return
            // this
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldarg_0));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldtoken, td));
            // invokerClass
            rpcWorker.Append(rpcWorker.Create(OpCodes.Call, Weaver.getTypeFromHandleReference));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldstr, rpcName));
            // writer
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldloc_0));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldc_I4, NetworkBehaviourProcessor.GetChannelId(ca)));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Callvirt, Weaver.sendRpcInternal));

            NetworkBehaviourProcessor.WriteRecycleWriter(rpcWorker);

            rpcWorker.Append(rpcWorker.Create(OpCodes.Ret));

            return(rpc);
        }
コード例 #13
0
        /// <summary>
        /// Replaces the user code with a stub.
        /// Moves the original code to a new method
        /// </summary>
        /// <param name="td">The class containing the method </param>
        /// <param name="md">The method to be stubbed </param>
        /// <param name="ServerRpcAttr">The attribute that made this an RPC</param>
        /// <returns>The method containing the original code</returns>
        /// <remarks>
        /// Generates code like this:
        /// <code>
        /// public void MyServerRpc(float thrusting, int spin)
        /// {
        ///     NetworkWriter networkWriter = new NetworkWriter();
        ///     networkWriter.Write(thrusting);
        ///     networkWriter.WritePackedUInt32((uint) spin);
        ///     base.SendServerRpcInternal(cmdName, networkWriter, cmdName);
        /// }
        ///
        /// public void UserCode_MyServerRpc(float thrusting, int spin)
        /// {
        ///     // whatever the user was doing before
        ///
        /// }
        /// </code>
        /// </remarks>
        public static MethodDefinition GenerateStub(MethodDefinition md, CustomAttribute serverRpcAttr)
        {
            MethodDefinition cmd = MethodProcessor.SubstituteMethod(md);

            ILProcessor worker = md.Body.GetILProcessor();

            NetworkBehaviourProcessor.WriteSetupLocals(worker);

            // NetworkWriter writer = new NetworkWriter();
            NetworkBehaviourProcessor.WriteCreateWriter(worker);

            // write all the arguments that the user passed to the Cmd call
            if (!NetworkBehaviourProcessor.WriteArguments(worker, md, RemoteCallType.ServerRpc))
            {
                return(null);
            }

            string cmdName = md.Name;

            int  channel          = serverRpcAttr.GetField("channel", 0);
            bool requireAuthority = serverRpcAttr.GetField("requireAuthority", true);


            // invoke internal send and return
            // load 'base.' to call the SendServerRpc function with
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Ldtoken, md.DeclaringType));
            // invokerClass
            worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getTypeFromHandleReference));
            worker.Append(worker.Create(OpCodes.Ldstr, cmdName));
            // writer
            worker.Append(worker.Create(OpCodes.Ldloc_0));
            worker.Append(worker.Create(OpCodes.Ldc_I4, channel));
            worker.Append(worker.Create(requireAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0));
            worker.Append(worker.Create(OpCodes.Call, WeaverTypes.sendServerRpcInternal));

            NetworkBehaviourProcessor.WriteRecycleWriter(worker);

            worker.Append(worker.Create(OpCodes.Ret));

            return(cmd);
        }
コード例 #14
0
        /*
         *  // generates code like:
         *  public void CmdThrust(float thrusting, int spin)
         *  {
         *      NetworkWriter networkWriter = new NetworkWriter();
         *      networkWriter.Write(thrusting);
         *      networkWriter.WritePackedUInt32((uint)spin);
         *      base.SendCommandInternal(cmdName, networkWriter, cmdName);
         *  }
         *
         *  public void CallCmdThrust(float thrusting, int spin)
         *  {
         *      // whatever the user was doing before
         *  }
         *
         *  Originally HLAPI put the send message code inside the Call function
         *  and then proceeded to replace every call to CmdTrust with CallCmdTrust
         *
         *  This method moves all the user's code into the "CallCmd" method
         *  and replaces the body of the original method with the send message code.
         *  This way we do not need to modify the code anywhere else,  and this works
         *  correctly in dependent assemblies
         */
        public static MethodDefinition ProcessCommandCall(WeaverTypes weaverTypes, Writers writers, Logger Log, TypeDefinition td, MethodDefinition md, CustomAttribute commandAttr, ref bool WeavingFailed)
        {
            MethodDefinition cmd = MethodProcessor.SubstituteMethod(Log, td, md, ref WeavingFailed);

            ILProcessor worker = md.Body.GetILProcessor();

            NetworkBehaviourProcessor.WriteSetupLocals(worker, weaverTypes);

            // NetworkWriter writer = new NetworkWriter();
            NetworkBehaviourProcessor.WriteCreateWriter(worker, weaverTypes);

            // write all the arguments that the user passed to the Cmd call
            if (!NetworkBehaviourProcessor.WriteArguments(worker, writers, Log, md, RemoteCallType.Command, ref WeavingFailed))
            {
                return(null);
            }

            string cmdName           = md.Name;
            int    channel           = commandAttr.GetField("channel", 0);
            bool   requiresAuthority = commandAttr.GetField("requiresAuthority", true);

            // invoke internal send and return
            // load 'base.' to call the SendCommand function with
            worker.Emit(OpCodes.Ldarg_0);
            worker.Emit(OpCodes.Ldtoken, td);
            // invokerClass
            worker.Emit(OpCodes.Call, weaverTypes.getTypeFromHandleReference);
            worker.Emit(OpCodes.Ldstr, cmdName);
            // writer
            worker.Emit(OpCodes.Ldloc_0);
            worker.Emit(OpCodes.Ldc_I4, channel);
            // requiresAuthority ? 1 : 0
            worker.Emit(requiresAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
            worker.Emit(OpCodes.Call, weaverTypes.sendCommandInternal);

            NetworkBehaviourProcessor.WriteRecycleWriter(worker, weaverTypes);

            worker.Emit(OpCodes.Ret);
            return(cmd);
        }
コード例 #15
0
ファイル: CommandProcessor.cs プロジェクト: noerror/Mirror
        /*
            // generates code like:
            public void CmdThrust(float thrusting, int spin)
            {
                NetworkWriter networkWriter = new NetworkWriter();
                networkWriter.Write(thrusting);
                networkWriter.WritePackedUInt32((uint)spin);
                base.SendCommandInternal(cmdName, networkWriter, cmdName);
            }

            public void CallCmdThrust(float thrusting, int spin)
            {
                // whatever the user was doing before
            }

            Originally HLAPI put the send message code inside the Call function
            and then proceeded to replace every call to CmdTrust with CallCmdTrust

            This method moves all the user's code into the "CallCmd" method
            and replaces the body of the original method with the send message code.
            This way we do not need to modify the code anywhere else,  and this works
            correctly in dependent assemblies
        */
        public static MethodDefinition ProcessCommandCall(TypeDefinition td, MethodDefinition md, CustomAttribute commandAttr)
        {
            MethodDefinition cmd = MethodProcessor.SubstituteMethod(td, md);

            ILProcessor worker = md.Body.GetILProcessor();

            NetworkBehaviourProcessor.WriteSetupLocals(worker);

            // NetworkWriter writer = new NetworkWriter();
            NetworkBehaviourProcessor.WriteCreateWriter(worker);

            // write all the arguments that the user passed to the Cmd call
            if (!NetworkBehaviourProcessor.WriteArguments(worker, md, RemoteCallType.Command))
                return null;

            string cmdName = md.Name;
            int channel = commandAttr.GetField("channel", 0);
            bool ignoreAuthority = commandAttr.GetField("ignoreAuthority", false);

            // invoke internal send and return
            // load 'base.' to call the SendCommand function with
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Ldtoken, td));
            // invokerClass
            worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getTypeFromHandleReference));
            worker.Append(worker.Create(OpCodes.Ldstr, cmdName));
            // writer
            worker.Append(worker.Create(OpCodes.Ldloc_0));
            worker.Append(worker.Create(OpCodes.Ldc_I4, channel));
            worker.Append(worker.Create(ignoreAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0));
            worker.Append(worker.Create(OpCodes.Call, WeaverTypes.sendCommandInternal));

            NetworkBehaviourProcessor.WriteRecycleWriter(worker);

            worker.Append(worker.Create(OpCodes.Ret));

            return cmd;
        }
コード例 #16
0
        /* generates code like:
         * public void CallTargetTest (NetworkConnection conn, int param)
         * {
         *  if (!NetworkServer.get_active ()) {
         *      Debug.LogError((object)"TargetRPC Function TargetTest called on client.");
         *  } else if (((?)conn) is ULocalConnectionToServer) {
         *      Debug.LogError((object)"TargetRPC Function TargetTest called on connection to server");
         *  } else {
         *      NetworkWriter writer = new NetworkWriter ();
         *      writer.WritePackedUInt32 ((uint)param);
         *      base.SendTargetRPCInternal (conn, typeof(class), "TargetTest", val);
         *  }
         * }
         */
        public static MethodDefinition ProcessTargetRpcCall(TypeDefinition td, MethodDefinition md, CustomAttribute ca)
        {
            MethodDefinition rpc = new MethodDefinition("Call" + md.Name, MethodAttributes.Public |
                                                        MethodAttributes.HideBySig,
                                                        Weaver.voidType);

            // add paramters
            foreach (ParameterDefinition pd in md.Parameters)
            {
                rpc.Parameters.Add(new ParameterDefinition(pd.Name, ParameterAttributes.None, pd.ParameterType));
            }

            ILProcessor rpcWorker = rpc.Body.GetILProcessor();
            Instruction label     = rpcWorker.Create(OpCodes.Nop);

            NetworkBehaviourProcessor.WriteSetupLocals(rpcWorker);

            NetworkBehaviourProcessor.WriteServerActiveCheck(rpcWorker, md.Name, label, "TargetRPC Function");

            Instruction labelConnectionCheck = rpcWorker.Create(OpCodes.Nop);

            // check specifically for ULocalConnectionToServer so a host is not trying to send
            // an TargetRPC to the "server" from it's local client.
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldarg_1));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Isinst, Weaver.ULocalConnectionToServerType));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Brfalse, labelConnectionCheck));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldstr, string.Format("TargetRPC Function {0} called on connection to server", md.Name)));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Call, Weaver.logErrorReference));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ret));
            rpcWorker.Append(labelConnectionCheck);

            NetworkBehaviourProcessor.WriteCreateWriter(rpcWorker);

            // write all the arguments that the user passed to the TargetRpc call
            if (!NetworkBehaviourProcessor.WriteArguments(rpcWorker, md, "TargetRPC", true))
            {
                return(null);
            }

            var rpcName = md.Name;
            int index   = rpcName.IndexOf(k_TargetRpcPrefix);

            if (index > -1)
            {
                rpcName = rpcName.Substring(k_TargetRpcPrefix.Length);
            }

            // invoke SendInternal and return
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldarg_0));                                 // this
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldarg_1));                                 // connection
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldtoken, td));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Call, Weaver.getTypeFromHandleReference)); // invokerClass
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldstr, rpcName));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldloc_0));                                 // writer
            rpcWorker.Append(rpcWorker.Create(OpCodes.Ldc_I4, NetworkBehaviourProcessor.GetChannelId(ca)));
            rpcWorker.Append(rpcWorker.Create(OpCodes.Callvirt, Weaver.sendTargetRpcInternal));

            rpcWorker.Append(rpcWorker.Create(OpCodes.Ret));

            return(rpc);
        }
コード例 #17
0
ファイル: CommandProcessor.cs プロジェクト: Lagunovas/Mirror
        /*
         *  // generates code like:
         *  public void CallCmdThrust(float thrusting, int spin)
         *  {
         *      Debug.LogError("Call Command function CmdThrust");
         *      if (!NetworkClient.active)
         *      {
         *          Debug.LogError("Command function CmdThrust called on server.");
         *          return;
         *      }
         *
         *      if (isServer)
         *      {
         *          // we are ON the server, invoke directly
         *          CmdThrust(thrusting, spin);
         *          return;
         *      }
         *
         *      NetworkWriter networkWriter = new NetworkWriter();
         *      networkWriter.Write(thrusting);
         *      networkWriter.WritePackedUInt32((uint)spin);
         *      base.SendCommandInternal(cmdName, networkWriter, cmdName);
         *  }
         */
        public static MethodDefinition ProcessCommandCall(TypeDefinition td, MethodDefinition md, CustomAttribute ca)
        {
            MethodDefinition cmd = new MethodDefinition("Call" + md.Name, MethodAttributes.Public |
                                                        MethodAttributes.HideBySig,
                                                        Weaver.voidType);

            // add paramters
            foreach (ParameterDefinition pd in md.Parameters)
            {
                cmd.Parameters.Add(new ParameterDefinition(pd.Name, ParameterAttributes.None, pd.ParameterType));
            }

            ILProcessor cmdWorker = cmd.Body.GetILProcessor();
            Instruction label     = cmdWorker.Create(OpCodes.Nop);

            NetworkBehaviourProcessor.WriteSetupLocals(cmdWorker);

            if (Weaver.generateLogErrors)
            {
                cmdWorker.Append(cmdWorker.Create(OpCodes.Ldstr, "Call Command function " + md.Name));
                cmdWorker.Append(cmdWorker.Create(OpCodes.Call, Weaver.logErrorReference));
            }

            NetworkBehaviourProcessor.WriteClientActiveCheck(cmdWorker, md.Name, label, "Command function");

            // local client check
            Instruction localClientLabel = cmdWorker.Create(OpCodes.Nop);

            cmdWorker.Append(cmdWorker.Create(OpCodes.Ldarg_0));
            cmdWorker.Append(cmdWorker.Create(OpCodes.Call, Weaver.UBehaviourIsServer));
            cmdWorker.Append(cmdWorker.Create(OpCodes.Brfalse, localClientLabel));

            // call the cmd function directly.
            cmdWorker.Append(cmdWorker.Create(OpCodes.Ldarg_0));
            for (int i = 0; i < md.Parameters.Count; i++)
            {
                cmdWorker.Append(cmdWorker.Create(OpCodes.Ldarg, i + 1));
            }
            cmdWorker.Append(cmdWorker.Create(OpCodes.Call, md));
            cmdWorker.Append(cmdWorker.Create(OpCodes.Ret));
            cmdWorker.Append(localClientLabel);

            // NetworkWriter writer = new NetworkWriter();
            NetworkBehaviourProcessor.WriteCreateWriter(cmdWorker);

            // write all the arguments that the user passed to the Cmd call
            if (!NetworkBehaviourProcessor.WriteArguments(cmdWorker, md, "Command", false))
            {
                return(null);
            }

            var cmdName = md.Name;
            int index   = cmdName.IndexOf(k_CmdPrefix);

            if (index > -1)
            {
                cmdName = cmdName.Substring(k_CmdPrefix.Length);
            }

            // invoke interal send and return
            cmdWorker.Append(cmdWorker.Create(OpCodes.Ldarg_0));                                 // load 'base.' to call the SendCommand function with
            cmdWorker.Append(cmdWorker.Create(OpCodes.Ldtoken, td));
            cmdWorker.Append(cmdWorker.Create(OpCodes.Call, Weaver.getTypeFromHandleReference)); // invokerClass
            cmdWorker.Append(cmdWorker.Create(OpCodes.Ldstr, cmdName));
            cmdWorker.Append(cmdWorker.Create(OpCodes.Ldloc_0));                                 // writer
            cmdWorker.Append(cmdWorker.Create(OpCodes.Ldc_I4, NetworkBehaviourProcessor.GetChannelId(ca)));
            cmdWorker.Append(cmdWorker.Create(OpCodes.Call, Weaver.sendCommandInternal));

            cmdWorker.Append(cmdWorker.Create(OpCodes.Ret));

            return(cmd);
        }