static void ProcessSiteMethod(WeaverLists weaverLists, MethodDefinition md)
        {
            // process all references to replaced members with properties
            //Weaver.DLog(td, "      ProcessSiteMethod " + md);

            if (md.Name == ".cctor" ||
                md.Name == NetworkBehaviourProcessor.ProcessedFunctionName ||
                md.Name.StartsWith(Weaver.InvokeRpcPrefix))
            {
                return;
            }

            if (md.IsAbstract)
            {
                return;
            }

            if (md.Body != null && md.Body.Instructions != null)
            {
                for (int iCount = 0; iCount < md.Body.Instructions.Count;)
                {
                    Instruction instr = md.Body.Instructions[iCount];
                    iCount += ProcessInstruction(weaverLists, md, instr, iCount);
                }
            }
        }
Beispiel #2
0
        static bool WeaveAssemblies(IEnumerable <string> assemblies, IEnumerable <string> dependencies, string outputDir, string unityEngineDLLPath, string mirrorNetDLLPath)
        {
            WeavingFailed = false;
            WeaveLists    = new WeaverLists();

            using (AssemblyDefinition unityAssembly = AssemblyDefinition.ReadAssembly(unityEngineDLLPath))
                using (AssemblyDefinition mirrorAssembly = AssemblyDefinition.ReadAssembly(mirrorNetDLLPath))
                {
                    WeaverTypes.SetupUnityTypes(unityAssembly, mirrorAssembly);

                    try
                    {
                        foreach (string asm in assemblies)
                        {
                            if (!Weave(asm, unityAssembly, mirrorAssembly, dependencies, unityEngineDLLPath, mirrorNetDLLPath, outputDir))
                            {
                                return(false);
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        Log.Error("Exception :" + e);
                        return(false);
                    }
                }
            return(true);
        }
Beispiel #3
0
        public static bool WeaveAssemblies(IEnumerable <string> assemblies, IEnumerable <string> dependencies, IAssemblyResolver assemblyResolver, string outputDir, string unityEngineDLLPath, string mirrorNetDLLPath)
        {
            WeavingFailed = false;
            WeaveLists    = new WeaverLists();

            UnityAssembly = AssemblyDefinition.ReadAssembly(unityEngineDLLPath);
            NetAssembly   = AssemblyDefinition.ReadAssembly(mirrorNetDLLPath);

            SetupUnityTypes();

            try
            {
                foreach (string ass in assemblies)
                {
                    if (!Weave(ass, dependencies, assemblyResolver, unityEngineDLLPath, mirrorNetDLLPath, outputDir))
                    {
                        return(false);
                    }
                }
            }
            catch (Exception e)
            {
                Log.Error("Exception :" + e);
                return(false);
            }
            CorLibModule = null;
            return(true);
        }
Beispiel #4
0
 public SyncVarProcessor(AssemblyDefinition assembly, WeaverTypes weaverTypes, WeaverLists weaverLists, Logger Log)
 {
     this.assembly    = assembly;
     this.weaverTypes = weaverTypes;
     this.weaverLists = weaverLists;
     this.Log         = Log;
 }
Beispiel #5
0
        static bool Weave(string assName, IEnumerable <string> dependencies)
        {
            using (DefaultAssemblyResolver asmResolver = new DefaultAssemblyResolver())
                using (CurrentAssembly = AssemblyDefinition.ReadAssembly(assName, new ReaderParameters {
                    ReadWrite = true, ReadSymbols = true, AssemblyResolver = asmResolver
                }))
                {
                    asmResolver.AddSearchDirectory(Path.GetDirectoryName(assName));
                    asmResolver.AddSearchDirectory(Helpers.UnityEngineDllDirectoryName());
                    if (dependencies != null)
                    {
                        foreach (string path in dependencies)
                        {
                            asmResolver.AddSearchDirectory(path);
                        }
                    }

                    WeaverTypes.SetupTargetTypes(CurrentAssembly);
                    // WeaverList depends on WeaverTypes setup because it uses Import
                    WeaveLists = new WeaverLists();


                    System.Diagnostics.Stopwatch rwstopwatch = System.Diagnostics.Stopwatch.StartNew();
                    // Need to track modified from ReaderWriterProcessor too because it could find custom read/write functions or create functions for NetworkMessages
                    bool modified = ReaderWriterProcessor.Process(CurrentAssembly);
                    rwstopwatch.Stop();
                    Console.WriteLine($"Find all reader and writers took {rwstopwatch.ElapsedMilliseconds} milliseconds");

                    ModuleDefinition moduleDefinition = CurrentAssembly.MainModule;
                    Console.WriteLine($"Script Module: {moduleDefinition.Name}");

                    modified |= WeaveModule(moduleDefinition);

                    if (WeavingFailed)
                    {
                        return(false);
                    }

                    if (modified)
                    {
                        PropertySiteProcessor.Process(moduleDefinition);

                        // add class that holds read/write functions
                        moduleDefinition.Types.Add(WeaveLists.generateContainerClass);

                        ReaderWriterProcessor.InitializeReaderAndWriters(CurrentAssembly);

                        // write to outputDir if specified, otherwise perform in-place write
                        WriterParameters writeParams = new WriterParameters {
                            WriteSymbols = true
                        };
                        CurrentAssembly.Write(writeParams);
                    }
                }

            return(true);
        }
        static void ProcessSiteClass(WeaverLists weaverLists, TypeDefinition td)
        {
            //Console.WriteLine("    ProcessSiteClass " + td);
            foreach (MethodDefinition md in td.Methods)
            {
                ProcessSiteMethod(weaverLists, md);
            }

            foreach (TypeDefinition nested in td.NestedTypes)
            {
                ProcessSiteClass(weaverLists, nested);
            }
        }
Beispiel #7
0
        public static bool WeaveAssembly(string assembly, IEnumerable <string> dependencies)
        {
            WeavingFailed = false;
            WeaveLists    = new WeaverLists();

            try
            {
                return(Weave(assembly, dependencies));
            }
            catch (Exception e)
            {
                Log.Error("Exception :" + e);
                return(false);
            }
        }
        public static void Process(ModuleDefinition moduleDef, WeaverLists weaverLists)
        {
            DateTime startTime = DateTime.Now;

            //Search through the types
            foreach (TypeDefinition td in moduleDef.Types)
            {
                if (td.IsClass)
                {
                    ProcessSiteClass(weaverLists, td);
                }
            }

            Console.WriteLine("  ProcessSitesModule " + moduleDef.Name + " elapsed time:" + (DateTime.Now - startTime));
        }
Beispiel #9
0
        public static bool WeaveAssembly(Assembly assembly)
        {
            WeavingFailed = false;
            WeaveLists    = new WeaverLists();

            try
            {
                return(Weave(assembly));
            }
            catch (Exception e)
            {
                Log.Error("Exception :" + e);
                return(false);
            }
        }
        // replaces syncvar read access with the NetworkXYZ.get property calls
        static void ProcessInstructionGetterField(WeaverLists weaverLists, MethodDefinition md, Instruction i, FieldDefinition opField)
        {
            // don't replace property call sites in constructors
            if (md.Name == ".ctor")
            {
                return;
            }

            // does it set a field that we replaced?
            if (weaverLists.replacementGetterProperties.TryGetValue(opField, out MethodDefinition replacement))
            {
                //replace with property
                //DLog(td, "    replacing "  + md.Name + ":" + i);
                i.OpCode  = OpCodes.Call;
                i.Operand = replacement;
                //DLog(td, "    replaced  "  + md.Name + ":" + i);
            }
        }
Beispiel #11
0
        static bool WeaveAssemblies(IEnumerable <string> assemblies, IEnumerable <string> dependencies, string outputDir, string unityEngineDLLPath, string mirrorNetDLLPath)
        {
            WeavingFailed = false;
            WeaveLists    = new WeaverLists();

            try
            {
                foreach (string asm in assemblies)
                {
                    if (!Weave(asm, dependencies, unityEngineDLLPath, mirrorNetDLLPath, outputDir))
                    {
                        return(false);
                    }
                }
            }
            catch (Exception e)
            {
                Log.Error("Exception :" + e);
                return(false);
            }
            return(true);
        }
        static int ProcessInstruction(WeaverLists weaverLists, MethodDefinition md, Instruction instr, int iCount)
        {
            if (instr.OpCode == OpCodes.Stfld && instr.Operand is FieldDefinition opFieldst)
            {
                // this instruction sets the value of a field. cache the field reference.
                ProcessInstructionSetterField(weaverLists, md, instr, opFieldst);
            }

            if (instr.OpCode == OpCodes.Ldfld && instr.Operand is FieldDefinition opFieldld)
            {
                // this instruction gets the value of a field. cache the field reference.
                ProcessInstructionGetterField(weaverLists, md, instr, opFieldld);
            }

            if (instr.OpCode == OpCodes.Ldflda && instr.Operand is FieldDefinition opFieldlda)
            {
                // loading a field by reference,  watch out for initobj instruction
                // see https://github.com/vis2k/Mirror/issues/696
                return(ProcessInstructionLoadAddress(weaverLists, md, instr, opFieldlda, iCount));
            }

            return(1);
        }
        static int ProcessInstructionLoadAddress(WeaverLists weaverLists, MethodDefinition md, Instruction instr, FieldDefinition opField, int iCount)
        {
            // don't replace property call sites in constructors
            if (md.Name == ".ctor")
            {
                return(1);
            }

            // does it set a field that we replaced?
            if (weaverLists.replacementSetterProperties.TryGetValue(opField, out MethodDefinition replacement))
            {
                // we have a replacement for this property
                // is the next instruction a initobj?
                Instruction nextInstr = md.Body.Instructions[iCount + 1];

                if (nextInstr.OpCode == OpCodes.Initobj)
                {
                    // we need to replace this code with:
                    //     var tmp = new MyStruct();
                    //     this.set_Networkxxxx(tmp);
                    ILProcessor        worker      = md.Body.GetILProcessor();
                    VariableDefinition tmpVariable = new VariableDefinition(opField.FieldType);
                    md.Body.Variables.Add(tmpVariable);

                    worker.InsertBefore(instr, worker.Create(OpCodes.Ldloca, tmpVariable));
                    worker.InsertBefore(instr, worker.Create(OpCodes.Initobj, opField.FieldType));
                    worker.InsertBefore(instr, worker.Create(OpCodes.Ldloc, tmpVariable));
                    worker.InsertBefore(instr, worker.Create(OpCodes.Call, replacement));

                    worker.Remove(instr);
                    worker.Remove(nextInstr);
                    return(4);
                }
            }

            return(1);
        }
        // Weave takes an AssemblyDefinition to be compatible with both old and
        // new weavers:
        // * old takes a filepath, new takes a in-memory byte[]
        // * old uses DefaultAssemblyResolver with added dependencies paths,
        //   new uses ...?
        //
        // => assembly: the one we are currently weaving (MyGame.dll)
        // => resolver: useful in case we need to resolve any of the assembly's
        //              assembly.MainModule.AssemblyReferences.
        //              -> we can resolve ANY of them given that the resolver
        //                 works properly (need custom one for ILPostProcessor)
        //              -> IMPORTANT: .Resolve() takes an AssemblyNameReference.
        //                 those from assembly.MainModule.AssemblyReferences are
        //                 guaranteed to be resolve-able.
        //                 Parsing from a string for Library/.../Mirror.dll
        //                 would not be guaranteed to be resolve-able because
        //                 for ILPostProcessor we can't assume where Mirror.dll
        //                 is etc.
        public bool Weave(AssemblyDefinition assembly, IAssemblyResolver resolver, out bool modified)
        {
            WeavingFailed = false;
            modified      = false;
            try
            {
                Resolver        = resolver;
                CurrentAssembly = assembly;

                // fix "No writer found for ..." error
                // https://github.com/vis2k/Mirror/issues/2579
                // -> when restarting Unity, weaver would try to weave a DLL
                //    again
                // -> resulting in two GeneratedNetworkCode classes (see ILSpy)
                // -> the second one wouldn't have all the writer types setup
                if (CurrentAssembly.MainModule.ContainsClass(GeneratedCodeNamespace, GeneratedCodeClassName))
                {
                    //Log.Warning($"Weaver: skipping {CurrentAssembly.Name} because already weaved");
                    return(true);
                }

                weaverTypes = new WeaverTypes(CurrentAssembly, Log, ref WeavingFailed);

                // weaverTypes are needed for CreateGeneratedCodeClass
                CreateGeneratedCodeClass();

                // WeaverList depends on WeaverTypes setup because it uses Import
                weaverLists = new WeaverLists();

                // initialize readers & writers with this assembly.
                // we need to do this in every Process() call.
                // otherwise we would get
                // "System.ArgumentException: Member ... is declared in another module and needs to be imported"
                // errors when still using the previous module's reader/writer funcs.
                writers = new Writers(CurrentAssembly, weaverTypes, GeneratedCodeClass, Log);
                readers = new Readers(CurrentAssembly, weaverTypes, GeneratedCodeClass, Log);

                Stopwatch rwstopwatch = Stopwatch.StartNew();
                // Need to track modified from ReaderWriterProcessor too because it could find custom read/write functions or create functions for NetworkMessages
                modified = ReaderWriterProcessor.Process(CurrentAssembly, resolver, Log, writers, readers, ref WeavingFailed);
                rwstopwatch.Stop();
                Console.WriteLine($"Find all reader and writers took {rwstopwatch.ElapsedMilliseconds} milliseconds");

                ModuleDefinition moduleDefinition = CurrentAssembly.MainModule;
                Console.WriteLine($"Script Module: {moduleDefinition.Name}");

                modified |= WeaveModule(moduleDefinition);

                if (WeavingFailed)
                {
                    return(false);
                }

                if (modified)
                {
                    PropertySiteProcessor.Process(moduleDefinition, weaverLists);

                    // add class that holds read/write functions
                    moduleDefinition.Types.Add(GeneratedCodeClass);

                    ReaderWriterProcessor.InitializeReaderAndWriters(CurrentAssembly, weaverTypes, writers, readers, GeneratedCodeClass);

                    // DO NOT WRITE here.
                    // CompilationFinishedHook writes to the file.
                    // ILPostProcessor writes to in-memory assembly.
                    // it depends on the caller.
                    //CurrentAssembly.Write(new WriterParameters{ WriteSymbols = true });
                }

                return(true);
            }
            catch (Exception e)
            {
                Log.Error("Exception :" + e);
                WeavingFailed = true;
                return(false);
            }
        }
Beispiel #15
0
        static bool Weave(string assName, IEnumerable <string> dependencies)
        {
            using (DefaultAssemblyResolver asmResolver = new DefaultAssemblyResolver())
                using (CurrentAssembly = AssemblyDefinition.ReadAssembly(assName, new ReaderParameters {
                    ReadWrite = true, ReadSymbols = true, AssemblyResolver = asmResolver
                }))
                {
                    asmResolver.AddSearchDirectory(Path.GetDirectoryName(assName));
                    asmResolver.AddSearchDirectory(Helpers.UnityEngineDllDirectoryName());
                    if (dependencies != null)
                    {
                        foreach (string path in dependencies)
                        {
                            asmResolver.AddSearchDirectory(path);
                        }
                    }

                    // fix "No writer found for ..." error
                    // https://github.com/vis2k/Mirror/issues/2579
                    // -> when restarting Unity, weaver would try to weave a DLL
                    //    again
                    // -> resulting in two GeneratedNetworkCode classes (see ILSpy)
                    // -> the second one wouldn't have all the writer types setup
                    if (ContainsGeneratedCodeClass(CurrentAssembly.MainModule))
                    {
                        //Log.Warning($"Weaver: skipping {CurrentAssembly.Name} because already weaved");
                        return(true);
                    }

                    WeaverTypes.SetupTargetTypes(CurrentAssembly);

                    CreateGeneratedCodeClass();

                    // WeaverList depends on WeaverTypes setup because it uses Import
                    WeaveLists = new WeaverLists();

                    System.Diagnostics.Stopwatch rwstopwatch = System.Diagnostics.Stopwatch.StartNew();
                    // Need to track modified from ReaderWriterProcessor too because it could find custom read/write functions or create functions for NetworkMessages
                    bool modified = ReaderWriterProcessor.Process(CurrentAssembly);
                    rwstopwatch.Stop();
                    Console.WriteLine($"Find all reader and writers took {rwstopwatch.ElapsedMilliseconds} milliseconds");

                    ModuleDefinition moduleDefinition = CurrentAssembly.MainModule;
                    Console.WriteLine($"Script Module: {moduleDefinition.Name}");

                    modified |= WeaveModule(moduleDefinition);

                    if (WeavingFailed)
                    {
                        return(false);
                    }

                    if (modified)
                    {
                        PropertySiteProcessor.Process(moduleDefinition);

                        // add class that holds read/write functions
                        moduleDefinition.Types.Add(GeneratedCodeClass);

                        ReaderWriterProcessor.InitializeReaderAndWriters(CurrentAssembly);

                        // write to outputDir if specified, otherwise perform in-place write
                        WriterParameters writeParams = new WriterParameters {
                            WriteSymbols = true
                        };
                        CurrentAssembly.Write(writeParams);
                    }
                }

            return(true);
        }