static void LoadWriters(AssemblyDefinition currentAssembly, TypeDefinition klass)
        {
            // register all the writers in this class.  Skip the ones with wrong signature
            foreach (MethodDefinition method in klass.Methods)
            {
                if (method.Parameters.Count != 2)
                {
                    continue;
                }

                if (method.Parameters[0].ParameterType.FullName != "Mirror.NetworkWriter")
                {
                    continue;
                }

                if (method.ReturnType.FullName != "System.Void")
                {
                    continue;
                }

                if (method.GetCustomAttribute("System.Runtime.CompilerServices.ExtensionAttribute") == null)
                {
                    continue;
                }

                TypeReference dataType = method.Parameters[1].ParameterType;
                Writers.Register(dataType, currentAssembly.MainModule.ImportReference(method));
            }
        }
예제 #2
0
        /// <summary>
        /// Creates a method that will store all the readers and writers into
        /// <see cref="Writer{T}.Write"/> and <see cref="Reader{T}.Read"/>
        ///
        /// The method will be marked InitializeOnLoadMethodAttribute so it gets
        /// executed before mirror runtime code
        /// </summary>
        /// <param name="currentAssembly"></param>
        public static void InitializeReaderAndWriters(ModuleDefinition module)
        {
            MethodDefinition rwInitializer = module.GeneratedClass().AddMethod(
                "InitReadWriters",
                MethodAttributes.Public | MethodAttributes.Static);

            System.Reflection.ConstructorInfo attributeconstructor = typeof(RuntimeInitializeOnLoadMethodAttribute).GetConstructor(new [] { typeof(RuntimeInitializeLoadType) });

            var customAttributeRef = new CustomAttribute(module.ImportReference(attributeconstructor));

            customAttributeRef.ConstructorArguments.Add(new CustomAttributeArgument(module.ImportReference <RuntimeInitializeLoadType>(), RuntimeInitializeLoadType.BeforeSceneLoad));
            rwInitializer.CustomAttributes.Add(customAttributeRef);

            if (IsEditorAssembly(module))
            {
                // editor assembly,  add InitializeOnLoadMethod too.  Useful for the editor tests
                System.Reflection.ConstructorInfo initializeOnLoadConstructor = typeof(InitializeOnLoadMethodAttribute).GetConstructor(new Type[0]);
                var initializeCustomConstructorRef = new CustomAttribute(module.ImportReference(initializeOnLoadConstructor));
                rwInitializer.CustomAttributes.Add(initializeCustomConstructorRef);
            }

            ILProcessor worker = rwInitializer.Body.GetILProcessor();

            Writers.InitializeWriters(worker);
            Readers.InitializeReaders(worker);

            RegisterMessages(module, worker);

            worker.Append(worker.Create(OpCodes.Ret));
        }
예제 #3
0
 protected RpcProcessor(ModuleDefinition module, Readers readers, Writers writers, IWeaverLogger logger)
 {
     this.module  = module;
     this.readers = readers;
     this.writers = writers;
     this.logger  = logger;
 }
