Esempio n. 1
0
        // 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
            {
                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
                syncVarAccessLists = new SyncVarAccessLists();

                // 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)
                {
                    SyncVarAttributeAccessReplacer.Process(moduleDefinition, syncVarAccessLists);

                    // 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);
            }
        }
Esempio n. 2
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);
        }