diff --git a/Source/Engine/Animations/AnimationGraph.cs b/Source/Engine/Animations/AnimationGraph.cs index 46b3acfc1..2e26b8370 100644 --- a/Source/Engine/Animations/AnimationGraph.cs +++ b/Source/Engine/Animations/AnimationGraph.cs @@ -1,7 +1,6 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; @@ -94,9 +93,11 @@ namespace FlaxEngine public AnimatedModel Instance; } + [HideInEditor] [CustomMarshaller(typeof(Context), MarshalMode.Default, typeof(ContextMarshaller))] internal static class ContextMarshaller { + [HideInEditor] [StructLayout(LayoutKind.Sequential)] public struct ContextNative { @@ -116,7 +117,7 @@ namespace FlaxEngine internal static Context ToManaged(ContextNative managed) { - return new Context() + return new Context { Graph = managed.Graph, GraphExecutor = managed.GraphExecutor, @@ -129,9 +130,10 @@ namespace FlaxEngine Instance = AnimatedModelMarshaller.ConvertToManaged(managed.Instance), }; } + internal static ContextNative ToNative(Context managed) { - return new ContextNative() + return new ContextNative { Graph = managed.Graph, GraphExecutor = managed.GraphExecutor, @@ -144,6 +146,7 @@ namespace FlaxEngine Instance = AnimatedModelMarshaller.ConvertToUnmanaged(managed.Instance), }; } + internal static void Free(ContextNative unmanaged) { } @@ -243,6 +246,12 @@ namespace FlaxEngine throw new ArgumentNullException(nameof(source)); if (destination == null) throw new ArgumentNullException(nameof(destination)); + if (source->NodesCount <= 0 || source->NodesCount > 4096) + throw new ArgumentOutOfRangeException(nameof(source)); + if (destination->NodesCount <= 0 || destination->NodesCount > 4096) + throw new ArgumentOutOfRangeException(nameof(destination)); + if (source->NodesCount != destination->NodesCount) + throw new ArgumentOutOfRangeException(); destination->NodesCount = source->NodesCount; destination->Unused = source->Unused; Utils.MemoryCopy(new IntPtr(destination->Nodes), new IntPtr(source->Nodes), (ulong)(source->NodesCount * sizeof(Transform))); diff --git a/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp b/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp index d74c523f1..cdd5b03eb 100644 --- a/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp +++ b/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp @@ -5,7 +5,6 @@ #include "Engine/Scripting/Scripting.h" #include "Engine/Scripting/BinaryModule.h" #include "Engine/Scripting/ManagedCLR/MCore.h" -#include "Engine/Scripting/ManagedCLR/MDomain.h" #include "Engine/Scripting/ManagedCLR/MMethod.h" #include "Engine/Scripting/ManagedCLR/MClass.h" #include "Engine/Scripting/ManagedCLR/MUtils.h" @@ -189,12 +188,8 @@ bool AnimGraph::InitCustomNode(Node* node) return false; } - // Create node values managed array + // Initialization can happen on Content Thread so ensure to have runtime attached MCore::Thread::Attach(); - MArray* values = MCore::Array::New( MCore::TypeCache::Object, node->Values.Count()); - MObject** valuesPtr = MCore::Array::GetAddress(values); - for (int32 i = 0; i < node->Values.Count(); i++) - valuesPtr[i] = MUtils::BoxVariant(node->Values[i]); // Allocate managed node object (create GC handle to prevent destruction) MObject* obj = type->CreateInstance(); @@ -202,7 +197,7 @@ bool AnimGraph::InitCustomNode(Node* node) // Initialize node InternalInitData initData; - initData.Values = values; + initData.Values = MUtils::ToArray(node->Values, MCore::TypeCache::Object); initData.BaseModel = BaseModel.GetManagedInstance(); void* params[1]; params[0] = &initData; @@ -211,7 +206,6 @@ bool AnimGraph::InitCustomNode(Node* node) if (exception) { MCore::GCHandle::Free(handleGC); - MException ex(exception); ex.Log(LogType::Warning, TEXT("AnimGraph")); return false; diff --git a/Source/Engine/Core/Types/Version.h b/Source/Engine/Core/Types/Version.h index 57c6e10fe..1dc36ea38 100644 --- a/Source/Engine/Core/Types/Version.h +++ b/Source/Engine/Core/Types/Version.h @@ -72,15 +72,6 @@ public: return _major; } - /// - /// Gets the high 16 bits of the revision number. - /// - /// A 16-bit signed integer. - FORCE_INLINE int16 MajorRevision() const - { - return static_cast(_revision >> 16); - } - /// /// Gets the value of the minor component of the version number for the current Version object. /// @@ -90,15 +81,6 @@ public: return _minor; } - /// - /// Gets the low 16 bits of the revision number. - /// - /// A 16-bit signed integer. - FORCE_INLINE int16 MinorRevision() const - { - return static_cast(_revision & 65535); - } - /// /// Gets the value of the revision component of the version number for the current Version object. /// @@ -126,61 +108,26 @@ public: return _major == obj._major && _minor == obj._minor && _build == obj._build && _revision == obj._revision; } - /// - /// Determines whether two specified Version objects are equal. - /// - /// The other Version object. - /// True if equals ; otherwise, false. FORCE_INLINE bool operator==(const Version& other) const { return Equals(other); } - - /// - /// Determines whether the first specified Version object is greater than the second specified Version object. - /// - /// The first Version object. - /// True if is greater than ; otherwise, false. - FORCE_INLINE bool operator >(const Version& other) const + FORCE_INLINE bool operator>(const Version& other) const { return other < *this; } - - /// - /// Determines whether the first specified Version object is greater than or equal to the second specified Version object. - /// /summary> - /// The other Version object. - /// True if is greater than or equal to ; otherwise, false. - FORCE_INLINE bool operator >=(const Version& other) const + FORCE_INLINE bool operator>=(const Version& other) const { return other <= *this; } - - /// - /// Determines whether two specified Version objects are not equal. - /// - /// The other Version object. - /// True if does not equal ; otherwise, false. FORCE_INLINE bool operator!=(const Version& other) const { return !(*this == other); } - - /// - /// Determines whether the first specified Version object is less than the second specified Version object. - /// - /// The first other object. - /// True if is less than ; otherwise, false. FORCE_INLINE bool operator<(const Version& other) const { return CompareTo(other) < 0; } - - /// - /// Determines whether the first specified Version object is less than or equal to the second Version object. - /// - /// The other Version object. - /// True if is less than or equal to ; otherwise, false. FORCE_INLINE bool operator<=(const Version& other) const { return CompareTo(other) <= 0; diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index acfd7181b..da372ac90 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -444,7 +444,7 @@ namespace FlaxEngine.Interop } else { - toManagedFieldMethod = typeof(MarshalHelper<>.ReferenceTypeField<>).MakeGenericType(type, fieldType).GetMethod(nameof(MarshalHelper.ReferenceTypeField.ToManagedField), bindingFlags); + toManagedFieldMethod = typeof(MarshalHelper<>.ReferenceTypeField<>).MakeGenericType(type, arrayElementType).GetMethod(nameof(MarshalHelper.ReferenceTypeField.ToManagedFieldArray), bindingFlags); toNativeFieldMethod = typeof(MarshalHelper<>.ReferenceTypeField<>).MakeGenericType(type, fieldType).GetMethod(nameof(MarshalHelper.ReferenceTypeField.ToNativeField), bindingFlags); } } @@ -663,6 +663,17 @@ namespace FlaxEngine.Interop MarshalHelperReferenceType.ToManaged(ref fieldValueRef, Unsafe.Read(fieldPtr.ToPointer()), false); } + internal static void ToManagedFieldArray(FieldInfo field, ref T fieldOwner, IntPtr fieldPtr, out int fieldOffset) + { + fieldOffset = Unsafe.SizeOf(); + IntPtr fieldStartPtr = fieldPtr; + fieldPtr = EnsureAlignment(fieldPtr, IntPtr.Size); + fieldOffset += (fieldPtr - fieldStartPtr).ToInt32(); + + ref TField[] fieldValueRef = ref GetFieldReference(field, ref fieldOwner); + MarshalHelperReferenceType.ToManagedArray(ref fieldValueRef, Unsafe.Read(fieldPtr.ToPointer()), false); + } + internal static void ToNativeField(FieldInfo field, ref T fieldOwner, IntPtr fieldPtr, out int fieldOffset) { fieldOffset = Unsafe.SizeOf(); @@ -691,14 +702,15 @@ namespace FlaxEngine.Interop internal static void ToManaged(ref T managedValue, IntPtr nativePtr, bool byRef) { Type type = typeof(T); - if (type.IsByRef || byRef) + byRef |= type.IsByRef; + if (byRef) { if (type.IsByRef) type = type.GetElementType(); Assert.IsTrue(type.IsValueType); } - if (type == typeof(IntPtr)) + if (type == typeof(IntPtr) && byRef) managedValue = (T)(object)nativePtr; else if (type == typeof(ManagedHandle)) managedValue = (T)(object)ManagedHandle.FromIntPtr(nativePtr); @@ -778,10 +790,12 @@ namespace FlaxEngine.Interop if (type == typeof(string)) managedValue = Unsafe.As(ManagedString.ToManaged(nativePtr)); + else if (nativePtr == IntPtr.Zero) + managedValue = null; else if (type.IsClass) - managedValue = nativePtr != IntPtr.Zero ? Unsafe.As(ManagedHandle.FromIntPtr(nativePtr).Target) : null; + managedValue = Unsafe.As(ManagedHandle.FromIntPtr(nativePtr).Target); else if (type.IsInterface) // Dictionary - managedValue = nativePtr != IntPtr.Zero ? Unsafe.As(ManagedHandle.FromIntPtr(nativePtr).Target) : null; + managedValue = Unsafe.As(ManagedHandle.FromIntPtr(nativePtr).Target); else throw new NotImplementedException(); } diff --git a/Source/Engine/Scripting/Internal/ManagedSerialization.cpp b/Source/Engine/Scripting/Internal/ManagedSerialization.cpp index f1543a326..f5ea46b5e 100644 --- a/Source/Engine/Scripting/Internal/ManagedSerialization.cpp +++ b/Source/Engine/Scripting/Internal/ManagedSerialization.cpp @@ -108,7 +108,7 @@ void ManagedSerialization::Deserialize(const StringAnsiView& data, MObject* obje // Prepare arguments void* args[3]; args[0] = object; - args[1] = (void*)str; + args[1] = (void*)&str; args[2] = (void*)&len; // Call serialization tool diff --git a/Source/Engine/Scripting/ManagedCLR/MUtils.cpp b/Source/Engine/Scripting/ManagedCLR/MUtils.cpp index d97ff92cd..be8e10fab 100644 --- a/Source/Engine/Scripting/ManagedCLR/MUtils.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MUtils.cpp @@ -3,7 +3,6 @@ #include "MUtils.h" #include "MClass.h" #include "MCore.h" -#include "MDomain.h" #include "Engine/Core/Log.h" #include "Engine/Core/Types/DataContainer.h" #include "Engine/Core/Types/Version.h" @@ -449,7 +448,7 @@ Variant MUtils::UnboxVariant(MObject* value) { auto& a = array[i]; a.SetType(elementType); - Platform::MemoryCopy(&a.AsData,(byte*)ptr + elementSize * i, elementSize); + Platform::MemoryCopy(&a.AsData, (byte*)ptr + elementSize * i, elementSize); } break; case VariantType::Transform: @@ -1004,11 +1003,11 @@ MClass* MUtils::GetClass(const Variant& value) case VariantType::Enum: return Scripting::FindClass(StringAnsiView(value.Type.TypeName)); case VariantType::ManagedObject: - { - MObject* obj = (MObject*)value; - if (obj) - return MCore::Object::GetClass(obj); - } + { + MObject* obj = (MObject*)value; + if (obj) + return MCore::Object::GetClass(obj); + } default: ; } return GetClass(value.Type); @@ -1224,10 +1223,10 @@ MObject* MUtils::ToManaged(const Version& value) auto versionToManaged = scriptingClass->GetMethod("VersionToManaged", 4); CHECK_RETURN(versionToManaged, nullptr); - int major = value.Major(); - int minor = value.Minor(); - int build = value.Build(); - int revision = value.Revision(); + int32 major = value.Major(); + int32 minor = value.Minor(); + int32 build = value.Build(); + int32 revision = value.Revision(); void* params[4]; params[0] = &major; @@ -1244,26 +1243,29 @@ MObject* MUtils::ToManaged(const Version& value) Version MUtils::ToNative(MObject* value) { + Version result; if (value) #if USE_NETCORE { - auto ver = Version(); - auto scriptingClass = Scripting::GetStaticClass(); - CHECK_RETURN(scriptingClass, ver); - auto versionToNative = scriptingClass->GetMethod("VersionToNative", 2); - CHECK_RETURN(versionToNative, ver); + CHECK_RETURN(scriptingClass, result); + auto versionToNative = scriptingClass->GetMethod("VersionToNative", 5); + CHECK_RETURN(versionToNative, result); - void* params[2]; + void* params[5]; params[0] = value; - params[1] = &ver; + params[1] = (byte*)&result; + params[2] = (byte*)&result + sizeof(int32); + params[3] = (byte*)&result + sizeof(int32) * 2; + params[4] = (byte*)&result + sizeof(int32) * 3; versionToNative->Invoke(nullptr, params, nullptr); - return ver; + + return result; } #else return *(Version*)MCore::Object::Unbox(value); #endif - return Version(); + return result; } #endif diff --git a/Source/Engine/Scripting/Scripting.cs b/Source/Engine/Scripting/Scripting.cs index 7a91b2d96..2b49d97d4 100644 --- a/Source/Engine/Scripting/Scripting.cs +++ b/Source/Engine/Scripting/Scripting.cs @@ -229,22 +229,24 @@ namespace FlaxEngine return ManagedHandle.Alloc(new CultureInfo(lcid)); } - internal static void VersionToNative(ManagedHandle versionHandle, IntPtr nativePtr) + [StructLayout(LayoutKind.Sequential)] + internal struct VersionNative + { + public int Major; + public int Minor; + public int Build; + public int Revision; + } + + internal static void VersionToNative(ManagedHandle versionHandle, ref int major, ref int minor, ref int build, ref int revision) { Version version = Unsafe.As(versionHandle.Target); if (version != null) { - Marshal.WriteInt32(nativePtr, 0, version.Major); - Marshal.WriteInt32(nativePtr, 4, version.Minor); - Marshal.WriteInt32(nativePtr, 8, version.Build); - Marshal.WriteInt32(nativePtr, 12, version.Revision); - } - else - { - Marshal.WriteInt32(nativePtr, 0, 0); - Marshal.WriteInt32(nativePtr, 4, 0); - Marshal.WriteInt32(nativePtr, 8, -1); - Marshal.WriteInt32(nativePtr, 12, -1); + major = version.Major; + minor = version.Minor; + build = version.Build; + revision = version.Revision; } }