예제 #4
0
        // Finds SyncObjects fields in a type
        // Type should be a NetworkBehaviour
        public static List <FieldDefinition> FindSyncObjectsFields(Writers writers, Readers readers, Logger Log, TypeDefinition td, ref bool WeavingFailed)
        {
            List <FieldDefinition> syncObjects = new List <FieldDefinition>();

            foreach (FieldDefinition fd in td.Fields)
            {
                if (fd.FieldType.Resolve().ImplementsInterface <SyncObject>())
                {
                    if (fd.IsStatic)
                    {
                        Log.Error($"{fd.Name} cannot be static", fd);
                        WeavingFailed = true;
                        continue;
                    }

                    GenerateReadersAndWriters(writers, readers, fd.FieldType, ref WeavingFailed);

                    syncObjects.Add(fd);
                }
            }

            // SyncObjects dirty mask is 64 bit. can't sync more than 64.
            if (syncObjects.Count > 64)
            {
                Log.Error($"{td.Name} has > {SyncObjectsLimit} SyncObjects (SyncLists etc). Consider refactoring your class into multiple components", td);
                WeavingFailed = true;
            }


            return(syncObjects);
        }
        public static bool WriteArguments(ILProcessor worker, MethodDefinition md, bool skipFirst)
        {
            // write each argument
            short argNum = 1;

            foreach (ParameterDefinition pd in md.Parameters)
            {
                if (argNum == 1 && skipFirst)
                {
                    argNum += 1;
                    continue;
                }

                MethodReference writeFunc = Writers.GetWriteFunc(pd.ParameterType);
                if (writeFunc == null)
                {
                    Weaver.Error($"{md} has invalid parameter {pd}");
                    return(false);
                }
                // use built-in writer func on writer object
                worker.Append(worker.Create(OpCodes.Ldloc_0));         // writer object
                worker.Append(worker.Create(OpCodes.Ldarg, argNum));   // argument
                worker.Append(worker.Create(OpCodes.Call, writeFunc)); // call writer func on writer object
                argNum += 1;
            }
            return(true);
        }
        // adds Mirror.GeneratedNetworkCode.InitReadWriters() method that
        // registers all generated writers into Mirror.Writer<T> static class.
        // -> uses [RuntimeInitializeOnLoad] attribute so it's invoke at runtime
        // -> uses [InitializeOnLoad] if UnityEditor is referenced so it works
        //    in Editor and in tests too
        //
        // use ILSpy to see the result (it's in the DLL's 'Mirror' namespace)
        public static void InitializeReaderAndWriters(AssemblyDefinition currentAssembly)
        {
            MethodDefinition rwInitializer = new MethodDefinition("InitReadWriters", MethodAttributes.Public |
                                                                  MethodAttributes.Static,
                                                                  WeaverTypes.Import(typeof(void)));

            // add [RuntimeInitializeOnLoad] in any case
            System.Reflection.ConstructorInfo attributeconstructor = typeof(RuntimeInitializeOnLoadMethodAttribute).GetConstructor(new[] { typeof(RuntimeInitializeLoadType) });
            CustomAttribute customAttributeRef = new CustomAttribute(currentAssembly.MainModule.ImportReference(attributeconstructor));

            customAttributeRef.ConstructorArguments.Add(new CustomAttributeArgument(WeaverTypes.Import <RuntimeInitializeLoadType>(), RuntimeInitializeLoadType.BeforeSceneLoad));
            rwInitializer.CustomAttributes.Add(customAttributeRef);

            // add [InitializeOnLoad] if UnityEditor is referenced
            if (IsEditorAssembly(currentAssembly))
            {
                System.Reflection.ConstructorInfo initializeOnLoadConstructor = typeof(InitializeOnLoadMethodAttribute).GetConstructor(new Type[0]);
                CustomAttribute initializeCustomConstructorRef = new CustomAttribute(currentAssembly.MainModule.ImportReference(initializeOnLoadConstructor));
                rwInitializer.CustomAttributes.Add(initializeCustomConstructorRef);
            }

            // fill function body with reader/writer initializers
            ILProcessor worker = rwInitializer.Body.GetILProcessor();

            // for debugging: add a log to see if initialized on load
            //worker.Emit(OpCodes.Ldstr, $"[InitReadWriters] called!");
            //worker.Emit(OpCodes.Call, WeaverTypes.logWarningReference);

            Writers.InitializeWriters(worker);
            Readers.InitializeReaders(worker);

            worker.Emit(OpCodes.Ret);

            Weaver.GeneratedCodeClass.Methods.Add(rwInitializer);
        }
