Skip to content

Commit dc67db2

Browse files
authored
Merge pull request #1 from pepoipod/SplitReaderWriterGenPhase
Merge upstream PR MirrorNetworking#4112: Split custom R/W gen & register process
2 parents 29e6f72 + 5f0ed9b commit dc67db2

1 file changed

Lines changed: 57 additions & 20 deletions

File tree

Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,49 @@ public static class ReaderWriterProcessor
1212
{
1313
public static bool Process(AssemblyDefinition CurrentAssembly, IAssemblyResolver resolver, Logger Log, Writers writers, Readers readers, ref bool WeavingFailed)
1414
{
15-
// find NetworkReader/Writer extensions from Mirror.dll first.
16-
// and NetworkMessage custom writer/reader extensions.
17-
// NOTE: do not include this result in our 'modified' return value,
15+
// Process in two passes so that custom reader/writer registration
16+
// always completes before any NetworkMessage reader/writer is generated.
17+
//
18+
// With a single pass per assembly, a message assembly could be visited
19+
// before the assembly that declares a custom reader/writer for one of
20+
// the message's field types. The weaver would then generate a fallback
21+
// reader/writer for that type and cache it; the later custom registration
22+
// is ignored because a generated function is already registered. For a
23+
// reference type without public fields the fallback writer only emits the
24+
// null-flag byte, silently dropping the value. Registering all custom
25+
// readers/writers first makes the result independent of visit order.
26+
27+
// Mirror.dll is excluded from FindProcessTargetAssemblies, so resolve it
28+
// separately and feed it into both passes.
29+
AssemblyDefinition mirrorAssembly = ResolveMirrorAssembly(CurrentAssembly, resolver, Log);
30+
31+
// process dependencies, this way weaver can process types of other assemblies properly.
32+
// fixes: https://github.com/MirrorNetworking/Mirror/issues/2503
33+
List<AssemblyDefinition> assemblyReferences = FindProcessTargetAssemblies(CurrentAssembly, resolver)
34+
.Where(assembly => assembly != null && assembly != CurrentAssembly)
35+
.ToList();
36+
37+
// pass 1: register all declared custom readers/writers.
38+
// NOTE: do not include Mirror/referenced results in 'modified',
1839
// otherwise Unity crashes when running tests
19-
ProcessMirrorAssemblyClasses(CurrentAssembly, resolver, Log, writers, readers, ref WeavingFailed);
40+
if (mirrorAssembly != null)
41+
RegisterDeclaredReadersWriters(CurrentAssembly, mirrorAssembly, writers, readers);
2042

21-
// process dependencies first, this way weaver can process types of other assemblies properly.
22-
// fixes: https://github.com/MirrorNetworking/Mirror/issues/2503
23-
//
24-
// find NetworkReader/Writer extensions in referenced assemblies
25-
IEnumerable<AssemblyDefinition> assemblyReferences = FindProcessTargetAssemblies(CurrentAssembly, resolver)
26-
.Where(assembly => assembly != null && assembly != CurrentAssembly);
43+
foreach (AssemblyDefinition referencedAssembly in assemblyReferences)
44+
RegisterDeclaredReadersWriters(CurrentAssembly, referencedAssembly, writers, readers);
45+
46+
bool modified = RegisterDeclaredReadersWriters(CurrentAssembly, CurrentAssembly, writers, readers);
47+
48+
// pass 2: generate readers/writers for all NetworkMessages.
49+
if (mirrorAssembly != null)
50+
GenerateMessageReadersWriters(CurrentAssembly, mirrorAssembly, writers, readers, ref WeavingFailed);
2751

2852
foreach (AssemblyDefinition referencedAssembly in assemblyReferences)
29-
ProcessAssemblyClasses(CurrentAssembly, referencedAssembly, writers, readers, ref WeavingFailed);
53+
GenerateMessageReadersWriters(CurrentAssembly, referencedAssembly, writers, readers, ref WeavingFailed);
54+
55+
modified |= GenerateMessageReadersWriters(CurrentAssembly, CurrentAssembly, writers, readers, ref WeavingFailed);
3056

31-
return ProcessAssemblyClasses(CurrentAssembly, CurrentAssembly, writers, readers, ref WeavingFailed);
57+
return modified;
3258
}
3359

3460
// look for assembly instead of relying on CurrentAssembly.MainModule.
@@ -65,7 +91,10 @@ void ProcessAssembly(AssemblyDefinition current)
6591
}
6692
}
6793

68-
static void ProcessMirrorAssemblyClasses(AssemblyDefinition CurrentAssembly, IAssemblyResolver resolver, Logger Log, Writers writers, Readers readers, ref bool WeavingFailed)
94+
// resolve Mirror.dll's AssemblyDefinition. it is skipped by
95+
// FindProcessTargetAssemblies, so it has to be resolved separately
96+
// and fed into both passes.
97+
static AssemblyDefinition ResolveMirrorAssembly(AssemblyDefinition CurrentAssembly, IAssemblyResolver resolver, Logger Log)
6998
{
7099
// find Mirror.dll in assembly's references.
71100
// those are guaranteed to be resolvable and correct.
@@ -78,16 +107,17 @@ static void ProcessMirrorAssemblyClasses(AssemblyDefinition CurrentAssembly, IAs
78107
// if we only were to resolve one known type like in WeaverTypes,
79108
// then we wouldn't need it.
80109
AssemblyDefinition mirrorAssembly = resolver.Resolve(mirrorAssemblyReference);
81-
if (mirrorAssembly != null)
82-
{
83-
ProcessAssemblyClasses(CurrentAssembly, mirrorAssembly, writers, readers, ref WeavingFailed);
84-
}
85-
else Log.Error($"Failed to resolve {mirrorAssemblyReference}");
110+
if (mirrorAssembly == null)
111+
Log.Error($"Failed to resolve {mirrorAssemblyReference}");
112+
return mirrorAssembly;
86113
}
87-
else Log.Error("Failed to find Mirror AssemblyNameReference. Can't register Mirror.dll readers/writers.");
114+
115+
Log.Error("Failed to find Mirror AssemblyNameReference. Can't register Mirror.dll readers/writers.");
116+
return null;
88117
}
89118

90-
static bool ProcessAssemblyClasses(AssemblyDefinition CurrentAssembly, AssemblyDefinition assembly, Writers writers, Readers readers, ref bool WeavingFailed)
119+
// pass 1: register all declared custom reader/writer extension methods in 'assembly'.
120+
static bool RegisterDeclaredReadersWriters(AssemblyDefinition CurrentAssembly, AssemblyDefinition assembly, Writers writers, Readers readers)
91121
{
92122
bool modified = false;
93123
foreach (TypeDefinition klass in assembly.MainModule.Types)
@@ -101,7 +131,14 @@ static bool ProcessAssemblyClasses(AssemblyDefinition CurrentAssembly, AssemblyD
101131
modified |= LoadDeclaredReaders(CurrentAssembly, klass, readers);
102132
}
103133
}
134+
return modified;
135+
}
104136

137+
// pass 2: generate readers/writers for all NetworkMessages in 'assembly'.
138+
// must run after every custom reader/writer has been registered.
139+
static bool GenerateMessageReadersWriters(AssemblyDefinition CurrentAssembly, AssemblyDefinition assembly, Writers writers, Readers readers, ref bool WeavingFailed)
140+
{
141+
bool modified = false;
105142
foreach (TypeDefinition klass in assembly.MainModule.Types)
106143
{
107144
// if assembly has any network message then it is modified

0 commit comments

Comments
 (0)