static MethodDefinition GenerateCollectionWriter(TypeReference variable, TypeReference elementType, string writerFunction) { MethodDefinition writerFunc = GenerateWriterFunc(variable); MethodReference elementWriteFunc = GetWriteFunc(elementType); MethodReference intWriterFunc = GetWriteFunc(WeaverTypes.Import <int>()); // need this null check till later PR when GetWriteFunc throws exception instead if (elementWriteFunc == null) { Weaver.Error($"Cannot generate writer for {variable}. Use a supported type or provide a custom writer", variable); return(writerFunc); } ModuleDefinition module = Weaver.CurrentAssembly.MainModule; TypeReference readerExtensions = module.ImportReference(typeof(NetworkWriterExtensions)); MethodReference collectionWriter = Resolvers.ResolveMethod(readerExtensions, Weaver.CurrentAssembly, writerFunction); GenericInstanceMethod methodRef = new GenericInstanceMethod(collectionWriter); methodRef.GenericArguments.Add(elementType); // generates // reader.WriteArray<T>(array); ILProcessor worker = writerFunc.Body.GetILProcessor(); worker.Emit(OpCodes.Ldarg_0); // writer worker.Emit(OpCodes.Ldarg_1); // collection worker.Emit(OpCodes.Call, methodRef); // WriteArray worker.Emit(OpCodes.Ret); return(writerFunc); }
static void WriteNullCheck(ILProcessor worker) { // if (value == null) // { // writer.WriteBoolean(false); // return; // } // Instruction labelNotNull = worker.Create(OpCodes.Nop); worker.Emit(OpCodes.Ldarg_1); worker.Emit(OpCodes.Brtrue, labelNotNull); worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldc_I4_0); worker.Emit(OpCodes.Call, GetWriteFunc(WeaverTypes.Import <bool>())); worker.Emit(OpCodes.Ret); worker.Append(labelNotNull); // write.WriteBoolean(true); worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldc_I4_1); worker.Emit(OpCodes.Call, GetWriteFunc(WeaverTypes.Import <bool>())); }
static MethodDefinition GenerateReaderFunction(TypeReference variable) { string functionName = "_Read_" + variable.FullName; // create new reader for this type MethodDefinition readerFunc = new MethodDefinition(functionName, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, variable); readerFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, WeaverTypes.Import <NetworkReader>())); readerFunc.Body.InitLocals = true; RegisterReadFunc(variable, readerFunc); return(readerFunc); }
static MethodDefinition GenerateWriterFunc(TypeReference variable) { string functionName = "_Write_" + variable.FullName; // create new writer for this type MethodDefinition writerFunc = new MethodDefinition(functionName, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, WeaverTypes.Import(typeof(void))); writerFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, WeaverTypes.Import <NetworkWriter>())); writerFunc.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.None, variable)); writerFunc.Body.InitLocals = true; RegisterWriteFunc(variable, writerFunc); return(writerFunc); }
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); }