예제 #7
0
        static void LoadDeclaredWriters(AssemblyDefinition currentAssembly, TypeDefinition klass)
        {
            // register all the writers in this class.  Skip the ones with wrong signature
            foreach (MethodDefinition method in klass.Methods)
            {
                if (method.Parameters.Count != 2)
                {
                    continue;
                }

                if (!method.Parameters[0].ParameterType.Is <NetworkWriter>())
                {
                    continue;
                }

                if (!method.ReturnType.Is(typeof(void)))
                {
                    continue;
                }

                if (!method.HasCustomAttribute <System.Runtime.CompilerServices.ExtensionAttribute>())
                {
                    continue;
                }

                if (method.HasGenericParameters)
                {
                    continue;
                }

                TypeReference dataType = method.Parameters[1].ParameterType;
                Writers.Register(dataType, currentAssembly.MainModule.ImportReference(method));
            }
        }
예제 #8
0
        public AssemblyDefinition Weave(ICompiledAssembly compiledAssembly)
        {
            try
            {
                CurrentAssembly = AssemblyDefinitionFor(compiledAssembly);

                ModuleDefinition module = CurrentAssembly.MainModule;
                readers = new Readers(module, logger);
                writers = new Writers(module, logger);
                var rwstopwatch = System.Diagnostics.Stopwatch.StartNew();
                propertySiteProcessor = new PropertySiteProcessor();
                var rwProcessor = new ReaderWriterProcessor(module, readers, writers);

                bool modified = rwProcessor.Process();
                rwstopwatch.Stop();
                Console.WriteLine($"Find all reader and writers took {rwstopwatch.ElapsedMilliseconds} milliseconds");

                Console.WriteLine($"Script Module: {module.Name}");

                modified |= WeaveModule(module);

                if (!modified)
                    return CurrentAssembly;

                rwProcessor.InitializeReaderAndWriters();

                return CurrentAssembly;
            }
            catch (Exception e)
            {
                logger.Error("Exception :" + e);
                return null;
            }
        }
예제 #9
0
        /// <summary>
        /// Creates a method that will store all the readers and writers into
        /// <see cref="Writer{T}.write"/> and <see cref="Reader{T}.read"/>
        ///
        /// The method will be marked InitializeOnLoadMethodAttribute so it gets
        /// executed before mirror runtime code
        /// </summary>
        /// <param name="currentAssembly"></param>
        public static void InitializeReaderAndWriters(AssemblyDefinition currentAssembly)
        {
            var rwInitializer = new MethodDefinition("InitReadWriters", MethodAttributes.Public |
                                                     MethodAttributes.Static,
                                                     WeaverTypes.Import(typeof(void)));

            System.Reflection.ConstructorInfo attributeconstructor = typeof(RuntimeInitializeOnLoadMethodAttribute).GetConstructor(new [] { typeof(RuntimeInitializeLoadType) });

            var customAttributeRef = new CustomAttribute(currentAssembly.MainModule.ImportReference(attributeconstructor));

            customAttributeRef.ConstructorArguments.Add(new CustomAttributeArgument(WeaverTypes.Import <RuntimeInitializeLoadType>(), RuntimeInitializeLoadType.BeforeSceneLoad));
            rwInitializer.CustomAttributes.Add(customAttributeRef);

            if (IsEditorAssembly(currentAssembly))
            {
                // editor assembly,  add InitializeOnLoadMethod too.  Useful for the editor tests
                System.Reflection.ConstructorInfo initializeOnLoadConstructor = typeof(InitializeOnLoadMethodAttribute).GetConstructor(new Type[0]);
                var initializeCustomConstructorRef = new CustomAttribute(currentAssembly.MainModule.ImportReference(initializeOnLoadConstructor));
                rwInitializer.CustomAttributes.Add(initializeCustomConstructorRef);
            }

            ILProcessor worker = rwInitializer.Body.GetILProcessor();

            Writers.InitializeWriters(worker);
            Readers.InitializeReaders(worker);

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

            Weaver.WeaveLists.ConfirmGeneratedCodeClass();
            TypeDefinition generateClass = Weaver.WeaveLists.generateContainerClass;

            generateClass.Methods.Add(rwInitializer);
        }
