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; } }
static bool WeaveModule(ModuleDefinition moduleDefinition) { try { bool modified = false; var watch = System.Diagnostics.Stopwatch.StartNew(); watch.Start(); foreach (TypeDefinition td in moduleDefinition.Types) { if (td.IsClass && td.BaseType.CanBeResolved()) { modified |= WeaveNetworkBehavior(td); modified |= ServerClientAttributeProcessor.Process(td); } } watch.Stop(); Console.WriteLine("Weave behaviours and messages took" + watch.ElapsedMilliseconds + " milliseconds"); if (modified) { PropertySiteProcessor.Process(moduleDefinition); } return(modified); } catch (Exception ex) { Error(ex.ToString()); throw new Exception(ex.Message, ex); } }
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; }
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 bool WeaveModule(ModuleDefinition moduleDefinition) { try { bool modified = false; // We need to do 2 passes, because SyncListStructs might be referenced from other modules, so we must make sure we generate them first. System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew(); foreach (TypeDefinition td in moduleDefinition.Types) { if (td.IsClass && td.BaseType.CanBeResolved()) { modified |= WeaveSyncObject(td); } } watch.Stop(); Console.WriteLine("Weave sync objects took " + watch.ElapsedMilliseconds + " milliseconds"); watch.Start(); foreach (TypeDefinition td in moduleDefinition.Types) { if (td.IsClass && td.BaseType.CanBeResolved()) { modified |= WeaveNetworkBehavior(td); modified |= WeaveMessage(td); modified |= ServerClientAttributeProcessor.Process(td); } } watch.Stop(); Console.WriteLine("Weave behaviours and messages took" + watch.ElapsedMilliseconds + " milliseconds"); if (modified) { PropertySiteProcessor.Process(moduleDefinition); } return(modified); } catch (Exception ex) { Error(ex.ToString()); throw new Exception(ex.Message, ex); } }
private AssemblyDefinition Weave(string compiledAssembly) { try { CurrentAssembly = AssemblyDefinition.ReadAssembly(compiledAssembly); var module = CurrentAssembly.MainModule; readers = new Readers(module, logger); writers = new Writers(module, logger); var rwstopwatch = 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(); Directory.CreateDirectory(Path.GetDirectoryName(compiledAssembly) + "\\weave\\"); CurrentAssembly.Write(Path.GetDirectoryName(compiledAssembly) + "\\weave\\" + Path.GetFileName(compiledAssembly)); return CurrentAssembly; } catch (Exception e) { logger.Error("Exception :" + e.StackTrace); return null; } #endif }
static bool Weave(string assName, AssemblyDefinition unityAssembly, AssemblyDefinition mirrorAssembly, IEnumerable <string> dependencies, string unityEngineDLLPath, string mirrorNetDLLPath, string outputDir) { 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()); asmResolver.AddSearchDirectory(Path.GetDirectoryName(unityEngineDLLPath)); asmResolver.AddSearchDirectory(Path.GetDirectoryName(mirrorNetDLLPath)); if (dependencies != null) { foreach (string path in dependencies) { asmResolver.AddSearchDirectory(path); } } WeaverTypes.SetupTargetTypes(unityAssembly, mirrorAssembly, CurrentAssembly); System.Diagnostics.Stopwatch rwstopwatch = System.Diagnostics.Stopwatch.StartNew(); ReaderWriterProcessor.Process(CurrentAssembly); rwstopwatch.Stop(); Console.WriteLine("Find all reader and writers took " + rwstopwatch.ElapsedMilliseconds + " milliseconds"); ModuleDefinition moduleDefinition = CurrentAssembly.MainModule; Console.WriteLine("Script Module: {0}", moduleDefinition.Name); bool modified = WeaveModule(moduleDefinition); if (WeavingFailed) { return(false); } if (modified) { // this must be done for ALL code, not just NetworkBehaviours try { PropertySiteProcessor.Process(moduleDefinition); } catch (Exception e) { Log.Error("ProcessPropertySites exception: " + e); return(false); } if (WeavingFailed) { return(false); } // write to outputDir if specified, otherwise perform in-place write WriterParameters writeParams = new WriterParameters { WriteSymbols = true }; if (!string.IsNullOrEmpty(outputDir)) { CurrentAssembly.Write(Helpers.DestinationFileFor(outputDir, assName), writeParams); } else { CurrentAssembly.Write(writeParams); } } } return(true); }
static bool Weave(string assName, IEnumerable <string> dependencies, IAssemblyResolver assemblyResolver, string unityEngineDLLPath, string mirrorNetDLLPath, string outputDir) { 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()); asmResolver.AddSearchDirectory(Path.GetDirectoryName(unityEngineDLLPath)); asmResolver.AddSearchDirectory(Path.GetDirectoryName(mirrorNetDLLPath)); if (dependencies != null) { foreach (string path in dependencies) { asmResolver.AddSearchDirectory(path); } } SetupTargetTypes(); Readers.Init(CurrentAssembly); Writers.Init(CurrentAssembly); ModuleDefinition moduleDefinition = CurrentAssembly.MainModule; Console.WriteLine("Script Module: {0}", moduleDefinition.Name); // Process each NetworkBehaviour bool didWork = false; // We need to do 2 passes, because SyncListStructs might be referenced from other modules, so we must make sure we generate them first. for (int pass = 0; pass < 2; pass++) { System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew(); foreach (TypeDefinition td in moduleDefinition.Types) { if (td.IsClass && td.BaseType.CanBeResolved()) { try { if (pass == 0) { didWork |= CheckSyncList(td); } else { didWork |= CheckNetworkBehaviour(td); didWork |= CheckMessageBase(td); } } catch (Exception ex) { Weaver.Error(ex.Message); throw ex; } } if (WeavingFailed) { return(false); } } watch.Stop(); Console.WriteLine("Pass: "******" took " + watch.ElapsedMilliseconds + " milliseconds"); } if (didWork) { // this must be done for ALL code, not just NetworkBehaviours try { PropertySiteProcessor.ProcessSitesModule(CurrentAssembly.MainModule); } catch (Exception e) { Log.Error("ProcessPropertySites exception: " + e); return(false); } if (WeavingFailed) { //Log.Error("Failed phase II."); return(false); } // write to outputDir if specified, otherwise perform in-place write WriterParameters writeParams = new WriterParameters { WriteSymbols = true }; if (outputDir != null) { CurrentAssembly.Write(Helpers.DestinationFileFor(outputDir, assName), writeParams); } else { CurrentAssembly.Write(writeParams); } } } return(true); }
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); }
static bool Weave(string assName, IEnumerable <string> dependencies, IAssemblyResolver assemblyResolver, string unityEngineDLLPath, string mirrorNetDLLPath, string outputDir) { ReaderParameters readParams = Helpers.ReaderParameters(assName, dependencies, assemblyResolver, unityEngineDLLPath, mirrorNetDLLPath); using (CurrentAssembly = AssemblyDefinition.ReadAssembly(assName, readParams)) { SetupTargetTypes(); Readers.Init(CurrentAssembly); Writers.Init(CurrentAssembly); ModuleDefinition moduleDefinition = CurrentAssembly.MainModule; Console.WriteLine("Script Module: {0}", moduleDefinition.Name); // Process each NetworkBehaviour bool didWork = false; // We need to do 2 passes, because SyncListStructs might be referenced from other modules, so we must make sure we generate them first. for (int pass = 0; pass < 2; pass++) { System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew(); foreach (TypeDefinition td in moduleDefinition.Types) { if (td.IsClass && td.BaseType.CanBeResolved()) { try { if (pass == 0) { didWork |= CheckSyncList(td); } else { didWork |= CheckNetworkBehaviour(td); didWork |= CheckMessageBase(td); } } catch (Exception ex) { if (CurrentAssembly.MainModule.SymbolReader != null) { CurrentAssembly.MainModule.SymbolReader.Dispose(); } Weaver.Error(ex.Message); throw ex; } } if (WeavingFailed) { if (CurrentAssembly.MainModule.SymbolReader != null) { CurrentAssembly.MainModule.SymbolReader.Dispose(); } return(false); } } watch.Stop(); Console.WriteLine("Pass: "******" took " + watch.ElapsedMilliseconds + " milliseconds"); } if (didWork) { // this must be done for ALL code, not just NetworkBehaviours try { PropertySiteProcessor.ProcessSitesModule(CurrentAssembly.MainModule); } catch (Exception e) { Log.Error("ProcessPropertySites exception: " + e); if (CurrentAssembly.MainModule.SymbolReader != null) { CurrentAssembly.MainModule.SymbolReader.Dispose(); } return(false); } if (WeavingFailed) { //Log.Error("Failed phase II."); if (CurrentAssembly.MainModule.SymbolReader != null) { CurrentAssembly.MainModule.SymbolReader.Dispose(); } return(false); } string dest = Helpers.DestinationFileFor(outputDir, assName); //Console.WriteLine ("Output:" + dest); WriterParameters writeParams = Helpers.GetWriterParameters(readParams); CurrentAssembly.Write(dest, writeParams); } if (CurrentAssembly.MainModule.SymbolReader != null) { CurrentAssembly.MainModule.SymbolReader.Dispose(); } } return(true); }
// 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); } }
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); }