diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 9e121fbd8c..b7e3070241 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -23,6 +23,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Fixed +- Issue where the IL post-processor could not resolve core library types, such as `Guid` and `List`, in assemblies compiled against .NET reference assemblies, for example when targeting .NET 10. Those split the core library across `System.Runtime`, `System.Collections` and other assemblies. - Fixed issue where a prefab added to a `NetworkPrefabsList` while a session was running was registered more than once and logged a duplicate `GlobalObjectIdHash` error. (#4184) - Issue where moving a `NetworkObject` into another scene made the clients that did not observe it log "Trying to synchronize NetworkObjectId but it was not spawned". The scene migration is now only sent to the clients that observe the `NetworkObject`. (#4176) - Issue where a `NetworkObject` that was moved into another scene while hidden from a client spawned in that client's active scene when it was shown with `NetworkShow`, instead of the scene it is in on the server. (#4176) diff --git a/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporter.cs b/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporter.cs index 7c904750f5..f2acea3bd7 100644 --- a/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporter.cs +++ b/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporter.cs @@ -1,3 +1,5 @@ +using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; using Mono.Cecil; @@ -8,15 +10,74 @@ internal class PostProcessorReflectionImporter : DefaultReflectionImporter { private const string k_SystemPrivateCoreLib = "System.Private.CoreLib"; private readonly AssemblyNameReference m_CorrectCorlib; + private readonly Dictionary m_CorlibTypeScopes = new Dictionary(); public PostProcessorReflectionImporter(ModuleDefinition module) : base(module) { m_CorrectCorlib = module.AssemblyReferences.FirstOrDefault(a => a.Name == "mscorlib" || a.Name == "netstandard" || a.Name == k_SystemPrivateCoreLib); } + // .NET reference packs split System.Private.CoreLib across System.Runtime, System.Collections and others, + // so a module that references none of the assemblies above needs the one that defines or forwards the type. + protected override IMetadataScope ImportScope(Type type) + { + if (m_CorrectCorlib == null && type.Assembly.GetName().Name == k_SystemPrivateCoreLib) + { + var outermost = type; + while (outermost.DeclaringType != null) + { + outermost = outermost.DeclaringType; + } + + var reference = FindReferenceDefining(outermost.FullName); + if (reference != null) + { + return reference; + } + } + + return base.ImportScope(type); + } + public override AssemblyNameReference ImportReference(AssemblyName reference) { return m_CorrectCorlib != null && reference.Name == k_SystemPrivateCoreLib ? m_CorrectCorlib : base.ImportReference(reference); } + + private AssemblyNameReference FindReferenceDefining(string fullName) + { + if (m_CorlibTypeScopes.TryGetValue(fullName, out var cached)) + { + return cached; + } + + AssemblyNameReference found = null; + foreach (var reference in module.AssemblyReferences) + { + AssemblyDefinition assembly; + try + { + assembly = module.AssemblyResolver.Resolve(reference); + } + catch (AssemblyResolutionException) + { + continue; + } + + if (assembly == null) + { + continue; + } + + if (assembly.MainModule.GetType(fullName) != null || assembly.MainModule.ExportedTypes.Any(t => t.FullName == fullName)) + { + found = reference; + break; + } + } + + m_CorlibTypeScopes[fullName] = found; + return found; + } } }