예제 #10
0
        public static bool Process(ModuleDefinition module, Assembly unityAssembly)
        {
            // darn global state causing bugs
            Readers.Init();
            Writers.Init();
            messages.Clear();
            foreach (Assembly unityAsm in unityAssembly.assemblyReferences)
            {
                if (unityAsm.name == "Mirror")
                {
                    using (var asmResolver = new DefaultAssemblyResolver())
                        using (var assembly = AssemblyDefinition.ReadAssembly(unityAsm.outputPath, new ReaderParameters {
                            ReadWrite = false, ReadSymbols = false, AssemblyResolver = asmResolver
                        }))
                        {
                            ProcessAssemblyClasses(module, assembly.MainModule);
                        }
                }
            }

            int writeCount = Writers.Count;
            int readCount  = Readers.Count;

            ProcessAssemblyClasses(module, module);

            return(Writers.Count != writeCount || Readers.Count != readCount);
        }
        public static MethodDefinition ProcessRpcInvoke(WeaverTypes weaverTypes, Writers writers, Readers readers, Logger Log, TypeDefinition td, MethodDefinition md, MethodDefinition rpcCallFunc, ref bool WeavingFailed)
        {
            string rpcName = Weaver.GenerateMethodName(Weaver.InvokeRpcPrefix, md);

            MethodDefinition rpc = new MethodDefinition(rpcName, MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig,
                                                        weaverTypes.Import(typeof(void)));

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

            NetworkBehaviourProcessor.WriteClientActiveCheck(worker, weaverTypes, md.Name, label, "RPC");

            // setup for reader
            worker.Emit(OpCodes.Ldarg_0);
            worker.Emit(OpCodes.Castclass, td);

            if (!NetworkBehaviourProcessor.ReadArguments(md, readers, Log, worker, RemoteCallType.ClientRpc, ref WeavingFailed))
            {
                return(null);
            }

            // invoke actual command function
            worker.Emit(OpCodes.Callvirt, rpcCallFunc);
            worker.Emit(OpCodes.Ret);

            NetworkBehaviourProcessor.AddInvokeParameters(weaverTypes, rpc.Parameters);
            td.Methods.Add(rpc);
            return(rpc);
        }
        // find all readers and writers and register them
        public static void ProcessReadersAndWriters(AssemblyDefinition CurrentAssembly)
        {
            Readers.Init();
            Writers.Init();

            foreach (Assembly unityAsm in CompilationPipeline.GetAssemblies())
            {
                if (unityAsm.name != CurrentAssembly.Name.Name)
                {
                    try
                    {
                        using (DefaultAssemblyResolver asmResolver = new DefaultAssemblyResolver())
                            using (AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(unityAsm.outputPath, new ReaderParameters {
                                ReadWrite = false, ReadSymbols = false, AssemblyResolver = asmResolver
                            }))
                            {
                                ProcessAssemblyClasses(CurrentAssembly, assembly);
                            }
                    }
                    catch (FileNotFoundException)
                    {
                        // During first import,  this gets called before some assemblies
                        // are built,  just skip them
                    }
                }
            }

            ProcessAssemblyClasses(CurrentAssembly, CurrentAssembly);
        }
예제 #13
0
 public SyncVarProcessor(ModuleDefinition module, Readers readers, Writers writers, PropertySiteProcessor propertySiteProcessor, IWeaverLogger logger)
 {
     this.module  = module;
     this.readers = readers;
     this.writers = writers;
     this.propertySiteProcessor = propertySiteProcessor;
     this.logger = logger;
 }
