diff --git a/Source/Editor/CustomEditors/Dedicated/RagdollEditor.cs b/Source/Editor/CustomEditors/Dedicated/RagdollEditor.cs index 28c039dc8..5a10b9a52 100644 --- a/Source/Editor/CustomEditors/Dedicated/RagdollEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/RagdollEditor.cs @@ -167,7 +167,7 @@ namespace FlaxEditor.CustomEditors.Dedicated Presenter.Undo?.AddAction(new MultiUndoAction(actions)); // Build ragdoll - SceneGraph.Actors.AnimatedModelNode.BuildRagdoll(animatedModel, options, ragdoll); + AnimatedModelNode.BuildRagdoll(animatedModel, options, ragdoll); } private void OnRebuildBone(Button button) @@ -191,7 +191,7 @@ namespace FlaxEditor.CustomEditors.Dedicated } // Build ragdoll - SceneGraph.Actors.AnimatedModelNode.BuildRagdoll(animatedModel, new AnimatedModelNode.RebuildOptions(), ragdoll, name); + AnimatedModelNode.BuildRagdoll(animatedModel, new AnimatedModelNode.RebuildOptions(), ragdoll, name); } private void OnRemoveBone(Button button) diff --git a/Source/Engine/Engine/NativeInterop.Managed.cs b/Source/Engine/Engine/NativeInterop.Managed.cs index 7eda1cdec..797b02d5b 100644 --- a/Source/Engine/Engine/NativeInterop.Managed.cs +++ b/Source/Engine/Engine/NativeInterop.Managed.cs @@ -50,13 +50,13 @@ namespace FlaxEngine.Interop /// The resources must be released by calling FreePooled() instead of Free()-method. public static ManagedArray WrapPooledArray(Array arr, Type arrayType) { - ManagedArray managedArray = ManagedArrayPool.Get(arr.Length * Marshal.SizeOf(arr.GetType().GetElementType())); + ManagedArray managedArray = ManagedArrayPool.Get(arr.Length * NativeInterop.GetTypeSize(arr.GetType().GetElementType())); managedArray.WrapArray(arr, arrayType); return managedArray; } internal static ManagedArray AllocateNewArray(int length, Type arrayType, Type elementType) - => new ManagedArray((IntPtr)NativeInterop.NativeAlloc(length, Marshal.SizeOf(elementType)), length, arrayType, elementType); + => new ManagedArray((IntPtr)NativeInterop.NativeAlloc(length, NativeInterop.GetTypeSize(elementType)), length, arrayType, elementType); internal static ManagedArray AllocateNewArray(IntPtr ptr, int length, Type arrayType, Type elementType) => new ManagedArray(ptr, length, arrayType, elementType); @@ -86,7 +86,7 @@ namespace FlaxEngine.Interop _length = arr.Length; _arrayType = arrayType; _elementType = arr.GetType().GetElementType(); - _elementSize = Marshal.SizeOf(_elementType); + _elementSize = NativeInterop.GetTypeSize(_elementType); } internal void Allocate(int length) where T : unmanaged @@ -117,7 +117,7 @@ namespace FlaxEngine.Interop _length = length; _arrayType = arrayType; _elementType = elementType; - _elementSize = Marshal.SizeOf(elementType); + _elementSize = NativeInterop.GetTypeSize(_elementType); } ~ManagedArray() diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index c079a14e1..d4a8d44f8 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -885,6 +885,7 @@ namespace FlaxEngine.Interop handle.Free(); fieldHandleCacheCollectible.Clear(); #endif + _typeSizeCache.Clear(); foreach (var pair in classAttributesCacheCollectible) pair.Value.Free(); diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index a6eb5368c..e82cb3858 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -46,6 +46,7 @@ namespace FlaxEngine.Interop #endif private static Dictionary classAttributesCacheCollectible = new(); private static Dictionary assemblyHandles = new(); + private static Dictionary _typeSizeCache = new(); private static Dictionary loadedNativeLibraries = new(); internal static Dictionary nativeLibraryPaths = new(); @@ -584,7 +585,7 @@ namespace FlaxEngine.Interop else if (fieldType.IsClass || fieldType.IsPointer) fieldAlignment = IntPtr.Size; else - fieldAlignment = Marshal.SizeOf(fieldType); + fieldAlignment = GetTypeSize(fieldType); } internal static void ToManagedField(FieldInfo field, ref T fieldOwner, IntPtr fieldPtr, out int fieldOffset) @@ -1088,6 +1089,26 @@ namespace FlaxEngine.Interop return handle; } + internal static int GetTypeSize(Type type) + { + if (!_typeSizeCache.TryGetValue(type, out var size)) + { + try + { + size = Marshal.SizeOf(type); + } + catch + { + // Workaround the issue where structure defined within generic type instance (eg. MyType.MyStruct) fails to get size + // https://github.com/dotnet/runtime/issues/46426 + var obj = Activator.CreateInstance(type); + size = Marshal.SizeOf(obj); + } + _typeSizeCache.Add(type, size); + } + return size; + } + private static class DelegateHelpers { #if USE_AOT diff --git a/Source/Engine/Level/Spline.cs b/Source/Engine/Level/Spline.cs index 28a6aff8c..a2c9aecde 100644 --- a/Source/Engine/Level/Spline.cs +++ b/Source/Engine/Level/Spline.cs @@ -23,8 +23,8 @@ namespace FlaxEngine if (_keyframes == null || _keyframes.Length != count) _keyframes = new BezierCurve.Keyframe[count]; #if !BUILD_RELEASE - if (Marshal.SizeOf(typeof(BezierCurve.Keyframe)) != Transform.SizeInBytes * 3 + sizeof(float)) - throw new Exception("Invalid size of BezierCurve keyframe " + Marshal.SizeOf(typeof(BezierCurve.Keyframe)) + " bytes."); + if (System.Runtime.CompilerServices.Unsafe.SizeOf.Keyframe>() != Transform.SizeInBytes * 3 + sizeof(float)) + throw new Exception("Invalid size of BezierCurve keyframe " + System.Runtime.CompilerServices.Unsafe.SizeOf.Keyframe>() + " bytes."); #endif Internal_GetKeyframes(__unmanagedPtr, _keyframes); return _keyframes;