From ff438a6219499946cad209bb13acd1da2c68cff4 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sat, 3 Dec 2022 20:45:11 +0200 Subject: [PATCH 1/4] Set default culture to InvariantCulture Fixes issues such as wrong decimal separator in floating point strings when used with parameterless .ToString() --- Source/Engine/Engine/NativeInterop.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index 34daf9fcf..6d1846512 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -797,6 +797,12 @@ namespace FlaxEngine hostExecutable = Marshal.PtrToStringUni(hostExecutableName); NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), InternalDllResolver); + // Change default culture to match with Mono runtime default culture + CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; + CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; + System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; + System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; + // TODO: benchmark collectible setting performance, maybe enable it only in editor builds? scriptingAssemblyLoadContext = new AssemblyLoadContext(null, true); From 551c58db4f93572b3111b8bea8309036b95b1e1a Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Tue, 13 Dec 2022 20:24:39 +0200 Subject: [PATCH 2/4] Fix incorrect array marshalling in few Editor methods --- Source/Editor/Editor.cs | 10 +++++----- Source/Editor/Managed/ManagedEditor.Internal.cpp | 14 ++++++++++---- .../Editor/Windows/Assets/CollisionDataWindow.cs | 2 +- Source/Editor/Windows/Assets/VisualScriptWindow.cs | 4 ++-- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index 9eeb4bb35..54ce17158 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -1554,7 +1554,7 @@ namespace FlaxEditor internal static partial bool Internal_CookMeshCollision(string path, CollisionDataType type, IntPtr model, int modelLodIndex, uint materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int convexVertexLimit); [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetCollisionWires", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] - internal static partial void Internal_GetCollisionWires(IntPtr collisionData, [MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), ConstantElementCount = 1)] out Float3[] triangles, [MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), ConstantElementCount = 1)] out int[] indices); + internal static partial void Internal_GetCollisionWires(IntPtr collisionData, [MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), CountElementName = "trianglesCount")] out Float3[] triangles, [MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), CountElementName = "indicesCount")] out int[] indices, out int trianglesCount, out int indicesCount); [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetEditorBoxWithChildren", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] internal static partial void Internal_GetEditorBoxWithChildren(IntPtr obj, out BoundingBox resultAsRef); @@ -1602,12 +1602,12 @@ namespace FlaxEditor internal static partial void Internal_RunVisualScriptBreakpointLoopTick(float deltaTime); [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetVisualScriptLocals", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] - [return: MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), ConstantElementCount = 1)] - internal static partial VisualScriptLocal[] Internal_GetVisualScriptLocals(); + [return: MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), CountElementName = "localsCount")] + internal static partial VisualScriptLocal[] Internal_GetVisualScriptLocals(out int localsCount); [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetVisualScriptStackFrames", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] - [return: MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), ConstantElementCount = 1)] - internal static partial VisualScriptStackFrame[] Internal_GetVisualScriptStackFrames(); + [return: MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), CountElementName = "stackFrameCount")] + internal static partial VisualScriptStackFrame[] Internal_GetVisualScriptStackFrames(out int stackFrameCount); [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetVisualScriptPreviousScopeFrame", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] internal static partial VisualScriptStackFrame Internal_GetVisualScriptPreviousScopeFrame(); diff --git a/Source/Editor/Managed/ManagedEditor.Internal.cpp b/Source/Editor/Managed/ManagedEditor.Internal.cpp index 11844b23c..144698b3f 100644 --- a/Source/Editor/Managed/ManagedEditor.Internal.cpp +++ b/Source/Editor/Managed/ManagedEditor.Internal.cpp @@ -419,7 +419,7 @@ public: return 0; int32 count = 0; - const int32 maxCount = outArraySize;//(int32)mono_array_length(*outMessages); + const int32 maxCount = outArraySize; byte* ptr = CachedLogData.Get(); byte* end = ptr + CachedLogData.Count(); @@ -798,7 +798,7 @@ public: #endif } - static void GetCollisionWires(CollisionData* collisionData, MonoArray** triangles, MonoArray** indices) + static void GetCollisionWires(CollisionData* collisionData, MonoArray** triangles, MonoArray** indices, int* trianglesCount, int* indicesCount) { SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetCollisionWires") if (!collisionData || collisionData->WaitForLoaded() || collisionData->GetOptions().Type == CollisionDataType::None) @@ -822,6 +822,8 @@ public: mono_array_set(*indices, int32, iI++, i + 1); mono_array_set(*indices, int32, iI++, i); } + *trianglesCount = debugLines.Count(); + *indicesCount = linesCount * 3; } static void GetEditorBoxWithChildren(Actor* obj, BoundingBox* result) @@ -960,10 +962,11 @@ public: int32 BoxId; }; - static MonoArray* GetVisualScriptLocals() + static MonoArray* GetVisualScriptLocals(int* localsCount) { SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetVisualScriptLocals") MonoArray* result = nullptr; + *localsCount = 0; const auto stack = VisualScripting::GetThreadStackTop(); if (stack && stack->Scope) { @@ -998,6 +1001,7 @@ public: local.ValueTypeName = MUtils::ToString(v.Value.Type.GetTypeName()); mono_array_set(result, VisualScriptLocalManaged, stack->Scope->Parameters.Length() + i, local); } + *localsCount = count; } return result; } @@ -1009,10 +1013,11 @@ public: int32 BoxId; }; - static MonoArray* GetVisualScriptStackFrames() + static MonoArray* GetVisualScriptStackFrames(int* stackFramesCount) { SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetVisualScriptStackFrames") MonoArray* result = nullptr; + *stackFramesCount = 0; const auto stack = VisualScripting::GetThreadStackTop(); if (stack) { @@ -1038,6 +1043,7 @@ public: s = s->PreviousFrame; count++; } + *stackFramesCount = count; } return result; } diff --git a/Source/Editor/Windows/Assets/CollisionDataWindow.cs b/Source/Editor/Windows/Assets/CollisionDataWindow.cs index 249aa916e..bd6d1ab3a 100644 --- a/Source/Editor/Windows/Assets/CollisionDataWindow.cs +++ b/Source/Editor/Windows/Assets/CollisionDataWindow.cs @@ -236,7 +236,7 @@ namespace FlaxEditor.Windows.Assets _collisionWiresModel = FlaxEngine.Content.CreateVirtualAsset(); _collisionWiresModel.SetupLODs(new[] { 1 }); } - Editor.Internal_GetCollisionWires(FlaxEngine.Object.GetUnmanagedPtr(Asset), out var triangles, out var indices); + Editor.Internal_GetCollisionWires(FlaxEngine.Object.GetUnmanagedPtr(Asset), out var triangles, out var indices, out var _, out var _); if (triangles != null && indices != null) _collisionWiresModel.LODs[0].Meshes[0].UpdateMesh(triangles, indices); else diff --git a/Source/Editor/Windows/Assets/VisualScriptWindow.cs b/Source/Editor/Windows/Assets/VisualScriptWindow.cs index 8c480fd04..de70ea1e2 100644 --- a/Source/Editor/Windows/Assets/VisualScriptWindow.cs +++ b/Source/Editor/Windows/Assets/VisualScriptWindow.cs @@ -818,7 +818,7 @@ namespace FlaxEditor.Windows.Assets var state = (BreakpointHangState)Editor.Instance.Simulation.BreakpointHangTag; if (state.Locals == null) { - state.Locals = Editor.Internal_GetVisualScriptLocals(); + state.Locals = Editor.Internal_GetVisualScriptLocals(out var _); Editor.Instance.Simulation.BreakpointHangTag = state; } return state; @@ -829,7 +829,7 @@ namespace FlaxEditor.Windows.Assets var state = (BreakpointHangState)Editor.Instance.Simulation.BreakpointHangTag; if (state.StackFrames == null) { - state.StackFrames = Editor.Internal_GetVisualScriptStackFrames(); + state.StackFrames = Editor.Internal_GetVisualScriptStackFrames(out var _); Editor.Instance.Simulation.BreakpointHangTag = state; } return state; From 84f8e3a4b4ead96198eb2a037ace848c5cd3b55b Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Tue, 13 Dec 2022 20:25:57 +0200 Subject: [PATCH 3/4] Fix crash when releasing scripting assembly --- Source/Editor/CustomEditors/CustomEditorsUtil.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Editor/CustomEditors/CustomEditorsUtil.cpp b/Source/Editor/CustomEditors/CustomEditorsUtil.cpp index a02ad1c4a..8eb9782bc 100644 --- a/Source/Editor/CustomEditors/CustomEditorsUtil.cpp +++ b/Source/Editor/CustomEditors/CustomEditorsUtil.cpp @@ -183,7 +183,11 @@ void OnAssemblyUnloading(MAssembly* assembly) // Remove entries with user classes for (auto i = Cache.Begin(); i.IsNotEnd(); ++i) { +#if USE_NETCORE + MonoClass* monoClass = mono_type_get_class(i->Key); +#else MonoClass* monoClass = (MonoClass*)(void*)i->Key; +#endif if (assembly->GetClass(monoClass)) { From b9f11298e81dc10d4ee96ac54c1828607d55ca50 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sun, 11 Dec 2022 13:54:12 +0200 Subject: [PATCH 4/4] Avoid pre-allocating custom attributes for managed types --- Source/Engine/Engine/NativeInterop.cs | 12 ++++++++++ Source/Engine/Scripting/DotNet/CoreCLR.h | 6 +++++ Source/Engine/Scripting/DotNet/MonoApi.cpp | 24 +++++++++++++++++++ Source/Engine/Scripting/ManagedCLR/MClass.cpp | 19 +++++++++++---- 4 files changed, 57 insertions(+), 4 deletions(-) diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index 6d1846512..841113c9b 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -1365,6 +1365,18 @@ namespace FlaxEngine *classAttributesCount = attributeTypes.Length; } + [UnmanagedCallersOnly] + internal static IntPtr GetCustomAttribute(IntPtr typeHandle, IntPtr attribHandle) + { + Type type = (Type)GCHandle.FromIntPtr(typeHandle).Target; + Type attribType = (Type)GCHandle.FromIntPtr(attribHandle).Target; + object attrib = type.GetCustomAttributes(false).FirstOrDefault(x => x.GetType() == attribType); + + if (attrib != null) + return GCHandle.ToIntPtr(GCHandle.Alloc(attrib, GCHandleType.Weak)); + return IntPtr.Zero; + } + [UnmanagedCallersOnly] internal static void GetClassInterfaces(IntPtr typeHandle, IntPtr* classInterfaces, int* classInterfacesCount) { diff --git a/Source/Engine/Scripting/DotNet/CoreCLR.h b/Source/Engine/Scripting/DotNet/CoreCLR.h index 2f9c2a753..d869beadc 100644 --- a/Source/Engine/Scripting/DotNet/CoreCLR.h +++ b/Source/Engine/Scripting/DotNet/CoreCLR.h @@ -4,6 +4,7 @@ #include #include "Engine/Core/Types/String.h" +#include "Engine/Core/Collections/Array.h" #include "Engine/Scripting/Types.h" #if defined(_WIN32) @@ -46,4 +47,9 @@ public: static gchandle NewGCHandleWeakref(void* obj, bool track_resurrection); static void* GetGCHandleTarget(const gchandle& gchandle); static void FreeGCHandle(const gchandle& gchandle); + + static bool HasCustomAttribute(void* klass, void* attribClass); + static bool HasCustomAttribute(void* klass); + static void* GetCustomAttribute(void* klass, void* attribClass); + static Array GetCustomAttributes(void* klass); }; diff --git a/Source/Engine/Scripting/DotNet/MonoApi.cpp b/Source/Engine/Scripting/DotNet/MonoApi.cpp index 2d290b65e..8409bd72a 100644 --- a/Source/Engine/Scripting/DotNet/MonoApi.cpp +++ b/Source/Engine/Scripting/DotNet/MonoApi.cpp @@ -587,6 +587,30 @@ const char* CoreCLR::GetClassFullname(void* klass) return ((CoreCLRClass*)klass)->GetFullname().Get(); } +bool CoreCLR::HasCustomAttribute(void* klass, void* attribClass) +{ + return CoreCLR::GetCustomAttribute(klass, attribClass) != nullptr; +} +bool CoreCLR::HasCustomAttribute(void* klass) +{ + return CoreCLR::GetCustomAttribute(klass, nullptr) != nullptr; +} +void* CoreCLR::GetCustomAttribute(void* klass, void* attribClass) +{ + return CoreCLR::CallStaticMethodInternal(TEXT("GetCustomAttribute"), ((CoreCLRClass*)klass)->GetTypeHandle(), ((CoreCLRClass*)attribClass)->GetTypeHandle()); +} +Array CoreCLR::GetCustomAttributes(void* klass) +{ + Array attrib = ((CoreCLRClass*)klass)->GetCustomAttributes(); + + Array attributes; + attributes.Resize(attrib.Count(), false); + for (int i = 0; i < attrib.Count(); i++) + attributes.Add(attrib[i]->GetHandle()); + + return attributes; +} + /* * loader.h */ diff --git a/Source/Engine/Scripting/ManagedCLR/MClass.cpp b/Source/Engine/Scripting/ManagedCLR/MClass.cpp index 53fe1b358..9475e78d6 100644 --- a/Source/Engine/Scripting/ManagedCLR/MClass.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MClass.cpp @@ -14,6 +14,9 @@ #include #define GET_CUSTOM_ATTR() (MonoCustomAttrInfo*)(_attrInfo ? _attrInfo : _attrInfo = mono_custom_attrs_from_class(_monoClass)) #endif +#if USE_NETCORE +#include "Engine/Scripting/DotNet/CoreCLR.h" +#endif #if USE_MONO MClass::MClass(const MAssembly* parentAssembly, MonoClass* monoClass, const MString& fullname) @@ -375,7 +378,9 @@ MObject* MClass::CreateInstance(void** params, uint32 numParams) bool MClass::HasAttribute(const MClass* monoClass) const { -#if USE_MONO +#if USE_NETCORE + return CoreCLR::HasCustomAttribute(_monoClass, monoClass->GetNative()); +#elif USE_MONO MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR(); return attrInfo != nullptr && mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0; #else @@ -385,7 +390,9 @@ bool MClass::HasAttribute(const MClass* monoClass) const bool MClass::HasAttribute() const { -#if USE_MONO +#if USE_NETCORE + return CoreCLR::HasCustomAttribute(_monoClass); +#elif USE_MONO MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR(); return attrInfo && attrInfo->num_attrs > 0; #else @@ -395,7 +402,9 @@ bool MClass::HasAttribute() const MObject* MClass::GetAttribute(const MClass* monoClass) const { -#if USE_MONO +#if USE_NETCORE + return (MObject*)CoreCLR::GetCustomAttribute(_monoClass, monoClass->GetNative()); +#elif USE_MONO MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR(); return attrInfo ? mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative()) : nullptr; #else @@ -409,7 +418,9 @@ const Array& MClass::GetAttributes() return _attributes; _hasCachedAttributes = true; -#if USE_MONO +#if USE_NETCORE + _attributes = *(Array*)(&CoreCLR::GetCustomAttributes(_monoClass)); +#elif USE_MONO MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR(); if (attrInfo == nullptr) return _attributes;