예제 #14
0
        static void GenerateSerialization(TypeDefinition td)
        {
            Weaver.DLog(td, "  GenerateSerialization");
            foreach (MethodDefinition m in td.Methods)
            {
                if (m.Name == "Serialize")
                {
                    return;
                }
            }

            if (td.Fields.Count == 0)
            {
                return;
            }

            // check for self-referencing types
            foreach (FieldDefinition field in td.Fields)
            {
                if (field.FieldType.FullName == td.FullName)
                {
                    Weaver.Error($"{td} has field ${field} that references itself");
                    return;
                }
            }

            MethodDefinition serializeFunc = new MethodDefinition("Serialize",
                                                                  MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig,
                                                                  Weaver.voidType);

            serializeFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkWriterType)));
            ILProcessor serWorker = serializeFunc.Body.GetILProcessor();

            foreach (FieldDefinition field in td.Fields)
            {
                if (field.IsStatic || field.IsPrivate || field.IsSpecialName)
                {
                    continue;
                }

                MethodReference writeFunc = Writers.GetWriteFunc(field.FieldType);
                if (writeFunc != null)
                {
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                    serWorker.Append(serWorker.Create(OpCodes.Ldfld, field));
                    serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc));
                }
                else
                {
                    Weaver.Error($"{field} has unsupported type");
                    return;
                }
            }
            serWorker.Append(serWorker.Create(OpCodes.Ret));

            td.Methods.Add(serializeFunc);
        }
 public NetworkBehaviourProcessor(TypeDefinition td, Readers readers, Writers writers, PropertySiteProcessor propertySiteProcessor, IWeaverLogger logger)
 {
     Weaver.DLog(td, "NetworkBehaviourProcessor");
     netBehaviourSubclass = td;
     this.logger          = logger;
     serverRpcProcessor   = new ServerRpcProcessor(netBehaviourSubclass.Module, readers, writers, logger);
     clientRpcProcessor   = new ClientRpcProcessor(netBehaviourSubclass.Module, readers, writers, logger);
     syncVarProcessor     = new SyncVarProcessor(netBehaviourSubclass.Module, readers, writers, propertySiteProcessor, logger);
     syncObjectProcessor  = new SyncObjectProcessor(readers, writers, logger);
 }
예제 #16
0
        // Finds SyncObjects fields in a type
        // Type should be a NetworkBehaviour
        public static List <FieldDefinition> FindSyncObjectsFields(Writers writers, Readers readers, Logger Log, TypeDefinition td, ref bool WeavingFailed)
        {
            List <FieldDefinition> syncObjects = new List <FieldDefinition>();

            foreach (FieldDefinition fd in td.Fields)
            {
                if (fd.FieldType.IsGenericParameter)
                {
                    // can't call .Resolve on generic ones
                    continue;
                }

                if (fd.FieldType.Resolve().IsDerivedFrom <SyncObject>())
                {
                    if (fd.IsStatic)
                    {
                        Log.Error($"{fd.Name} cannot be static", fd);
                        WeavingFailed = true;
                        continue;
                    }

                    // SyncObjects always needs to be readonly to guarantee.
                    // Weaver calls InitSyncObject on them for dirty bits etc.
                    // Reassigning at runtime would cause undefined behaviour.
                    // (C# 'readonly' is called 'initonly' in IL code.)
                    //
                    // NOTE: instead of forcing readonly, we could also scan all
                    //       instructions for SyncObject assignments. this would
                    //       make unit tests very difficult though.
                    if (!fd.IsInitOnly)
                    {
                        // just a warning for now.
                        // many people might still use non-readonly SyncObjects.
                        Log.Warning($"{fd.Name} should have a 'readonly' keyword in front of the variable because {typeof(SyncObject)}s always need to be initialized by the Weaver.", fd);

                        // only log, but keep weaving. no need to break projects.
                        //WeavingFailed = true;
                    }

                    GenerateReadersAndWriters(writers, readers, fd.FieldType, ref WeavingFailed);

                    syncObjects.Add(fd);
                }
            }

            // SyncObjects dirty mask is 64 bit. can't sync more than 64.
            if (syncObjects.Count > 64)
            {
                Log.Error($"{td.Name} has > {SyncObjectsLimit} SyncObjects (SyncLists etc). Consider refactoring your class into multiple components", td);
                WeavingFailed = true;
            }


            return(syncObjects);
        }
