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); } } }
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); }
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); }
public SyncVarProcessor(AssemblyDefinition assembly, WeaverTypes weaverTypes, WeaverLists weaverLists, Logger Log) { this.assembly = assembly; this.weaverTypes = weaverTypes; this.weaverLists = weaverLists; this.Log = Log; }
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); } }
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)); }
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); } }
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); } }
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); }