void RegisterRpcs()
        {
            Weaver.DLog(netBehaviourSubclass, "  GenerateConstants ");

            // find static constructor
            MethodDefinition cctor = netBehaviourSubclass.GetMethod(".cctor");

            if (cctor != null)
            {
                // remove the return opcode from end of function. will add our own later.
                if (cctor.Body.Instructions.Count != 0)
                {
                    Instruction retInstr = cctor.Body.Instructions[cctor.Body.Instructions.Count - 1];
                    if (retInstr.OpCode == OpCodes.Ret)
                    {
                        cctor.Body.Instructions.RemoveAt(cctor.Body.Instructions.Count - 1);
                    }
                    else
                    {
                        logger.Error($"{netBehaviourSubclass.Name} has invalid class constructor", cctor);
                        return;
                    }
                }
            }
            else
            {
                // make one!
                cctor = netBehaviourSubclass.AddMethod(".cctor", MethodAttributes.Private |
                                                       MethodAttributes.HideBySig |
                                                       MethodAttributes.SpecialName |
                                                       MethodAttributes.RTSpecialName |
                                                       MethodAttributes.Static);
            }

            ILProcessor cctorWorker = cctor.Body.GetILProcessor();

            serverRpcProcessor.RegisterServerRpcs(cctorWorker);

            clientRpcProcessor.RegisterClientRpcs(cctorWorker);

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

            // in case class had no cctor, it might have BeforeFieldInit, so injected cctor would be called too late
            netBehaviourSubclass.Attributes &= ~TypeAttributes.BeforeFieldInit;
        }
示例#2
0
        /// <summary>
        /// Finds and fixes call to base methods within remote calls
        /// <para>For example, changes `base.CmdDoSomething` to `base.UserCode_CmdDoSomething` within `this.UserCode_CmdDoSomething`</para>
        /// </summary>
        /// <param name="type"></param>
        /// <param name="method"></param>
        public void FixRemoteCallToBaseMethod(TypeDefinition type, MethodDefinition method)
        {
            string callName = method.Name;

            // all ServerRpcs/Rpc start with "UserCode_"
            // eg CallCmdDoSomething
            if (!callName.StartsWith(UserCodePrefix))
            {
                return;
            }

            // eg CmdDoSomething
            string baseRemoteCallName = method.Name.Substring(UserCodePrefix.Length);

            foreach (Instruction instruction in method.Body.Instructions)
            {
                // if call to base.CmdDoSomething within this.CallCmdDoSomething
                if (IsCallToMethod(instruction, out MethodDefinition calledMethod) &&
                    calledMethod.Name == baseRemoteCallName)
                {
                    TypeDefinition  baseType   = type.BaseType.Resolve();
                    MethodReference baseMethod = baseType.GetMethodInBaseType(callName);

                    if (baseMethod == null)
                    {
                        logger.Error($"Could not find base method for {callName}", method);
                        return;
                    }

                    if (!baseMethod.Resolve().IsVirtual)
                    {
                        logger.Error($"Could not find base method that was virtual {callName}", method);
                        return;
                    }

                    instruction.Operand = method.Module.ImportReference(baseMethod);

                    Weaver.DLog(type, "Replacing call to '{0}' with '{1}' inside '{2}'", calledMethod.FullName, baseMethod.FullName, method.FullName);
                }
            }
        }
        // return true if modified
        public bool Process()
        {
            // only process once
            if (WasProcessed(netBehaviourSubclass))
            {
                return(false);
            }
            Weaver.DLog(netBehaviourSubclass, "Found NetworkBehaviour " + netBehaviourSubclass.FullName);

            Weaver.DLog(netBehaviourSubclass, "Process Start");
            MarkAsProcessed(netBehaviourSubclass);

            syncVarProcessor.ProcessSyncVars(netBehaviourSubclass);

            syncObjectProcessor.ProcessSyncObjects(netBehaviourSubclass);

            ProcessRpcs();

            Weaver.DLog(netBehaviourSubclass, "Process Done");
            return(true);
        }
示例#4
0
        void RegisterSyncObjects(TypeDefinition netBehaviourSubclass)
        {
            Weaver.DLog(netBehaviourSubclass, "  GenerateConstants ");

            // find instance constructor
            MethodDefinition ctor = netBehaviourSubclass.GetMethod(".ctor");

            if (ctor == null)
            {
                logger.Error($"{netBehaviourSubclass.Name} has invalid constructor", netBehaviourSubclass);
                return;
            }

            Instruction ret = ctor.Body.Instructions[ctor.Body.Instructions.Count - 1];

            if (ret.OpCode == OpCodes.Ret)
            {
                ctor.Body.Instructions.RemoveAt(ctor.Body.Instructions.Count - 1);
            }
            else
            {
                logger.Error($"{netBehaviourSubclass.Name} has invalid constructor", ctor, ctor.DebugInformation.SequencePoints.FirstOrDefault());
                return;
            }

            ILProcessor ctorWorker = ctor.Body.GetILProcessor();

            foreach (FieldDefinition fd in syncObjects)
            {
                GenerateSyncObjectRegistration(ctorWorker, fd);
            }

            // finish ctor
            ctorWorker.Append(ctorWorker.Create(OpCodes.Ret));

            // in case class had no cctor, it might have BeforeFieldInit, so injected cctor would be called too late
            netBehaviourSubclass.Attributes &= ~TypeAttributes.BeforeFieldInit;
        }