diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index 564c53801..304270b34 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -1626,7 +1626,9 @@ namespace FlaxEngine.Interop // We need private types of this assembly too, DefinedTypes contains a lot of types from other assemblies... var types = referencedTypes.Any() ? assembly.DefinedTypes.Where(x => !referencedTypes.Contains(x.FullName)).ToArray() : assembly.DefinedTypes.ToArray(); +#if FLAX_EDITOR Assert.IsTrue(Utils.GetAssemblies().Count(x => x.GetName().Name == "FlaxEngine.CSharp") == 1); +#endif return types; } diff --git a/Source/Engine/Scripting/ManagedCLR/MAssembly.h b/Source/Engine/Scripting/ManagedCLR/MAssembly.h index 0a785c06a..59d6d5360 100644 --- a/Source/Engine/Scripting/ManagedCLR/MAssembly.h +++ b/Source/Engine/Scripting/ManagedCLR/MAssembly.h @@ -38,6 +38,7 @@ private: mutable int32 _hasCachedClasses : 1; mutable ClassesDictionary _classes; + mutable ClassesDictionary _typeClasses; int32 _reloadCount; StringAnsi _name; @@ -234,6 +235,11 @@ public: /// const ClassesDictionary& GetClasses() const; + /// + /// Gets the classes lookup cache that includes runtime-cached types. Non-stable to iterate over due to dynamic types caching. + /// + ClassesDictionary& GetTypeClasses() const; + private: bool LoadCorlib(); bool LoadImage(const String& assemblyPath, const StringView& nativePath); diff --git a/Source/Engine/Scripting/ManagedCLR/MCore.cpp b/Source/Engine/Scripting/ManagedCLR/MCore.cpp index 6fa499002..5f20b3881 100644 --- a/Source/Engine/Scripting/ManagedCLR/MCore.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MCore.cpp @@ -142,7 +142,8 @@ void MAssembly::Unload(bool isReloading) _isLoaded = false; _hasCachedClasses = false; #if USE_NETCORE - ArenaAllocator::ClearDelete(_classes); + ArenaAllocator::ClearDelete(_typeClasses); + _classes.Clear(); #else _classes.ClearDelete(); #endif diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index 65dd09b44..0c1901e4b 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -355,7 +355,7 @@ void MCore::UnloadScriptingAssemblyLoadContext() MAssembly* a = e.Value; if (!a->IsLoaded() || !a->_hasCachedClasses) continue; - for (const auto& q : a->GetClasses()) + for (const auto& q : a->GetTypeClasses()) { MClass* c = q.Value; c->_hasCachedAttributes = false; @@ -781,6 +781,7 @@ const MAssembly::ClassesDictionary& MAssembly::GetClasses() const MCore::GC::FreeMemory((void*)managedClasses[i].fullname); MCore::GC::FreeMemory((void*)managedClasses[i].namespace_); } + _typeClasses = _classes; static void* RegisterManagedClassNativePointersPtr = GetStaticMethodPointer(TEXT("RegisterManagedClassNativePointers")); CallStaticMethod(RegisterManagedClassNativePointersPtr, &managedClasses, classCount); @@ -799,6 +800,12 @@ const MAssembly::ClassesDictionary& MAssembly::GetClasses() const return _classes; } +MAssembly::ClassesDictionary& MAssembly::GetTypeClasses() const +{ + GetClasses(); + return _typeClasses; +} + void GetAssemblyName(void* assemblyHandle, StringAnsi& name, StringAnsi& fullname) { static void* GetAssemblyNamePtr = GetStaticMethodPointer(TEXT("GetAssemblyName")); @@ -828,7 +835,7 @@ DEFINE_INTERNAL_CALL(void) NativeInterop_CreateClass(NativeClassDefinitions* man MClass* klass = assembly->Memory.New(assembly, managedClass->typeHandle, managedClass->name, managedClass->fullname, managedClass->namespace_, managedClass->typeAttributes); if (assembly != nullptr) { - auto& classes = const_cast(assembly->GetClasses()); + auto& classes = assembly->GetTypeClasses(); MClass* oldKlass; if (classes.TryGet(klass->GetFullName(), oldKlass)) { @@ -1746,7 +1753,7 @@ MClass* GetOrCreateClass(MType* typeHandle) klass = assembly->Memory.New(assembly, classInfo.typeHandle, classInfo.name, classInfo.fullname, classInfo.namespace_, classInfo.typeAttributes); if (assembly != nullptr) { - auto& classes = const_cast(assembly->GetClasses()); + auto& classes = assembly->GetTypeClasses(); if (classes.ContainsKey(klass->GetFullName())) { LOG(Warning, "Class '{0}' was already added to assembly '{1}'", String(klass->GetFullName()), String(assembly->GetName())); diff --git a/Source/Engine/Scripting/Runtime/Mono.cpp b/Source/Engine/Scripting/Runtime/Mono.cpp index 1449d405f..f32d12c57 100644 --- a/Source/Engine/Scripting/Runtime/Mono.cpp +++ b/Source/Engine/Scripting/Runtime/Mono.cpp @@ -1091,6 +1091,11 @@ const MAssembly::ClassesDictionary& MAssembly::GetClasses() const return _classes; } +const MAssembly::ClassesDictionary& MAssembly::GetTypeClasses() const +{ + return GetClasses(); +} + bool MAssembly::Load(MonoImage* monoImage) { if (IsLoaded()) diff --git a/Source/Engine/Scripting/Runtime/None.cpp b/Source/Engine/Scripting/Runtime/None.cpp index 178e98444..87ec35ac0 100644 --- a/Source/Engine/Scripting/Runtime/None.cpp +++ b/Source/Engine/Scripting/Runtime/None.cpp @@ -303,6 +303,11 @@ const MAssembly::ClassesDictionary& MAssembly::GetClasses() const return _classes; } +const MAssembly::ClassesDictionary& MAssembly::GetTypeClasses() const +{ + return GetClasses(); +} + bool MAssembly::LoadCorlib() { return false;