Weaver: pass AssemblyResolver to Weave() so ReaderWriterProcessor can resolve Mirror.dll from CurrentAssembly's References instead of passing the AssemblyDefinition / using reflection / opening the file from Weaver / etc.

-> prepares for ILPostProcessor which needs to use the resolver to find it
This commit is contained in:
vis2k 2021-08-23 19:03:40 +08:00
parent 5d629b0fb7
commit 7088938bb7
4 changed files with 56 additions and 15 deletions

View File

@ -12,6 +12,7 @@ namespace Mirror.Weaver
{
public static class CompilationFinishedHook
{
// needs to be the same as Weaver.MirrorAssemblyName!
const string MirrorRuntimeAssemblyName = "Mirror";
const string MirrorWeaverAssemblyName = "Mirror.Weaver";
@ -150,9 +151,6 @@ static HashSet<string> GetDependecyPaths(string assemblyPath)
// file path, with dependencies added.
static bool WeaveFromFile(string assemblyPath, string[] dependencies, string mirrorAssemblyPath)
{
// resolve mirror assembly
using (DefaultAssemblyResolver mirrorAsmResolver = new DefaultAssemblyResolver())
using (AssemblyDefinition mirrorAssembly = AssemblyDefinition.ReadAssembly(mirrorAssemblyPath, new ReaderParameters { ReadWrite = false, ReadSymbols = false, AssemblyResolver = mirrorAsmResolver }))
// open the assembly file as stream
using (FileStream stream = new FileStream(assemblyPath, FileMode.Open, FileAccess.ReadWrite))
// resolve assembly from stream
@ -174,7 +172,7 @@ static bool WeaveFromFile(string assemblyPath, string[] dependencies, string mir
// create weaver with logger
weaver = new Weaver(new CompilationFinishedLogger());
return weaver.Weave(assembly, mirrorAssembly);
return weaver.Weave(assembly, asmResolver);
}
}
}

View File

@ -244,5 +244,16 @@ public static IEnumerable<FieldDefinition> FindAllPublicFields(this TypeDefiniti
public static bool ContainsClass(this ModuleDefinition module, string nameSpace, string className) =>
module.GetTypes().Any(td => td.Namespace == nameSpace &&
td.Name == className);
public static AssemblyNameReference FindReference(this ModuleDefinition module, string referenceName)
{
foreach (AssemblyNameReference reference in module.AssemblyReferences)
{
if (reference.Name == referenceName)
return reference;
}
return null;
}
}
}

View File

@ -10,18 +10,40 @@ namespace Mirror.Weaver
{
public static class ReaderWriterProcessor
{
public static bool Process(AssemblyDefinition CurrentAssembly, AssemblyDefinition mirrorAssembly, Writers writers, Readers readers, ref bool WeavingFailed)
public static bool Process(AssemblyDefinition CurrentAssembly, IAssemblyResolver resolver, Logger Log, Writers writers, Readers readers, ref bool WeavingFailed)
{
// find NetworkReader/Writer extensions from Mirror.dll first.
// and NetworkMessage custom writer/reader extensions.
// NOTE: do not include this result in our 'modified' return value,
// otherwise Unity crashes when running tests
ProcessAssemblyClasses(CurrentAssembly, mirrorAssembly, writers, readers, ref WeavingFailed);
ProcessMirrorAssemblyClasses(CurrentAssembly, resolver, Log, writers, readers, ref WeavingFailed);
// find readers/writers in the assembly we are in right now.
return ProcessAssemblyClasses(CurrentAssembly, CurrentAssembly, writers, readers, ref WeavingFailed);
}
static void ProcessMirrorAssemblyClasses(AssemblyDefinition CurrentAssembly, IAssemblyResolver resolver, Logger Log, Writers writers, Readers readers, ref bool WeavingFailed)
{
// find Mirror.dll in assembly's references.
// those are guaranteed to be resolvable and correct.
// after all, it references them :)
AssemblyNameReference mirrorAssemblyReference = CurrentAssembly.MainModule.FindReference(Weaver.MirrorAssemblyName);
if (mirrorAssemblyReference != null)
{
// resolve the assembly to load the AssemblyDefinition.
// we need to search all types in it.
// if we only were to resolve one known type like in WeaverTypes,
// then we wouldn't need it.
AssemblyDefinition mirrorAssembly = resolver.Resolve(mirrorAssemblyReference);
if (mirrorAssembly != null)
{
ProcessAssemblyClasses(CurrentAssembly, mirrorAssembly, writers, readers, ref WeavingFailed);
}
else Log.Error($"Failed to resolve {mirrorAssemblyReference}");
}
else Log.Error("Failed to find Mirror AssemblyNameReference. Can't register Mirror.dll readers/writers.");
}
static bool ProcessAssemblyClasses(AssemblyDefinition CurrentAssembly, AssemblyDefinition assembly, Writers writers, Readers readers, ref bool WeavingFailed)
{
bool modified = false;

View File

@ -15,10 +15,14 @@ internal class Weaver
public const string GeneratedCodeClassName = "GeneratedNetworkCode";
TypeDefinition GeneratedCodeClass;
// for resolving Mirror.dll in ReaderWriterProcessor, we need to know
// Mirror.dll name
public const string MirrorAssemblyName = "Mirror";
WeaverTypes weaverTypes;
WeaverLists weaverLists;
IAssemblyResolver Resolver;
AssemblyDefinition CurrentAssembly;
AssemblyDefinition MirrorAssembly;
Writers writers;
Readers readers;
bool WeavingFailed;
@ -117,18 +121,24 @@ void CreateGeneratedCodeClass()
// new uses ...?
//
// => assembly: the one we are currently weaving (MyGame.dll)
// => mirrorAssembly: the Mirror.dll assembly. sometimes needed to find
// all extensions in Mirror.dll etc. while we can resolve known types
// in other assemblys, we can't search unknown types in another
// assembly without opening it.
// (weaver shouldn't worry about opening. it should simply weave)
public bool Weave(AssemblyDefinition assembly, AssemblyDefinition mirrorAssembly)
// => 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)
{
WeavingFailed = false;
try
{
Resolver = resolver;
CurrentAssembly = assembly;
MirrorAssembly = mirrorAssembly;
// fix "No writer found for ..." error
// https://github.com/vis2k/Mirror/issues/2579
@ -160,7 +170,7 @@ public bool Weave(AssemblyDefinition assembly, AssemblyDefinition mirrorAssembly
Stopwatch rwstopwatch = 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, mirrorAssembly, writers, readers, ref WeavingFailed);
bool modified = ReaderWriterProcessor.Process(CurrentAssembly, resolver, Log, writers, readers, ref WeavingFailed);
rwstopwatch.Stop();
Console.WriteLine($"Find all reader and writers took {rwstopwatch.ElapsedMilliseconds} milliseconds");