예제 #17
0
 public NetworkBehaviourProcessor(AssemblyDefinition assembly, WeaverTypes weaverTypes, SyncVarAccessLists syncVarAccessLists, Writers writers, Readers readers, Logger Log, TypeDefinition td)
 {
     this.assembly           = assembly;
     this.weaverTypes        = weaverTypes;
     this.syncVarAccessLists = syncVarAccessLists;
     this.writers            = writers;
     this.readers            = readers;
     this.Log = Log;
     syncVarAttributeProcessor = new SyncVarAttributeProcessor(assembly, weaverTypes, syncVarAccessLists, Log);
     netBehaviourSubclass      = td;
 }
        private static void LoadMessageReadWriter(ModuleDefinition module, TypeDefinition klass)
        {
            if (!klass.IsAbstract && !klass.IsInterface && klass.ImplementsInterface <NetworkMessage>())
            {
                Readers.GetReadFunc(module.ImportReference(klass));
                Writers.GetWriteFunc(module.ImportReference(klass));
            }

            foreach (TypeDefinition td in klass.NestedTypes)
            {
                LoadMessageReadWriter(module, td);
            }
        }
예제 #19
0
        public static bool WriteArguments(ILProcessor worker, Writers writers, Logger Log, MethodDefinition method, RemoteCallType callType, ref bool WeavingFailed)
        {
            // write each argument
            // example result

            /*
             * writer.WritePackedInt32(someNumber);
             * writer.WriteNetworkIdentity(someTarget);
             */

            bool skipFirst = callType == RemoteCallType.TargetRpc &&
                             TargetRpcProcessor.HasNetworkConnectionParameter(method);

            // arg of calling  function, arg 0 is "this" so start counting at 1
            int argNum = 1;

            foreach (ParameterDefinition param in method.Parameters)
            {
                // NetworkConnection is not sent via the NetworkWriter so skip it here
                // skip first for NetworkConnection in TargetRpc
                if (argNum == 1 && skipFirst)
                {
                    argNum += 1;
                    continue;
                }
                // skip SenderConnection in Command
                if (IsSenderConnection(param, callType))
                {
                    argNum += 1;
                    continue;
                }

                MethodReference writeFunc = writers.GetWriteFunc(param.ParameterType, ref WeavingFailed);
                if (writeFunc == null)
                {
                    Log.Error($"{method.Name} has invalid parameter {param}", method);
                    WeavingFailed = true;
                    return(false);
                }

                // use built-in writer func on writer object
                // NetworkWriter object
                worker.Emit(OpCodes.Ldloc_0);
                // add argument to call
                worker.Emit(OpCodes.Ldarg, argNum);
                // call writer extension method
                worker.Emit(OpCodes.Call, writeFunc);
                argNum += 1;
            }
            return(true);
        }
