From 97a9e7a598b05d90f4a6a39bd6ce87d34dc89dc8 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 11 Sep 2026 23:14:34 +0200 Subject: [PATCH] Tolerate unloadable types in ServerShared reflection scans CultCache discovers DatabaseEntry types by scanning every loaded assembly. Outside Unity, plugin assemblies that reference UnityEngine throw ReflectionTypeLoadException and took the whole scan down; keep the types that do load. Also fix GetAllGenericChildClasses reading and writing the ChildClasses cache instead of its own. Co-Authored-By: Claude Opus 5 --- .../CultCache/ReflectionExtensions.cs | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Assets/Scripts/ServerShared/CultCache/ReflectionExtensions.cs b/Assets/Scripts/ServerShared/CultCache/ReflectionExtensions.cs index cdc04824b..8e3468194 100644 --- a/Assets/Scripts/ServerShared/CultCache/ReflectionExtensions.cs +++ b/Assets/Scripts/ServerShared/CultCache/ReflectionExtensions.cs @@ -8,13 +8,23 @@ using System.Threading.Tasks; public static class ReflectionExtensions { + // Every type that can be loaded from every assembly in the domain. An assembly whose dependencies are missing + // (a Unity plugin referencing UnityEngine when running outside Unity) still yields the types that do load. + private static IEnumerable LoadableTypes() + { + return AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => + { + try { return assembly.GetTypes(); } + catch (ReflectionTypeLoadException e) { return e.Types.Where(t => t != null); } + }); + } + private static Dictionary InterfaceClasses = new Dictionary(); public static Type[] GetAllInterfaceClasses(this Type type) { if (InterfaceClasses.ContainsKey(type)) return InterfaceClasses[type]; - return InterfaceClasses[type] = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(ass => ass.GetTypes()).Where(t => t.IsClass && t.GetInterfaces().Contains(type)).ToArray(); + return InterfaceClasses[type] = LoadableTypes().Where(t => t.IsClass && t.GetInterfaces().Contains(type)).ToArray(); } private static Dictionary ParentTypes = new Dictionary(); @@ -56,17 +66,15 @@ public static class ReflectionExtensions { if (ChildClasses.ContainsKey(type)) return ChildClasses[type]; - return ChildClasses[type] = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(ass => ass.GetTypes()).Where(type.IsAssignableFrom).ToArray(); + return ChildClasses[type] = LoadableTypes().Where(type.IsAssignableFrom).ToArray(); } - + private static Dictionary GenericChildClasses = new Dictionary(); public static Type[] GetAllGenericChildClasses(this Type genericType) { if (GenericChildClasses.ContainsKey(genericType)) - return ChildClasses[genericType]; - return ChildClasses[genericType] = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(ass => ass.GetTypes()).Where(type=>type.IsAssignableToGenericType(genericType)).ToArray(); + return GenericChildClasses[genericType]; + return GenericChildClasses[genericType] = LoadableTypes().Where(type=>type.IsAssignableToGenericType(genericType)).ToArray(); } public static bool IsAssignableToGenericType(this Type givenType, Type genericType)