예제 #20
0
        private static MethodDefinition GenerateEnumWriteFunc(TypeReference variable)
        {
            MethodDefinition writerFunc = GenerateWriterFunc(variable);

            ILProcessor worker = writerFunc.Body.GetILProcessor();

            MethodReference underlyingWriter = Writers.GetWriteFunc(variable.Resolve().GetEnumUnderlyingType());

            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Ldarg_1));
            worker.Append(worker.Create(OpCodes.Call, underlyingWriter));

            worker.Append(worker.Create(OpCodes.Ret));
            return(writerFunc);
        }
        // serialization of individual element
        private static MethodReference GenerateSerialization(string methodName, TypeDefinition td,
                                                             TypeReference itemType)
        {
            Weaver.DLog(td, "  GenerateSerialization");
            foreach (var m in td.Methods)
            {
                if (m.Name == methodName)
                {
                    return(m);
                }
            }

            var serializeFunc = new MethodDefinition(methodName, MethodAttributes.Public |
                                                     MethodAttributes.Virtual |
                                                     MethodAttributes.Public |
                                                     MethodAttributes.HideBySig,
                                                     Weaver.voidType);

            serializeFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None,
                                                                 Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkWriterType)));
            serializeFunc.Parameters.Add(new ParameterDefinition("item", ParameterAttributes.None, itemType));
            var serWorker = serializeFunc.Body.GetILProcessor();

            if (itemType.IsGenericInstance)
            {
                Weaver.Error($"{td} cannot have generic elements {itemType}");
                return(null);
            }

            var writeFunc = Writers.GetWriteFunc(itemType);

            if (writeFunc != null)
            {
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_2));
                serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc));
            }
            else
            {
                Weaver.Error($"{td} cannot have item of type {itemType}.  Use a type supported by mirror instead");
                return(null);
            }

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

            td.Methods.Add(serializeFunc);
            return(serializeFunc);
        }
        private static void CallWriter(ILProcessor serWorker, FieldDefinition field)
        {
            MethodReference writeFunc = Writers.GetWriteFunc(field.FieldType);

            if (writeFunc != null)
            {
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                serWorker.Append(serWorker.Create(OpCodes.Ldfld, field));
                serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc));
            }
            else
            {
                Weaver.Error($"{field.Name} has unsupported type", field);
            }
        }
예제 #23
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);
            }

            string rpcName = md.Name;

            // 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);
            }
            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, targetRpcAttr.GetField("channel", 0));
            worker.Emit(OpCodes.Callvirt, weaverTypes.sendTargetRpcInternal);

            NetworkBehaviourProcessor.WriteRecycleWriter(worker, weaverTypes);

            worker.Emit(OpCodes.Ret);

            return(rpc);
        }
예제 #24
0
        // serialization of individual element
        static bool GenerateSerialization(string methodName, TypeDefinition td, TypeReference itemType, TypeReference mirrorBaseType)
        {
            Weaver.DLog(td, "  GenerateSerialization");
            bool existing = td.HasMethodInBaseType(methodName, mirrorBaseType);

            if (existing)
            {
                return(true);
            }


            // this check needs to happen inside GenerateSerialization because
            // we need to check if user has made custom function above
            if (itemType.IsGenericInstance)
            {
                Weaver.Error($"Can not create Serialize or Deserialize for generic element in {td.Name}. Override virtual methods with custom Serialize and Deserialize to use {itemType} in SyncList", td);
                return(false);
            }

            var serializeFunc = new MethodDefinition(methodName, MethodAttributes.Public |
                                                     MethodAttributes.Virtual |
                                                     MethodAttributes.Public |
                                                     MethodAttributes.HideBySig,
                                                     WeaverTypes.Import(typeof(void)));

            serializeFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, WeaverTypes.Import <NetworkWriter>()));
            serializeFunc.Parameters.Add(new ParameterDefinition("item", ParameterAttributes.None, itemType));
            ILProcessor worker = serializeFunc.Body.GetILProcessor();

            MethodReference writeFunc = Writers.GetWriteFunc(itemType);

            if (writeFunc != null)
            {
                worker.Append(worker.Create(OpCodes.Ldarg_1));
                worker.Append(worker.Create(OpCodes.Ldarg_2));
                worker.Append(worker.Create(OpCodes.Call, writeFunc));
            }
            else
            {
                Weaver.Error($"{td.Name} has sync object generic type {itemType.Name}.  Use a type supported by mirror instead", td);
                return(false);
            }
            worker.Append(worker.Create(OpCodes.Ret));

            td.Methods.Add(serializeFunc);
            return(true);
        }
예제 #25
0
        static bool LoadMessageReadWriter(ModuleDefinition module, TypeDefinition klass)
        {
            bool modified = false;

            if (!klass.IsAbstract && !klass.IsInterface && klass.ImplementsInterface <NetworkMessage>())
            {
                Readers.GetReadFunc(module.ImportReference(klass));
                Writers.GetWriteFunc(module.ImportReference(klass));
                modified = true;
            }

            foreach (TypeDefinition td in klass.NestedTypes)
            {
                modified |= LoadMessageReadWriter(module, td);
            }
            return(modified);
        }
        // serialization of individual element
        static MethodReference GenerateSerialization(string methodName, TypeDefinition td, TypeReference itemType)
        {
            Weaver.DLog(td, "  GenerateSerialization");
            foreach (MethodDefinition m in td.Methods)
            {
                if (m.Name == methodName)
                {
                    return(m);
                }
            }

            MethodDefinition serializeFunc = new MethodDefinition(methodName, MethodAttributes.Public |
                                                                  MethodAttributes.Virtual |
                                                                  MethodAttributes.Public |
                                                                  MethodAttributes.HideBySig,
                                                                  Weaver.voidType);

            serializeFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkWriterType)));
            serializeFunc.Parameters.Add(new ParameterDefinition("item", ParameterAttributes.None, itemType));
            ILProcessor serWorker = serializeFunc.Body.GetILProcessor();

            if (itemType.IsGenericInstance)
            {
                Weaver.Error("GenerateSerialization for " + Helpers.PrettyPrintType(itemType) + " failed. Can't have generic parameters");
                return(null);
            }

            MethodReference writeFunc = Writers.GetWriteFunc(itemType);

            if (writeFunc != null)
            {
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_2));
                serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc));
            }
            else
            {
                Weaver.Error("GenerateSerialization for " + td.Name + " unknown type [" + itemType + "/" + itemType.FullName + "]. Member variables must be basic types.");
                return(null);
            }
            serWorker.Append(serWorker.Create(OpCodes.Ret));

            td.Methods.Add(serializeFunc);
            return(serializeFunc);
        }
예제 #27
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);
        }
예제 #28
0
        public static bool Process(AssemblyDefinition CurrentAssembly)
        {
            Readers.Init();
            Writers.Init();
            foreach (Assembly unityAsm in CompilationPipeline.GetAssemblies())
            {
                if (unityAsm.name == "Mirror")
                {
                    using (DefaultAssemblyResolver asmResolver = new DefaultAssemblyResolver())
                        using (AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(unityAsm.outputPath, new ReaderParameters {
                            ReadWrite = false, ReadSymbols = false, AssemblyResolver = asmResolver
                        })) {
                            ProcessAssemblyClasses(CurrentAssembly, assembly);
                        }
                }
            }

            return(ProcessAssemblyClasses(CurrentAssembly, CurrentAssembly));
        }
예제 #29
0
        // Generates serialization methods for synclists
        static void GenerateReadersAndWriters(Writers writers, Readers readers, TypeReference tr, ref bool WeavingFailed)
        {
            if (tr is GenericInstanceType genericInstance)
            {
                foreach (TypeReference argument in genericInstance.GenericArguments)
                {
                    if (!argument.IsGenericParameter)
                    {
                        readers.GetReadFunc(argument, ref WeavingFailed);
                        writers.GetWriteFunc(argument, ref WeavingFailed);
                    }
                }
            }

            if (tr != null)
            {
                GenerateReadersAndWriters(writers, readers, tr.Resolve().BaseType, ref WeavingFailed);
            }
        }
        /// <summary>
        /// Generates serialization methods for synclists
        /// </summary>
        /// <param name="td">The synclist class</param>
        /// <param name="mirrorBaseType">the base SyncObject td inherits from</param>
        static void GenerateReadersAndWriters(TypeReference tr)
        {
            if (tr is GenericInstanceType genericInstance)
            {
                foreach (TypeReference argument in genericInstance.GenericArguments)
                {
                    if (!argument.IsGenericParameter)
                    {
                        Readers.GetReadFunc(argument);
                        Writers.GetWriteFunc(argument);
                    }
                }
            }

            if (tr != null)
            {
                GenerateReadersAndWriters(tr.Resolve().BaseType);
            }
        }