diff options
Diffstat (limited to 'modules/mono/glue')
35 files changed, 4180 insertions, 1058 deletions
diff --git a/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings b/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings new file mode 100644 index 0000000000..3103fa78c7 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings @@ -0,0 +1,7 @@ +<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> + <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GC/@EntryIndexedValue">GC</s:String> + <s:Boolean x:Key="/Default/UserDictionary/Words/=gdnative/@EntryIndexedValue">True</s:Boolean> + <s:Boolean x:Key="/Default/UserDictionary/Words/=godotsharp/@EntryIndexedValue">True</s:Boolean> + <s:Boolean x:Key="/Default/UserDictionary/Words/=icall/@EntryIndexedValue">True</s:Boolean> + <s:Boolean x:Key="/Default/UserDictionary/Words/=quat/@EntryIndexedValue">True</s:Boolean> + <s:Boolean x:Key="/Default/UserDictionary/Words/=vcall/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs index a412047196..c32895baab 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs @@ -1,47 +1,28 @@ using System; using System.Collections.Generic; using System.Collections; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; +using Godot.NativeInterop; namespace Godot.Collections { - internal class ArraySafeHandle : SafeHandle - { - public ArraySafeHandle(IntPtr handle) : base(IntPtr.Zero, true) - { - this.handle = handle; - } - - public override bool IsInvalid - { - get { return handle == IntPtr.Zero; } - } - - protected override bool ReleaseHandle() - { - Array.godot_icall_Array_Dtor(handle); - return true; - } - } - /// <summary> /// Wrapper around Godot's Array class, an array of Variant /// typed elements allocated in the engine in C++. Useful when /// interfacing with the engine. Otherwise prefer .NET collections /// such as <see cref="System.Array"/> or <see cref="List{T}"/>. /// </summary> - public class Array : IList, IDisposable + public sealed class Array : IList, IDisposable { - private ArraySafeHandle _safeHandle; - private bool _disposed = false; + internal godot_array NativeValue; /// <summary> /// Constructs a new empty <see cref="Array"/>. /// </summary> public Array() { - _safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor()); + godot_icall_Array_Ctor(out NativeValue); } /// <summary> @@ -58,6 +39,7 @@ namespace Godot.Collections Add(element); } + // TODO: This must be removed. Lots of silent mistakes as it takes pretty much anything. /// <summary> /// Constructs a new <see cref="Array"/> from the given objects. /// </summary> @@ -69,25 +51,37 @@ namespace Godot.Collections { throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'"); } - _safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor_MonoArray(array)); + + godot_icall_Array_Ctor_MonoArray(array, out NativeValue); } - internal Array(ArraySafeHandle handle) + private Array(godot_array nativeValueToOwn) { - _safeHandle = handle; + NativeValue = nativeValueToOwn; } - internal Array(IntPtr handle) + // Explicit name to make it very clear + internal static Array CreateTakingOwnershipOfDisposableValue(godot_array nativeValueToOwn) + => new Array(nativeValueToOwn); + + ~Array() { - _safeHandle = new ArraySafeHandle(handle); + Dispose(false); } - internal IntPtr GetPtr() + /// <summary> + /// Disposes of this <see cref="Array"/>. + /// </summary> + public void Dispose() { - if (_disposed) - throw new ObjectDisposedException(GetType().FullName); + Dispose(true); + GC.SuppressFinalize(this); + } - return _safeHandle.DangerousGetHandle(); + public void Dispose(bool disposing) + { + // Always dispose `NativeValue` even if disposing is true + NativeValue.Dispose(); } /// <summary> @@ -97,7 +91,9 @@ namespace Godot.Collections /// <returns>A new Godot Array.</returns> public Array Duplicate(bool deep = false) { - return new Array(godot_icall_Array_Duplicate(GetPtr(), deep)); + godot_array newArray; + godot_icall_Array_Duplicate(ref NativeValue, deep, out newArray); + return CreateTakingOwnershipOfDisposableValue(newArray); } /// <summary> @@ -107,7 +103,7 @@ namespace Godot.Collections /// <returns><see cref="Error.Ok"/> if successful, or an error code.</returns> public Error Resize(int newSize) { - return godot_icall_Array_Resize(GetPtr(), newSize); + return godot_icall_Array_Resize(ref NativeValue, newSize); } /// <summary> @@ -115,7 +111,7 @@ namespace Godot.Collections /// </summary> public void Shuffle() { - godot_icall_Array_Shuffle(GetPtr()); + godot_icall_Array_Shuffle(ref NativeValue); } /// <summary> @@ -126,26 +122,9 @@ namespace Godot.Collections /// <returns>A new Godot Array with the contents of both arrays.</returns> public static Array operator +(Array left, Array right) { - return new Array(godot_icall_Array_Concatenate(left.GetPtr(), right.GetPtr())); - } - - // IDisposable - - /// <summary> - /// Disposes of this <see cref="Array"/>. - /// </summary> - public void Dispose() - { - if (_disposed) - return; - - if (_safeHandle != null) - { - _safeHandle.Dispose(); - _safeHandle = null; - } - - _disposed = true; + godot_array newArray; + godot_icall_Array_Concatenate(ref left.NativeValue, ref right.NativeValue, out newArray); + return CreateTakingOwnershipOfDisposableValue(newArray); } // IList @@ -160,8 +139,16 @@ namespace Godot.Collections /// <value>The object at the given <paramref name="index"/>.</value> public object this[int index] { - get => godot_icall_Array_At(GetPtr(), index); - set => godot_icall_Array_SetAt(GetPtr(), index, value); + get + { + godot_icall_Array_At(ref NativeValue, index, out godot_variant elem); + unsafe + { + using (elem) + return Marshaling.variant_to_mono_object(&elem); + } + } + set => godot_icall_Array_SetAt(ref NativeValue, index, value); } /// <summary> @@ -170,19 +157,19 @@ namespace Godot.Collections /// </summary> /// <param name="value">The object to add.</param> /// <returns>The new size after adding the object.</returns> - public int Add(object value) => godot_icall_Array_Add(GetPtr(), value); + public int Add(object value) => godot_icall_Array_Add(ref NativeValue, value); /// <summary> /// Checks if this <see cref="Array"/> contains the given object. /// </summary> /// <param name="value">The item to look for.</param> /// <returns>Whether or not this array contains the given object.</returns> - public bool Contains(object value) => godot_icall_Array_Contains(GetPtr(), value); + public bool Contains(object value) => godot_icall_Array_Contains(ref NativeValue, value); /// <summary> /// Erases all items from this <see cref="Array"/>. /// </summary> - public void Clear() => godot_icall_Array_Clear(GetPtr()); + public void Clear() => godot_icall_Array_Clear(ref NativeValue); /// <summary> /// Searches this <see cref="Array"/> for an object @@ -190,7 +177,7 @@ namespace Godot.Collections /// </summary> /// <param name="value">The object to search for.</param> /// <returns>The index of the object, or -1 if not found.</returns> - public int IndexOf(object value) => godot_icall_Array_IndexOf(GetPtr(), value); + public int IndexOf(object value) => godot_icall_Array_IndexOf(ref NativeValue, value); /// <summary> /// Inserts a new object at a given position in the array. @@ -200,20 +187,20 @@ namespace Godot.Collections /// </summary> /// <param name="index">The index to insert at.</param> /// <param name="value">The object to insert.</param> - public void Insert(int index, object value) => godot_icall_Array_Insert(GetPtr(), index, value); + public void Insert(int index, object value) => godot_icall_Array_Insert(ref NativeValue, index, value); /// <summary> /// Removes the first occurrence of the specified <paramref name="value"/> /// from this <see cref="Array"/>. /// </summary> /// <param name="value">The value to remove.</param> - public void Remove(object value) => godot_icall_Array_Remove(GetPtr(), value); + public void Remove(object value) => godot_icall_Array_Remove(ref NativeValue, value); /// <summary> /// Removes an element from this <see cref="Array"/> by index. /// </summary> /// <param name="index">The index of the element to remove.</param> - public void RemoveAt(int index) => godot_icall_Array_RemoveAt(GetPtr(), index); + public void RemoveAt(int index) => godot_icall_Array_RemoveAt(ref NativeValue, index); // ICollection @@ -222,7 +209,7 @@ namespace Godot.Collections /// This is also known as the size or length of the array. /// </summary> /// <returns>The number of elements.</returns> - public int Count => godot_icall_Array_Count(GetPtr()); + public int Count => godot_icall_Array_Count(ref NativeValue); object ICollection.SyncRoot => this; @@ -243,7 +230,7 @@ namespace Godot.Collections throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension."); // Internal call may throw ArgumentException - godot_icall_Array_CopyTo(GetPtr(), array, index); + godot_icall_Array_CopyTo(ref NativeValue, array, index); } // IEnumerable @@ -268,73 +255,71 @@ namespace Godot.Collections /// <returns>A string representation of this array.</returns> public override string ToString() { - return godot_icall_Array_ToString(GetPtr()); + return godot_icall_Array_ToString(ref NativeValue); } [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern IntPtr godot_icall_Array_Ctor(); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern IntPtr godot_icall_Array_Ctor_MonoArray(System.Array array); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Array_Dtor(IntPtr ptr); + internal static extern void godot_icall_Array_Ctor(out godot_array dest); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern object godot_icall_Array_At(IntPtr ptr, int index); + internal static extern void godot_icall_Array_Ctor_MonoArray(System.Array array, out godot_array dest); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern object godot_icall_Array_At_Generic(IntPtr ptr, int index, int elemTypeEncoding, IntPtr elemTypeClass); + internal static extern void godot_icall_Array_At(ref godot_array ptr, int index, out godot_variant elem); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Array_SetAt(IntPtr ptr, int index, object value); + internal static extern void godot_icall_Array_SetAt(ref godot_array ptr, int index, object value); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern int godot_icall_Array_Count(IntPtr ptr); + internal static extern int godot_icall_Array_Count(ref godot_array ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern int godot_icall_Array_Add(IntPtr ptr, object item); + internal static extern int godot_icall_Array_Add(ref godot_array ptr, object item); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Array_Clear(IntPtr ptr); + internal static extern void godot_icall_Array_Clear(ref godot_array ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern IntPtr godot_icall_Array_Concatenate(IntPtr left, IntPtr right); + internal static extern void godot_icall_Array_Concatenate(ref godot_array left, ref godot_array right, out godot_array dest); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern bool godot_icall_Array_Contains(IntPtr ptr, object item); + internal static extern bool godot_icall_Array_Contains(ref godot_array ptr, object item); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Array_CopyTo(IntPtr ptr, System.Array array, int arrayIndex); + internal static extern void godot_icall_Array_CopyTo(ref godot_array ptr, System.Array array, int arrayIndex); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern IntPtr godot_icall_Array_Duplicate(IntPtr ptr, bool deep); + internal static extern void godot_icall_Array_Duplicate(ref godot_array ptr, bool deep, out godot_array dest); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern int godot_icall_Array_IndexOf(IntPtr ptr, object item); + internal static extern int godot_icall_Array_IndexOf(ref godot_array ptr, object item); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Array_Insert(IntPtr ptr, int index, object item); + internal static extern void godot_icall_Array_Insert(ref godot_array ptr, int index, object item); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern bool godot_icall_Array_Remove(IntPtr ptr, object item); + internal static extern bool godot_icall_Array_Remove(ref godot_array ptr, object item); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Array_RemoveAt(IntPtr ptr, int index); + internal static extern void godot_icall_Array_RemoveAt(ref godot_array ptr, int index); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern Error godot_icall_Array_Resize(IntPtr ptr, int newSize); + internal static extern Error godot_icall_Array_Resize(ref godot_array ptr, int newSize); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern Error godot_icall_Array_Shuffle(IntPtr ptr); + internal static extern Error godot_icall_Array_Shuffle(ref godot_array ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Array_Generic_GetElementTypeInfo(Type elemType, out int elemTypeEncoding, out IntPtr elemTypeClass); + internal static extern string godot_icall_Array_ToString(ref godot_array ptr); + } - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern string godot_icall_Array_ToString(IntPtr ptr); + internal interface IGenericGodotArray + { + Array UnderlyingArray { get; } + Type TypeOfElements { get; } } + // TODO: Now we should be able to avoid boxing /// <summary> /// Typed wrapper around Godot's Array class, an array of Variant /// typed elements allocated in the engine in C++. Useful when @@ -342,24 +327,29 @@ namespace Godot.Collections /// such as arrays or <see cref="List{T}"/>. /// </summary> /// <typeparam name="T">The type of the array.</typeparam> - public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T> + [SuppressMessage("ReSharper", "RedundantExtendsListEntry")] + public sealed class Array<T> : IList<T>, ICollection<T>, IEnumerable<T>, IGenericGodotArray { - private Array _objectArray; + private readonly Array _underlyingArray; - internal static int elemTypeEncoding; - internal static IntPtr elemTypeClass; + internal ref godot_array NativeValue => ref _underlyingArray.NativeValue; - static Array() - { - Array.godot_icall_Array_Generic_GetElementTypeInfo(typeof(T), out elemTypeEncoding, out elemTypeClass); - } + // ReSharper disable StaticMemberInGenericType + // Warning is about unique static fields being created for each generic type combination: + // https://www.jetbrains.com/help/resharper/StaticMemberInGenericType.html + // In our case this is exactly what we want. + private static readonly Type TypeOfElements = typeof(T); + // ReSharper restore StaticMemberInGenericType + + Array IGenericGodotArray.UnderlyingArray => _underlyingArray; + Type IGenericGodotArray.TypeOfElements => TypeOfElements; /// <summary> /// Constructs a new empty <see cref="Array{T}"/>. /// </summary> public Array() { - _objectArray = new Array(); + _underlyingArray = new Array(); } /// <summary> @@ -372,7 +362,7 @@ namespace Godot.Collections if (collection == null) throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'"); - _objectArray = new Array(collection); + _underlyingArray = new Array(collection); } /// <summary> @@ -386,7 +376,8 @@ namespace Godot.Collections { throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'"); } - _objectArray = new Array(array); + + _underlyingArray = new Array(array); } /// <summary> @@ -395,23 +386,12 @@ namespace Godot.Collections /// <param name="array">The untyped array to construct from.</param> public Array(Array array) { - _objectArray = array; - } - - internal Array(IntPtr handle) - { - _objectArray = new Array(handle); - } - - internal Array(ArraySafeHandle handle) - { - _objectArray = new Array(handle); + _underlyingArray = array; } - internal IntPtr GetPtr() - { - return _objectArray.GetPtr(); - } + // Explicit name to make it very clear + internal static Array<T> CreateTakingOwnershipOfDisposableValue(godot_array nativeValueToOwn) + => new Array<T>(Array.CreateTakingOwnershipOfDisposableValue(nativeValueToOwn)); /// <summary> /// Converts this typed <see cref="Array{T}"/> to an untyped <see cref="Array"/>. @@ -419,7 +399,7 @@ namespace Godot.Collections /// <param name="from">The typed array to convert.</param> public static explicit operator Array(Array<T> from) { - return from._objectArray; + return from._underlyingArray; } /// <summary> @@ -429,7 +409,7 @@ namespace Godot.Collections /// <returns>A new Godot Array.</returns> public Array<T> Duplicate(bool deep = false) { - return new Array<T>(_objectArray.Duplicate(deep)); + return new Array<T>(_underlyingArray.Duplicate(deep)); } /// <summary> @@ -439,7 +419,7 @@ namespace Godot.Collections /// <returns><see cref="Error.Ok"/> if successful, or an error code.</returns> public Error Resize(int newSize) { - return _objectArray.Resize(newSize); + return _underlyingArray.Resize(newSize); } /// <summary> @@ -447,7 +427,7 @@ namespace Godot.Collections /// </summary> public void Shuffle() { - _objectArray.Shuffle(); + _underlyingArray.Shuffle(); } /// <summary> @@ -458,7 +438,7 @@ namespace Godot.Collections /// <returns>A new Godot Array with the contents of both arrays.</returns> public static Array<T> operator +(Array<T> left, Array<T> right) { - return new Array<T>(left._objectArray + right._objectArray); + return new Array<T>(left._underlyingArray + right._underlyingArray); } // IList<T> @@ -469,8 +449,16 @@ namespace Godot.Collections /// <value>The value at the given <paramref name="index"/>.</value> public T this[int index] { - get { return (T)Array.godot_icall_Array_At_Generic(GetPtr(), index, elemTypeEncoding, elemTypeClass); } - set { _objectArray[index] = value; } + get + { + Array.godot_icall_Array_At(ref _underlyingArray.NativeValue, index, out godot_variant elem); + unsafe + { + using (elem) + return (T)Marshaling.variant_to_mono_object_of_type(&elem, TypeOfElements); + } + } + set => _underlyingArray[index] = value; } /// <summary> @@ -481,7 +469,7 @@ namespace Godot.Collections /// <returns>The index of the item, or -1 if not found.</returns> public int IndexOf(T item) { - return _objectArray.IndexOf(item); + return _underlyingArray.IndexOf(item); } /// <summary> @@ -494,7 +482,7 @@ namespace Godot.Collections /// <param name="item">The item to insert.</param> public void Insert(int index, T item) { - _objectArray.Insert(index, item); + _underlyingArray.Insert(index, item); } /// <summary> @@ -503,7 +491,7 @@ namespace Godot.Collections /// <param name="index">The index of the element to remove.</param> public void RemoveAt(int index) { - _objectArray.RemoveAt(index); + _underlyingArray.RemoveAt(index); } // ICollection<T> @@ -513,10 +501,7 @@ namespace Godot.Collections /// This is also known as the size or length of the array. /// </summary> /// <returns>The number of elements.</returns> - public int Count - { - get { return _objectArray.Count; } - } + public int Count => _underlyingArray.Count; bool ICollection<T>.IsReadOnly => false; @@ -528,7 +513,7 @@ namespace Godot.Collections /// <returns>The new size after adding the item.</returns> public void Add(T item) { - _objectArray.Add(item); + _underlyingArray.Add(item); } /// <summary> @@ -536,7 +521,7 @@ namespace Godot.Collections /// </summary> public void Clear() { - _objectArray.Clear(); + _underlyingArray.Clear(); } /// <summary> @@ -546,7 +531,7 @@ namespace Godot.Collections /// <returns>Whether or not this array contains the given item.</returns> public bool Contains(T item) { - return _objectArray.Contains(item); + return _underlyingArray.Contains(item); } /// <summary> @@ -563,17 +548,14 @@ namespace Godot.Collections if (arrayIndex < 0) throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension."); - // TODO This may be quite slow because every element access is an internal call. - // It could be moved entirely to an internal call if we find out how to do the cast there. - - int count = _objectArray.Count; + int count = _underlyingArray.Count; if (array.Length < (arrayIndex + count)) throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds."); for (int i = 0; i < count; i++) { - array[arrayIndex] = (T)this[i]; + array[arrayIndex] = this[i]; arrayIndex++; } } @@ -586,7 +568,7 @@ namespace Godot.Collections /// <returns>A <see langword="bool"/> indicating success or failure.</returns> public bool Remove(T item) { - return Array.godot_icall_Array_Remove(GetPtr(), item); + return Array.godot_icall_Array_Remove(ref _underlyingArray.NativeValue, item); } // IEnumerable<T> @@ -597,23 +579,20 @@ namespace Godot.Collections /// <returns>An enumerator.</returns> public IEnumerator<T> GetEnumerator() { - int count = _objectArray.Count; + int count = _underlyingArray.Count; for (int i = 0; i < count; i++) { - yield return (T)this[i]; + yield return this[i]; } } - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); /// <summary> /// Converts this <see cref="Array{T}"/> to a string. /// </summary> /// <returns>A string representation of this array.</returns> - public override string ToString() => _objectArray.ToString(); + public override string ToString() => _underlyingArray.ToString(); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs index 1dca9e6ea7..187d910f9f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs @@ -4,11 +4,53 @@ using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Godot.NativeInterop; namespace Godot { internal static class DelegateUtils { + // TODO: Move somewhere else once we need to for things other than delegates + internal static void FreeGCHandle(IntPtr delegateGCHandle) + => GCHandle.FromIntPtr(delegateGCHandle).Free(); + + internal static bool DelegateEquals(IntPtr delegateGCHandleA, IntPtr delegateGCHandleB) + { + var @delegateA = (Delegate)GCHandle.FromIntPtr(delegateGCHandleA).Target; + var @delegateB = (Delegate)GCHandle.FromIntPtr(delegateGCHandleB).Target; + return @delegateA == @delegateB; + } + + internal static unsafe void InvokeWithVariantArgs(IntPtr delegateGCHandle, godot_variant** args, uint argc, godot_variant* ret) + { + // TODO: Optimize + var @delegate = (Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target; + var managedArgs = new object[argc]; + + var parameterInfos = @delegate.Method.GetParameters(); + + var paramsLength = parameterInfos.Length; + + if (argc != paramsLength) + { + throw new InvalidOperationException( + $"The delegate expects {paramsLength} arguments, but received {argc}."); + } + + for (uint i = 0; i < argc; i++) + { + managedArgs[i] = Marshaling.variant_to_mono_object_of_type( + args[i], parameterInfos[i].ParameterType); + } + + object invokeRet = @delegate.DynamicInvoke(managedArgs); + + *ret = Marshaling.mono_object_to_variant(invokeRet); + } + + // TODO: Check if we should be using BindingFlags.DeclaredOnly (would give better reflection performance). + private enum TargetKind : uint { Static, @@ -16,7 +58,10 @@ namespace Godot CompilerGenerated } - internal static bool TrySerializeDelegate(Delegate @delegate, Collections.Array serializedData) + internal static bool TrySerializeDelegateWithGCHandle(IntPtr delegateGCHandle, Collections.Array serializedData) + => TrySerializeDelegate((Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target, serializedData); + + private static bool TrySerializeDelegate(Delegate @delegate, Collections.Array serializedData) { if (@delegate is MulticastDelegate multicastDelegate) { @@ -72,12 +117,14 @@ namespace Godot return true; } } + // ReSharper disable once RedundantNameQualifier case Godot.Object godotObject: { using (var stream = new MemoryStream()) using (var writer = new BinaryWriter(stream)) { writer.Write((ulong)TargetKind.GodotObject); + // ReSharper disable once RedundantCast writer.Write((ulong)godotObject.GetInstanceId()); SerializeType(writer, @delegate.GetType()); @@ -93,7 +140,7 @@ namespace Godot { Type targetType = target.GetType(); - if (targetType.GetCustomAttribute(typeof(CompilerGeneratedAttribute), true) != null) + if (targetType.IsDefined(typeof(CompilerGeneratedAttribute), true)) { // Compiler generated. Probably a closure. Try to serialize it. @@ -213,6 +260,13 @@ namespace Godot } } + private static bool TryDeserializeDelegateWithGCHandle(Collections.Array serializedData, out IntPtr delegateGCHandle) + { + bool res = TryDeserializeDelegate(serializedData, out Delegate @delegate); + delegateGCHandle = GCHandle.ToIntPtr(GCHandle.Alloc(@delegate)); + return res; + } + private static bool TryDeserializeDelegate(Collections.Array serializedData, out Delegate @delegate) { if (serializedData.Count == 1) @@ -276,6 +330,7 @@ namespace Godot case TargetKind.GodotObject: { ulong objectId = reader.ReadUInt64(); + // ReSharper disable once RedundantNameQualifier Godot.Object godotObject = GD.InstanceFromId(objectId); if (godotObject == null) return false; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs index e80b6af68f..d0c7e4523b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs @@ -2,46 +2,28 @@ using System; using System.Collections.Generic; using System.Collections; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; +using Godot.NativeInterop; using System.Diagnostics.CodeAnalysis; namespace Godot.Collections { - internal class DictionarySafeHandle : SafeHandle - { - public DictionarySafeHandle(IntPtr handle) : base(IntPtr.Zero, true) - { - this.handle = handle; - } - - public override bool IsInvalid - { - get { return handle == IntPtr.Zero; } - } - - protected override bool ReleaseHandle() - { - Dictionary.godot_icall_Dictionary_Dtor(handle); - return true; - } - } - /// <summary> /// Wrapper around Godot's Dictionary class, a dictionary of Variant /// typed elements allocated in the engine in C++. Useful when /// interfacing with the engine. /// </summary> - public class Dictionary : IDictionary, IDisposable + public sealed class Dictionary : + IDictionary, + IDisposable { - private DictionarySafeHandle _safeHandle; - private bool _disposed = false; + internal godot_dictionary NativeValue; /// <summary> /// Constructs a new empty <see cref="Dictionary"/>. /// </summary> public Dictionary() { - _safeHandle = new DictionarySafeHandle(godot_icall_Dictionary_Ctor()); + godot_icall_Dictionary_Ctor(out NativeValue); } /// <summary> @@ -58,22 +40,18 @@ namespace Godot.Collections Add(entry.Key, entry.Value); } - internal Dictionary(DictionarySafeHandle handle) + private Dictionary(godot_dictionary nativeValueToOwn) { - _safeHandle = handle; + NativeValue = nativeValueToOwn; } - internal Dictionary(IntPtr handle) - { - _safeHandle = new DictionarySafeHandle(handle); - } + // Explicit name to make it very clear + internal static Dictionary CreateTakingOwnershipOfDisposableValue(godot_dictionary nativeValueToOwn) + => new Dictionary(nativeValueToOwn); - internal IntPtr GetPtr() + ~Dictionary() { - if (_disposed) - throw new ObjectDisposedException(GetType().FullName); - - return _safeHandle.DangerousGetHandle(); + Dispose(false); } /// <summary> @@ -81,16 +59,14 @@ namespace Godot.Collections /// </summary> public void Dispose() { - if (_disposed) - return; - - if (_safeHandle != null) - { - _safeHandle.Dispose(); - _safeHandle = null; - } + Dispose(true); + GC.SuppressFinalize(this); + } - _disposed = true; + public void Dispose(bool disposing) + { + // Always dispose `NativeValue` even if disposing is true + NativeValue.Dispose(); } /// <summary> @@ -100,7 +76,9 @@ namespace Godot.Collections /// <returns>A new Godot Dictionary.</returns> public Dictionary Duplicate(bool deep = false) { - return new Dictionary(godot_icall_Dictionary_Duplicate(GetPtr(), deep)); + godot_dictionary newDictionary; + godot_icall_Dictionary_Duplicate(ref NativeValue, deep, out newDictionary); + return CreateTakingOwnershipOfDisposableValue(newDictionary); } // IDictionary @@ -112,8 +90,9 @@ namespace Godot.Collections { get { - IntPtr handle = godot_icall_Dictionary_Keys(GetPtr()); - return new Array(new ArraySafeHandle(handle)); + godot_array keysArray; + godot_icall_Dictionary_Keys(ref NativeValue, out keysArray); + return Array.CreateTakingOwnershipOfDisposableValue(keysArray); } } @@ -124,16 +103,19 @@ namespace Godot.Collections { get { - IntPtr handle = godot_icall_Dictionary_Values(GetPtr()); - return new Array(new ArraySafeHandle(handle)); + godot_array valuesArray; + godot_icall_Dictionary_Values(ref NativeValue, out valuesArray); + return Array.CreateTakingOwnershipOfDisposableValue(valuesArray); } } private (Array keys, Array values, int count) GetKeyValuePairs() { - int count = godot_icall_Dictionary_KeyValuePairs(GetPtr(), out IntPtr keysHandle, out IntPtr valuesHandle); - Array keys = new Array(new ArraySafeHandle(keysHandle)); - Array values = new Array(new ArraySafeHandle(valuesHandle)); + godot_array keysArray; + godot_array valuesArray; + int count = godot_icall_Dictionary_KeyValuePairs(ref NativeValue, out keysArray, out valuesArray); + var keys = Array.CreateTakingOwnershipOfDisposableValue(keysArray); + var values = Array.CreateTakingOwnershipOfDisposableValue(valuesArray); return (keys, values, count); } @@ -147,8 +129,16 @@ namespace Godot.Collections /// <value>The object at the given <paramref name="key"/>.</value> public object this[object key] { - get => godot_icall_Dictionary_GetValue(GetPtr(), key); - set => godot_icall_Dictionary_SetValue(GetPtr(), key, value); + get + { + godot_icall_Dictionary_GetValue(ref NativeValue, key, out godot_variant value); + unsafe + { + using (value) + return Marshaling.variant_to_mono_object(&value); + } + } + set => godot_icall_Dictionary_SetValue(ref NativeValue, key, value); } /// <summary> @@ -157,19 +147,19 @@ namespace Godot.Collections /// </summary> /// <param name="key">The key at which to add the object.</param> /// <param name="value">The object to add.</param> - public void Add(object key, object value) => godot_icall_Dictionary_Add(GetPtr(), key, value); + public void Add(object key, object value) => godot_icall_Dictionary_Add(ref NativeValue, key, value); /// <summary> /// Erases all items from this <see cref="Dictionary"/>. /// </summary> - public void Clear() => godot_icall_Dictionary_Clear(GetPtr()); + public void Clear() => godot_icall_Dictionary_Clear(ref NativeValue); /// <summary> /// Checks if this <see cref="Dictionary"/> contains the given key. /// </summary> /// <param name="key">The key to look for.</param> /// <returns>Whether or not this dictionary contains the given key.</returns> - public bool Contains(object key) => godot_icall_Dictionary_ContainsKey(GetPtr(), key); + public bool Contains(object key) => godot_icall_Dictionary_ContainsKey(ref NativeValue, key); /// <summary> /// Gets an enumerator for this <see cref="Dictionary"/>. @@ -181,7 +171,7 @@ namespace Godot.Collections /// Removes an element from this <see cref="Dictionary"/> by key. /// </summary> /// <param name="key">The key of the element to remove.</param> - public void Remove(object key) => godot_icall_Dictionary_RemoveKey(GetPtr(), key); + public void Remove(object key) => godot_icall_Dictionary_RemoveKey(ref NativeValue, key); // ICollection @@ -194,7 +184,7 @@ namespace Godot.Collections /// This is also known as the size or length of the dictionary. /// </summary> /// <returns>The number of elements.</returns> - public int Count => godot_icall_Dictionary_Count(GetPtr()); + public int Count => godot_icall_Dictionary_Count(ref NativeValue); /// <summary> /// Copies the elements of this <see cref="Dictionary"/> to the given @@ -258,8 +248,17 @@ namespace Godot.Collections private void UpdateEntry() { _dirty = false; - godot_icall_Dictionary_KeyValuePairAt(_dictionary.GetPtr(), _index, out object key, out object value); - _entry = new DictionaryEntry(key, value); + godot_icall_Dictionary_KeyValuePairAt(ref _dictionary.NativeValue, _index, out var vKey, out var vValue); + unsafe + { + using (vKey) + using (vValue) + { + var key = Marshaling.variant_to_mono_object(&vKey); + var value = Marshaling.variant_to_mono_object(&vValue); + _entry = new DictionaryEntry(key, value); + } + } } public object Key => Entry.Key; @@ -286,76 +285,70 @@ namespace Godot.Collections /// <returns>A string representation of this dictionary.</returns> public override string ToString() { - return godot_icall_Dictionary_ToString(GetPtr()); + return godot_icall_Dictionary_ToString(ref NativeValue); } [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern IntPtr godot_icall_Dictionary_Ctor(); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Dictionary_Dtor(IntPtr ptr); + internal static extern void godot_icall_Dictionary_Ctor(out godot_dictionary dest); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern object godot_icall_Dictionary_GetValue(IntPtr ptr, object key); + internal static extern void godot_icall_Dictionary_GetValue(ref godot_dictionary ptr, object key, out godot_variant value); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern object godot_icall_Dictionary_GetValue_Generic(IntPtr ptr, object key, int valTypeEncoding, IntPtr valTypeClass); + internal static extern void godot_icall_Dictionary_SetValue(ref godot_dictionary ptr, object key, object value); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Dictionary_SetValue(IntPtr ptr, object key, object value); + internal static extern void godot_icall_Dictionary_Keys(ref godot_dictionary ptr, out godot_array dest); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern IntPtr godot_icall_Dictionary_Keys(IntPtr ptr); + internal static extern void godot_icall_Dictionary_Values(ref godot_dictionary ptr, out godot_array dest); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern IntPtr godot_icall_Dictionary_Values(IntPtr ptr); + internal static extern int godot_icall_Dictionary_KeyValuePairs(ref godot_dictionary ptr, out godot_array keys, out godot_array values); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern int godot_icall_Dictionary_Count(IntPtr ptr); + internal static extern void godot_icall_Dictionary_KeyValuePairAt(ref godot_dictionary ptr, int index, out godot_variant key, out godot_variant value); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern int godot_icall_Dictionary_KeyValuePairs(IntPtr ptr, out IntPtr keys, out IntPtr values); + internal static extern void godot_icall_Dictionary_Add(ref godot_dictionary ptr, object key, object value); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Dictionary_KeyValuePairAt(IntPtr ptr, int index, out object key, out object value); + internal static extern int godot_icall_Dictionary_Count(ref godot_dictionary ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Dictionary_KeyValuePairAt_Generic(IntPtr ptr, int index, out object key, out object value, int valueTypeEncoding, IntPtr valueTypeClass); + internal static extern void godot_icall_Dictionary_Clear(ref godot_dictionary ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value); + internal static extern bool godot_icall_Dictionary_Contains(ref godot_dictionary ptr, object key, object value); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Dictionary_Clear(IntPtr ptr); + internal static extern bool godot_icall_Dictionary_ContainsKey(ref godot_dictionary ptr, object key); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern bool godot_icall_Dictionary_Contains(IntPtr ptr, object key, object value); + internal static extern void godot_icall_Dictionary_Duplicate(ref godot_dictionary ptr, bool deep, out godot_dictionary dest); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern bool godot_icall_Dictionary_ContainsKey(IntPtr ptr, object key); + internal static extern bool godot_icall_Dictionary_RemoveKey(ref godot_dictionary ptr, object key); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern IntPtr godot_icall_Dictionary_Duplicate(IntPtr ptr, bool deep); + internal static extern bool godot_icall_Dictionary_Remove(ref godot_dictionary ptr, object key, object value); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern bool godot_icall_Dictionary_RemoveKey(IntPtr ptr, object key); + internal static extern bool godot_icall_Dictionary_TryGetValue(ref godot_dictionary ptr, object key, out godot_variant value); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern bool godot_icall_Dictionary_Remove(IntPtr ptr, object key, object value); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern bool godot_icall_Dictionary_TryGetValue(IntPtr ptr, object key, out object value); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern bool godot_icall_Dictionary_TryGetValue_Generic(IntPtr ptr, object key, out object value, int valTypeEncoding, IntPtr valTypeClass); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Dictionary_Generic_GetValueTypeInfo(Type valueType, out int valTypeEncoding, out IntPtr valTypeClass); + internal static extern string godot_icall_Dictionary_ToString(ref godot_dictionary ptr); + } - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern string godot_icall_Dictionary_ToString(IntPtr ptr); + internal interface IGenericGodotDictionary + { + Dictionary UnderlyingDictionary { get; } + Type TypeOfKeys { get; } + Type TypeOfValues { get; } } + // TODO: Now we should be able to avoid boxing + /// <summary> /// Typed wrapper around Godot's Dictionary class, a dictionary of Variant /// typed elements allocated in the engine in C++. Useful when @@ -364,24 +357,32 @@ namespace Godot.Collections /// </summary> /// <typeparam name="TKey">The type of the dictionary's keys.</typeparam> /// <typeparam name="TValue">The type of the dictionary's values.</typeparam> - public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue> + public sealed class Dictionary<TKey, TValue> : + IDictionary<TKey, TValue>, IGenericGodotDictionary { - private readonly Dictionary _objectDict; + private readonly Dictionary _underlyingDict; - internal static int valTypeEncoding; - internal static IntPtr valTypeClass; + internal ref godot_dictionary NativeValue => ref _underlyingDict.NativeValue; - static Dictionary() - { - Dictionary.godot_icall_Dictionary_Generic_GetValueTypeInfo(typeof(TValue), out valTypeEncoding, out valTypeClass); - } + // ReSharper disable StaticMemberInGenericType + // Warning is about unique static fields being created for each generic type combination: + // https://www.jetbrains.com/help/resharper/StaticMemberInGenericType.html + // In our case this is exactly what we want. + private static readonly Type TypeOfKeys = typeof(TKey); + + private static readonly Type TypeOfValues = typeof(TValue); + // ReSharper restore StaticMemberInGenericType + + Dictionary IGenericGodotDictionary.UnderlyingDictionary => _underlyingDict; + Type IGenericGodotDictionary.TypeOfKeys => TypeOfKeys; + Type IGenericGodotDictionary.TypeOfValues => TypeOfValues; /// <summary> /// Constructs a new empty <see cref="Dictionary{TKey, TValue}"/>. /// </summary> public Dictionary() { - _objectDict = new Dictionary(); + _underlyingDict = new Dictionary(); } /// <summary> @@ -391,19 +392,13 @@ namespace Godot.Collections /// <returns>A new Godot Dictionary.</returns> public Dictionary(IDictionary<TKey, TValue> dictionary) { - _objectDict = new Dictionary(); + _underlyingDict = new Dictionary(); if (dictionary == null) throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'"); - // TODO: Can be optimized - - IntPtr godotDictionaryPtr = GetPtr(); - foreach (KeyValuePair<TKey, TValue> entry in dictionary) - { - Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, entry.Key, entry.Value); - } + Add(entry.Key, entry.Value); } /// <summary> @@ -413,18 +408,12 @@ namespace Godot.Collections /// <returns>A new Godot Dictionary.</returns> public Dictionary(Dictionary dictionary) { - _objectDict = dictionary; + _underlyingDict = dictionary; } - internal Dictionary(IntPtr handle) - { - _objectDict = new Dictionary(handle); - } - - internal Dictionary(DictionarySafeHandle handle) - { - _objectDict = new Dictionary(handle); - } + // Explicit name to make it very clear + internal static Dictionary<TKey, TValue> CreateTakingOwnershipOfDisposableValue(godot_dictionary nativeValueToOwn) + => new Dictionary<TKey, TValue>(Dictionary.CreateTakingOwnershipOfDisposableValue(nativeValueToOwn)); /// <summary> /// Converts this typed <see cref="Dictionary{TKey, TValue}"/> to an untyped <see cref="Dictionary"/>. @@ -432,12 +421,7 @@ namespace Godot.Collections /// <param name="from">The typed dictionary to convert.</param> public static explicit operator Dictionary(Dictionary<TKey, TValue> from) { - return from._objectDict; - } - - internal IntPtr GetPtr() - { - return _objectDict.GetPtr(); + return from._underlyingDict; } /// <summary> @@ -447,7 +431,7 @@ namespace Godot.Collections /// <returns>A new Godot Dictionary.</returns> public Dictionary<TKey, TValue> Duplicate(bool deep = false) { - return new Dictionary<TKey, TValue>(_objectDict.Duplicate(deep)); + return new Dictionary<TKey, TValue>(_underlyingDict.Duplicate(deep)); } // IDictionary<TKey, TValue> @@ -458,8 +442,16 @@ namespace Godot.Collections /// <value>The value at the given <paramref name="key"/>.</value> public TValue this[TKey key] { - get { return (TValue)Dictionary.godot_icall_Dictionary_GetValue_Generic(_objectDict.GetPtr(), key, valTypeEncoding, valTypeClass); } - set { _objectDict[key] = value; } + get + { + Dictionary.godot_icall_Dictionary_GetValue(ref _underlyingDict.NativeValue, key, out godot_variant value); + unsafe + { + using (value) + return (TValue)Marshaling.variant_to_mono_object_of_type(&value, TypeOfValues); + } + } + set => _underlyingDict[key] = value; } /// <summary> @@ -469,8 +461,9 @@ namespace Godot.Collections { get { - IntPtr handle = Dictionary.godot_icall_Dictionary_Keys(_objectDict.GetPtr()); - return new Array<TKey>(new ArraySafeHandle(handle)); + godot_array keyArray; + Dictionary.godot_icall_Dictionary_Keys(ref _underlyingDict.NativeValue, out keyArray); + return Array<TKey>.CreateTakingOwnershipOfDisposableValue(keyArray); } } @@ -481,15 +474,25 @@ namespace Godot.Collections { get { - IntPtr handle = Dictionary.godot_icall_Dictionary_Values(_objectDict.GetPtr()); - return new Array<TValue>(new ArraySafeHandle(handle)); + godot_array valuesArray; + Dictionary.godot_icall_Dictionary_Values(ref _underlyingDict.NativeValue, out valuesArray); + return Array<TValue>.CreateTakingOwnershipOfDisposableValue(valuesArray); } } private KeyValuePair<TKey, TValue> GetKeyValuePair(int index) { - Dictionary.godot_icall_Dictionary_KeyValuePairAt_Generic(GetPtr(), index, out object key, out object value, valTypeEncoding, valTypeClass); - return new KeyValuePair<TKey, TValue>((TKey)key, (TValue)value); + Dictionary.godot_icall_Dictionary_KeyValuePairAt(ref _underlyingDict.NativeValue, index, out var vKey, out var vValue); + unsafe + { + using (vKey) + using (vValue) + { + var key = Marshaling.variant_to_mono_object_of_type(&vKey, TypeOfKeys); + var value = Marshaling.variant_to_mono_object_of_type(&vValue, TypeOfValues); + return new KeyValuePair<TKey, TValue>((TKey)key, (TValue)value); + } + } } /// <summary> @@ -500,7 +503,7 @@ namespace Godot.Collections /// <param name="value">The object to add.</param> public void Add(TKey key, TValue value) { - _objectDict.Add(key, value); + _underlyingDict.Add(key, value); } /// <summary> @@ -510,7 +513,7 @@ namespace Godot.Collections /// <returns>Whether or not this dictionary contains the given key.</returns> public bool ContainsKey(TKey key) { - return _objectDict.Contains(key); + return _underlyingDict.Contains(key); } /// <summary> @@ -519,7 +522,7 @@ namespace Godot.Collections /// <param name="key">The key of the element to remove.</param> public bool Remove(TKey key) { - return Dictionary.godot_icall_Dictionary_RemoveKey(GetPtr(), key); + return Dictionary.godot_icall_Dictionary_RemoveKey(ref _underlyingDict.NativeValue, key); } /// <summary> @@ -530,8 +533,18 @@ namespace Godot.Collections /// <returns>If an object was found for the given <paramref name="key"/>.</returns> public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { - bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out object retValue, valTypeEncoding, valTypeClass); - value = found ? (TValue)retValue : default; + bool found = Dictionary.godot_icall_Dictionary_TryGetValue(ref _underlyingDict.NativeValue, key, out godot_variant retValue); + + unsafe + { + using (retValue) + { + value = found ? + (TValue)Marshaling.variant_to_mono_object_of_type(&retValue, TypeOfValues) : + default; + } + } + return found; } @@ -542,16 +555,13 @@ namespace Godot.Collections /// This is also known as the size or length of the dictionary. /// </summary> /// <returns>The number of elements.</returns> - public int Count - { - get { return _objectDict.Count; } - } + public int Count => _underlyingDict.Count; bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false; void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) { - _objectDict.Add(item.Key, item.Value); + _underlyingDict.Add(item.Key, item.Value); } /// <summary> @@ -559,12 +569,12 @@ namespace Godot.Collections /// </summary> public void Clear() { - _objectDict.Clear(); + _underlyingDict.Clear(); } bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) { - return _objectDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value)); + return _underlyingDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value)); } /// <summary> @@ -595,8 +605,7 @@ namespace Godot.Collections bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) { - return Dictionary.godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value); - ; + return Dictionary.godot_icall_Dictionary_Remove(ref _underlyingDict.NativeValue, item.Key, item.Value); } // IEnumerable<KeyValuePair<TKey, TValue>> @@ -613,15 +622,12 @@ namespace Godot.Collections } } - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); /// <summary> /// Converts this <see cref="Dictionary{TKey, TValue}"/> to a string. /// </summary> /// <returns>A string representation of this dictionary.</returns> - public override string ToString() => _objectDict.ToString(); + public override string ToString() => _underlyingDict.ToString(); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs index df130a5c77..7922f38ac5 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.CompilerServices; using Godot.Collections; +using Godot.NativeInterop; namespace Godot { @@ -12,10 +13,12 @@ namespace Godot /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam> public Array<T> GetNodesInGroup<T>(StringName group) where T : class { - return new Array<T>(godot_icall_SceneTree_get_nodes_in_group_Generic(GetPtr(this), StringName.GetPtr(group), typeof(T))); + godot_array array; + godot_icall_SceneTree_get_nodes_in_group_Generic(GetPtr(this), ref group.NativeValue, typeof(T), out array); + return Array<T>.CreateTakingOwnershipOfDisposableValue(array); } [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern IntPtr godot_icall_SceneTree_get_nodes_in_group_Generic(IntPtr obj, IntPtr group, Type elemType); + internal static extern void godot_icall_SceneTree_get_nodes_in_group_Generic(IntPtr obj, ref godot_string_name group, Type elemType, out godot_array dest); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs index 236d0666bc..e8ea8f379b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs @@ -6,6 +6,7 @@ using real_t = System.Single; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; +using Godot.NativeInterop; namespace Godot { @@ -26,9 +27,10 @@ namespace Godot /// <param name="bytes">Byte array that will be decoded to a <c>Variant</c>.</param> /// <param name="allowObjects">If objects should be decoded.</param> /// <returns>The decoded <c>Variant</c>.</returns> - public static object Bytes2Var(byte[] bytes, bool allowObjects = false) + public static unsafe object Bytes2Var(byte[] bytes, bool allowObjects = false) { - return godot_icall_GD_bytes2var(bytes, allowObjects); + using var varBytes = Marshaling.mono_array_to_PackedByteArray(bytes); + return godot_icall_GD_bytes2var(&varBytes, allowObjects); } /// <summary> @@ -527,7 +529,7 @@ namespace Godot /// <returns>If the class exists in <see cref="ClassDB"/>.</returns> public static bool TypeExists(StringName type) { - return godot_icall_GD_type_exists(StringName.GetPtr(type)); + return godot_icall_GD_type_exists(ref type.NativeValue); } /// <summary> @@ -539,9 +541,14 @@ namespace Godot /// <param name="var">Variant that will be encoded.</param> /// <param name="fullObjects">If objects should be serialized.</param> /// <returns>The <c>Variant</c> encoded as an array of bytes.</returns> - public static byte[] Var2Bytes(object var, bool fullObjects = false) + public static unsafe byte[] Var2Bytes(object var, bool fullObjects = false) { - return godot_icall_GD_var2bytes(var, fullObjects); + godot_packed_byte_array varBytes; + godot_icall_GD_var2bytes(var, fullObjects, &varBytes); + using (varBytes) + { + return Marshaling.PackedByteArray_to_mono_array(&varBytes); + } } /// <summary> @@ -576,7 +583,7 @@ namespace Godot } [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern object godot_icall_GD_bytes2var(byte[] bytes, bool allowObjects); + internal static extern unsafe object godot_icall_GD_bytes2var(godot_packed_byte_array* bytes, bool allowObjects); [MethodImpl(MethodImplOptions.InternalCall)] internal static extern object godot_icall_GD_convert(object what, Variant.Type type); @@ -636,10 +643,10 @@ namespace Godot internal static extern object godot_icall_GD_str2var(string str); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern bool godot_icall_GD_type_exists(IntPtr type); + internal static extern bool godot_icall_GD_type_exists(ref godot_string_name type); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern byte[] godot_icall_GD_var2bytes(object what, bool fullObjects); + internal static extern unsafe void godot_icall_GD_var2bytes(object what, bool fullObjects, godot_packed_byte_array* bytes); [MethodImpl(MethodImplOptions.InternalCall)] internal static extern string godot_icall_GD_var2str(object var); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs index 50ae2eb112..733a8ac114 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs @@ -6,149 +6,8 @@ namespace Godot internal static class MarshalUtils { /// <summary> - /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> - /// is <see cref="Collections.Array{T}"/>; otherwise returns <see langword="false"/>. - /// </summary> - /// <exception cref="InvalidOperationException"> - /// Thrown when the given <paramref name="type"/> is not a generic type. - /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. - /// </exception> - private static bool TypeIsGenericArray(Type type) => - type.GetGenericTypeDefinition() == typeof(Collections.Array<>); - - /// <summary> - /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> - /// is <see cref="Collections.Dictionary{TKey, TValue}"/>; otherwise returns <see langword="false"/>. - /// </summary> - /// <exception cref="InvalidOperationException"> - /// Thrown when the given <paramref name="type"/> is not a generic type. - /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. - /// </exception> - private static bool TypeIsGenericDictionary(Type type) => - type.GetGenericTypeDefinition() == typeof(Collections.Dictionary<,>); - - /// <summary> - /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> - /// is <see cref="List{T}"/>; otherwise returns <see langword="false"/>. - /// </summary> - /// <exception cref="InvalidOperationException"> - /// Thrown when the given <paramref name="type"/> is not a generic type. - /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. - /// </exception> - private static bool TypeIsSystemGenericList(Type type) => - type.GetGenericTypeDefinition() == typeof(List<>); - - /// <summary> - /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> - /// is <see cref="Dictionary{TKey, TValue}"/>; otherwise returns <see langword="false"/>. - /// </summary> - /// <exception cref="InvalidOperationException"> - /// Thrown when the given <paramref name="type"/> is not a generic type. - /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. - /// </exception> - private static bool TypeIsSystemGenericDictionary(Type type) => - type.GetGenericTypeDefinition() == typeof(Dictionary<,>); - - /// <summary> - /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> - /// is <see cref="IEnumerable{T}"/>; otherwise returns <see langword="false"/>. - /// </summary> - /// <exception cref="InvalidOperationException"> - /// Thrown when the given <paramref name="type"/> is not a generic type. - /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. - /// </exception> - private static bool TypeIsGenericIEnumerable(Type type) => type.GetGenericTypeDefinition() == typeof(IEnumerable<>); - - /// <summary> - /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> - /// is <see cref="ICollection{T}"/>; otherwise returns <see langword="false"/>. - /// </summary> - /// <exception cref="InvalidOperationException"> - /// Thrown when the given <paramref name="type"/> is not a generic type. - /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. - /// </exception> - private static bool TypeIsGenericICollection(Type type) => type.GetGenericTypeDefinition() == typeof(ICollection<>); - - /// <summary> - /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> - /// is <see cref="IDictionary{TKey, TValue}"/>; otherwise returns <see langword="false"/>. - /// </summary> - /// <exception cref="InvalidOperationException"> - /// Thrown when the given <paramref name="type"/> is not a generic type. - /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. - /// </exception> - private static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>); - - /// <summary> /// Returns <see langword="true"/> if the <see cref="FlagsAttribute"/> is applied to the given type. /// </summary> private static bool TypeHasFlagsAttribute(Type type) => type.IsDefined(typeof(FlagsAttribute), false); - - /// <summary> - /// Returns the generic type definition of <paramref name="type"/>. - /// </summary> - /// <exception cref="InvalidOperationException"> - /// Thrown when the given <paramref name="type"/> is not a generic type. - /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. - /// </exception> - private static void GetGenericTypeDefinition(Type type, out Type genericTypeDefinition) - { - genericTypeDefinition = type.GetGenericTypeDefinition(); - } - - /// <summary> - /// Gets the element type for the given <paramref name="arrayType"/>. - /// </summary> - /// <param name="arrayType">Type for the generic array.</param> - /// <param name="elementType">Element type for the generic array.</param> - /// <exception cref="InvalidOperationException"> - /// Thrown when the given <paramref name="arrayType"/> is not a generic type. - /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. - /// </exception> - private static void ArrayGetElementType(Type arrayType, out Type elementType) - { - elementType = arrayType.GetGenericArguments()[0]; - } - - /// <summary> - /// Gets the key type and the value type for the given <paramref name="dictionaryType"/>. - /// </summary> - /// <param name="dictionaryType">The type for the generic dictionary.</param> - /// <param name="keyType">Key type for the generic dictionary.</param> - /// <param name="valueType">Value type for the generic dictionary.</param> - /// <exception cref="InvalidOperationException"> - /// Thrown when the given <paramref name="dictionaryType"/> is not a generic type. - /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. - /// </exception> - private static void DictionaryGetKeyValueTypes(Type dictionaryType, out Type keyType, out Type valueType) - { - var genericArgs = dictionaryType.GetGenericArguments(); - keyType = genericArgs[0]; - valueType = genericArgs[1]; - } - - /// <summary> - /// Constructs a new <see cref="Type"/> from <see cref="Collections.Array{T}"/> - /// where the generic type for the elements is <paramref name="elemType"/>. - /// </summary> - /// <param name="elemType">Element type for the array.</param> - /// <returns>The generic array type with the specified element type.</returns> - private static Type MakeGenericArrayType(Type elemType) - { - return typeof(Collections.Array<>).MakeGenericType(elemType); - } - - /// <summary> - /// Constructs a new <see cref="Type"/> from <see cref="Collections.Dictionary{TKey, TValue}"/> - /// where the generic type for the keys is <paramref name="keyType"/> and - /// for the values is <paramref name="valueType"/>. - /// </summary> - /// <param name="keyType">Key type for the dictionary.</param> - /// <param name="valueType">Key type for the dictionary.</param> - /// <returns>The generic dictionary type with the specified key and value types.</returns> - private static Type MakeGenericDictionaryType(Type keyType, Type valueType) - { - return typeof(Collections.Dictionary<,>).MakeGenericType(keyType, valueType); - } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs new file mode 100644 index 0000000000..6ee8cbc0bc --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs @@ -0,0 +1,438 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if REAL_T_IS_DOUBLE +using real_t = System.Double; +#else +using real_t = System.Single; + +#endif + +namespace Godot.NativeInterop +{ + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_bool + { + public byte _value; + + public unsafe godot_bool(bool value) => _value = *(byte*)&value; + + public static unsafe implicit operator bool(godot_bool godotBool) => *(bool*)&godotBool._value; + public static implicit operator godot_bool(bool @bool) => new godot_bool(@bool); + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_ref : IDisposable + { + internal IntPtr _reference; + + public void Dispose() + { + if (_reference == IntPtr.Zero) + return; + NativeFuncs.godotsharp_ref_destroy(ref this); + _reference = IntPtr.Zero; + } + } + + [SuppressMessage("ReSharper", "InconsistentNaming")] + internal enum godot_variant_call_error_error + { + GODOT_CALL_ERROR_CALL_OK = 0, + GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD, + GODOT_CALL_ERROR_CALL_ERROR_INVALID_ARGUMENT, + GODOT_CALL_ERROR_CALL_ERROR_TOO_MANY_ARGUMENTS, + GODOT_CALL_ERROR_CALL_ERROR_TOO_FEW_ARGUMENTS, + GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL, + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_variant_call_error + { + godot_variant_call_error_error error; + int argument; + int expected; + } + + [StructLayout(LayoutKind.Explicit)] + // ReSharper disable once InconsistentNaming + internal struct godot_variant : IDisposable + { + // Variant.Type is generated as an enum of type long, so we can't use for the field as it must only take 32-bits. + [FieldOffset(0)] private int _typeField; + + // There's padding here + + [FieldOffset(8)] internal godot_variant_data _data; + + public Variant.Type _type + { + get => (Variant.Type)_typeField; + set => _typeField = (int)value; + } + + [StructLayout(LayoutKind.Explicit)] + // ReSharper disable once InconsistentNaming + internal unsafe struct godot_variant_data + { + [FieldOffset(0)] public godot_bool _bool; + [FieldOffset(0)] public long _int; + [FieldOffset(0)] public double _float; + [FieldOffset(0)] public Transform2D* _transform2d; + [FieldOffset(0)] public AABB* _aabb; + [FieldOffset(0)] public Basis* _basis; + [FieldOffset(0)] public Transform3D* _transform3d; + [FieldOffset(0)] public Vector4* _vector4; + [FieldOffset(0)] public Vector4i* _vector4i; + [FieldOffset(0)] public Projection* _projection; + [FieldOffset(0)] private godot_variant_data_mem _mem; + + // The following fields are not in the C++ union, but this is how they're stored in _mem. + [FieldOffset(0)] public godot_string_name _m_string_name; + [FieldOffset(0)] public godot_string _m_string; + [FieldOffset(0)] public Vector3 _m_vector3; + [FieldOffset(0)] public Vector3i _m_vector3i; + [FieldOffset(0)] public Vector2 _m_vector2; + [FieldOffset(0)] public Vector2i _m_vector2i; + [FieldOffset(0)] public Rect2 _m_rect2; + [FieldOffset(0)] public Rect2i _m_rect2i; + [FieldOffset(0)] public Plane _m_plane; + [FieldOffset(0)] public Quaternion _m_quaternion; + [FieldOffset(0)] public Color _m_color; + [FieldOffset(0)] public godot_node_path _m_node_path; + [FieldOffset(0)] public RID _m_rid; + [FieldOffset(0)] public godot_variant_obj_data _m_obj_data; + [FieldOffset(0)] public godot_callable _m_callable; + [FieldOffset(0)] public godot_signal _m_signal; + [FieldOffset(0)] public godot_dictionary _m_dictionary; + [FieldOffset(0)] public godot_array _m_array; + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_variant_obj_data + { + public UInt64 id; + public IntPtr obj; + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + private struct godot_variant_data_mem + { +#pragma warning disable 169 + private real_t _mem0; + private real_t _mem1; + private real_t _mem2; + private real_t _mem3; +#pragma warning restore 169 + } + } + + public void Dispose() + { + switch (_type) + { + case Variant.Type.Nil: + case Variant.Type.Bool: + case Variant.Type.Int: + case Variant.Type.Float: + case Variant.Type.Vector2: + case Variant.Type.Vector2i: + case Variant.Type.Rect2: + case Variant.Type.Rect2i: + case Variant.Type.Vector3: + case Variant.Type.Vector3i: + case Variant.Type.Plane: + case Variant.Type.Quaternion: + case Variant.Type.Color: + case Variant.Type.Rid: + return; + } + + NativeFuncs.godotsharp_variant_destroy(ref this); + _type = Variant.Type.Nil; + } + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_string : IDisposable + { + internal IntPtr _ptr; + + public void Dispose() + { + if (_ptr == IntPtr.Zero) + return; + NativeFuncs.godotsharp_string_destroy(ref this); + _ptr = IntPtr.Zero; + } + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_string_name : IDisposable + { + internal IntPtr _data; + + public void Dispose() + { + if (_data == IntPtr.Zero) + return; + NativeFuncs.godotsharp_string_name_destroy(ref this); + _data = IntPtr.Zero; + } + + // An static method because an instance method could result in a hidden copy if called on an `in` parameter. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsEmpty(in godot_string_name name) => + // This is all that's needed to check if it's empty. Equivalent to `== StringName()` in C++. + name._data == IntPtr.Zero; + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_node_path : IDisposable + { + internal IntPtr _data; + + public void Dispose() + { + if (_data == IntPtr.Zero) + return; + NativeFuncs.godotsharp_node_path_destroy(ref this); + _data = IntPtr.Zero; + } + + // An static method because an instance method could result in a hidden copy if called on an `in` parameter. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsEmpty(in godot_node_path nodePath) => + // This is all that's needed to check if it's empty. It's what the `is_empty()` C++ method does. + nodePath._data == IntPtr.Zero; + } + + [StructLayout(LayoutKind.Explicit)] + // ReSharper disable once InconsistentNaming + internal struct godot_signal : IDisposable + { + [FieldOffset(0)] public godot_string_name _name; + + // There's padding here on 32-bit + + [FieldOffset(8)] public UInt64 _objectId; + + public void Dispose() + { + if (_name._data == IntPtr.Zero) + return; + NativeFuncs.godotsharp_signal_destroy(ref this); + _name._data = IntPtr.Zero; + } + } + + [StructLayout(LayoutKind.Explicit)] + // ReSharper disable once InconsistentNaming + internal struct godot_callable : IDisposable + { + [FieldOffset(0)] public godot_string_name _method; + + // There's padding here on 32-bit + + [FieldOffset(8)] public UInt64 _objectId; + [FieldOffset(8)] public IntPtr _custom; + + public void Dispose() + { + if (_method._data == IntPtr.Zero && _custom == IntPtr.Zero) + return; + NativeFuncs.godotsharp_callable_destroy(ref this); + _method._data = IntPtr.Zero; + _custom = IntPtr.Zero; + } + } + + // A correctly constructed value needs to call the native default constructor to allocate `_p`. + // Don't pass a C# default constructed `godot_array` to native code, unless it's going to + // be re-assigned a new value (the copy constructor checks if `_p` is null so that's fine). + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_array : IDisposable + { + internal IntPtr _p; + + public void Dispose() + { + if (_p == IntPtr.Zero) + return; + NativeFuncs.godotsharp_array_destroy(ref this); + _p = IntPtr.Zero; + } + } + + // IMPORTANT: + // A correctly constructed value needs to call the native default constructor to allocate `_p`. + // Don't pass a C# default constructed `godot_dictionary` to native code, unless it's going to + // be re-assigned a new value (the copy constructor checks if `_p` is null so that's fine). + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_dictionary : IDisposable + { + internal IntPtr _p; + + public void Dispose() + { + if (_p == IntPtr.Zero) + return; + NativeFuncs.godotsharp_dictionary_destroy(ref this); + _p = IntPtr.Zero; + } + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_packed_byte_array : IDisposable + { + internal IntPtr _writeProxy; + internal IntPtr _ptr; + + public void Dispose() + { + if (_ptr == IntPtr.Zero) + return; + NativeFuncs.godotsharp_packed_byte_array_destroy(ref this); + _ptr = IntPtr.Zero; + } + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_packed_int32_array : IDisposable + { + internal IntPtr _writeProxy; + internal IntPtr _ptr; + + public void Dispose() + { + if (_ptr == IntPtr.Zero) + return; + NativeFuncs.godotsharp_packed_int32_array_destroy(ref this); + _ptr = IntPtr.Zero; + } + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_packed_int64_array : IDisposable + { + internal IntPtr _writeProxy; + internal IntPtr _ptr; + + public void Dispose() + { + if (_ptr == IntPtr.Zero) + return; + NativeFuncs.godotsharp_packed_int64_array_destroy(ref this); + _ptr = IntPtr.Zero; + } + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_packed_float32_array : IDisposable + { + internal IntPtr _writeProxy; + internal IntPtr _ptr; + + public void Dispose() + { + if (_ptr == IntPtr.Zero) + return; + NativeFuncs.godotsharp_packed_float32_array_destroy(ref this); + _ptr = IntPtr.Zero; + } + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_packed_float64_array : IDisposable + { + internal IntPtr _writeProxy; + internal IntPtr _ptr; + + public void Dispose() + { + if (_ptr == IntPtr.Zero) + return; + NativeFuncs.godotsharp_packed_float64_array_destroy(ref this); + _ptr = IntPtr.Zero; + } + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_packed_string_array : IDisposable + { + internal IntPtr _writeProxy; + internal IntPtr _ptr; + + public void Dispose() + { + if (_ptr == IntPtr.Zero) + return; + NativeFuncs.godotsharp_packed_string_array_destroy(ref this); + _ptr = IntPtr.Zero; + } + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_packed_vector2_array : IDisposable + { + internal IntPtr _writeProxy; + internal IntPtr _ptr; + + public void Dispose() + { + if (_ptr == IntPtr.Zero) + return; + NativeFuncs.godotsharp_packed_vector2_array_destroy(ref this); + _ptr = IntPtr.Zero; + } + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_packed_vector3_array : IDisposable + { + internal IntPtr _writeProxy; + internal IntPtr _ptr; + + public void Dispose() + { + if (_ptr == IntPtr.Zero) + return; + NativeFuncs.godotsharp_packed_vector3_array_destroy(ref this); + _ptr = IntPtr.Zero; + } + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct godot_packed_color_array : IDisposable + { + internal IntPtr _writeProxy; + internal IntPtr _ptr; + + public void Dispose() + { + if (_ptr == IntPtr.Zero) + return; + NativeFuncs.godotsharp_packed_color_array_destroy(ref this); + _ptr = IntPtr.Zero; + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs new file mode 100644 index 0000000000..08d49bb937 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs @@ -0,0 +1,32 @@ +using System; +using System.Runtime.CompilerServices; + +namespace Godot.NativeInterop +{ + internal static class InteropUtils + { + public static Object UnmanagedGetManaged(IntPtr unmanaged) + { + // TODO: Move to C# + return internal_unmanaged_get_managed(unmanaged); + } + + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern Object internal_unmanaged_get_managed(IntPtr unmanaged); + + public static void TieManagedToUnmanaged(Object managed, IntPtr unmanaged) + { + // TODO: Move to C# + internal_tie_managed_to_unmanaged(managed, unmanaged); + } + + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern void internal_tie_managed_to_unmanaged(Object managed, IntPtr unmanaged); + + public static unsafe Object EngineGetSingleton(string name) + { + using godot_string src = Marshaling.mono_string_to_godot(name); + return UnmanagedGetManaged(NativeFuncs.godotsharp_engine_get_singleton(&src)); + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs new file mode 100644 index 0000000000..9b6f9633d1 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs @@ -0,0 +1,1370 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Runtime.InteropServices; + +// ReSharper disable InconsistentNaming + +namespace Godot.NativeInterop +{ + // We want to use full name qualifiers here even if redundant for clarity + [SuppressMessage("ReSharper", "RedundantNameQualifier")] + internal static class Marshaling + { + public static unsafe void SetFieldValue(FieldInfo fieldInfo, object obj, godot_variant* value) + { + var valueObj = variant_to_mono_object_of_type(value, fieldInfo.FieldType); + fieldInfo.SetValue(obj, valueObj); + } + + public static Variant.Type managed_to_variant_type(Type type, ref bool r_nil_is_variant) + { + switch (Type.GetTypeCode(type)) + { + case TypeCode.Boolean: + return Variant.Type.Bool; + case TypeCode.Char: + return Variant.Type.Int; + case TypeCode.SByte: + return Variant.Type.Int; + case TypeCode.Int16: + return Variant.Type.Int; + case TypeCode.Int32: + return Variant.Type.Int; + case TypeCode.Int64: + return Variant.Type.Int; + case TypeCode.Byte: + return Variant.Type.Int; + case TypeCode.UInt16: + return Variant.Type.Int; + case TypeCode.UInt32: + return Variant.Type.Int; + case TypeCode.UInt64: + return Variant.Type.Int; + case TypeCode.Single: + return Variant.Type.Float; + case TypeCode.Double: + return Variant.Type.Float; + case TypeCode.String: + return Variant.Type.String; + default: + { + if (type == typeof(Vector2)) + return Variant.Type.Vector2; + + if (type == typeof(Vector2i)) + return Variant.Type.Vector2i; + + if (type == typeof(Rect2)) + return Variant.Type.Rect2; + + if (type == typeof(Rect2i)) + return Variant.Type.Rect2i; + + if (type == typeof(Transform2D)) + return Variant.Type.Transform2d; + + if (type == typeof(Vector3)) + return Variant.Type.Vector3; + + if (type == typeof(Vector3i)) + return Variant.Type.Vector3i; + + if (type == typeof(Vector4)) + return Variant.Type.Vector4; + + if (type == typeof(Vector4i)) + return Variant.Type.Vector4i; + + if (type == typeof(Basis)) + return Variant.Type.Basis; + + if (type == typeof(Quaternion)) + return Variant.Type.Quaternion; + + if (type == typeof(Transform3D)) + return Variant.Type.Transform3d; + + if (type == typeof(Projection)) + return Variant.Type.Projection; + + if (type == typeof(AABB)) + return Variant.Type.Aabb; + + if (type == typeof(Color)) + return Variant.Type.Color; + + if (type == typeof(Plane)) + return Variant.Type.Plane; + + if (type == typeof(Callable)) + return Variant.Type.Callable; + + if (type == typeof(SignalInfo)) + return Variant.Type.Signal; + + if (type.IsEnum) + return Variant.Type.Int; + + if (type.IsArray || type.IsSZArray) + { + if (type == typeof(Byte[])) + return Variant.Type.PackedByteArray; + + if (type == typeof(Int32[])) + return Variant.Type.PackedInt32Array; + + if (type == typeof(Int64[])) + return Variant.Type.PackedInt64Array; + + if (type == typeof(float[])) + return Variant.Type.PackedFloat32Array; + + if (type == typeof(double[])) + return Variant.Type.PackedFloat64Array; + + if (type == typeof(string[])) + return Variant.Type.PackedStringArray; + + if (type == typeof(Vector2[])) + return Variant.Type.PackedVector2Array; + + if (type == typeof(Vector3[])) + return Variant.Type.PackedVector3Array; + + if (type == typeof(Color[])) + return Variant.Type.PackedColorArray; + + if (typeof(Godot.Object[]).IsAssignableFrom(type)) + return Variant.Type.Array; + + if (type == typeof(object[])) + return Variant.Type.Array; + } + else if (type.IsGenericType) + { + var genericTypeDefinition = type.GetGenericTypeDefinition(); + + if (genericTypeDefinition == typeof(Collections.Dictionary<,>)) + return Variant.Type.Dictionary; + + if (genericTypeDefinition == typeof(Collections.Array<>)) + return Variant.Type.Array; + + if (genericTypeDefinition == typeof(System.Collections.Generic.Dictionary<,>)) + return Variant.Type.Dictionary; + + if (genericTypeDefinition == typeof(System.Collections.Generic.List<>)) + return Variant.Type.Array; + + if (genericTypeDefinition == typeof(IDictionary<,>)) + return Variant.Type.Dictionary; + + if (genericTypeDefinition == typeof(ICollection<>) || genericTypeDefinition == typeof(IEnumerable<>)) + return Variant.Type.Array; + } + else if (type == typeof(object)) + { + r_nil_is_variant = true; + return Variant.Type.Nil; + } + else + { + if (typeof(Godot.Object).IsAssignableFrom(type)) + return Variant.Type.Object; + + if (typeof(StringName) == type) + return Variant.Type.StringName; + + if (typeof(NodePath) == type) + return Variant.Type.NodePath; + + if (typeof(RID) == type) + return Variant.Type.Rid; + + if (typeof(Collections.Dictionary) == type || typeof(System.Collections.IDictionary) == type) + return Variant.Type.Dictionary; + + if (typeof(Collections.Array) == type || + typeof(System.Collections.ICollection) == type || + typeof(System.Collections.IEnumerable) == type) + { + return Variant.Type.Array; + } + } + + break; + } + } + + r_nil_is_variant = false; + + // Unknown + return Variant.Type.Nil; + } + + public static bool try_get_array_element_type(Type p_array_type, out Type r_elem_type) + { + if (p_array_type.IsArray || p_array_type.IsSZArray) + { + r_elem_type = p_array_type.GetElementType(); + return true; + } + else if (p_array_type.IsGenericType) + { + var genericTypeDefinition = p_array_type.GetGenericTypeDefinition(); + + if (typeof(Collections.Array) == genericTypeDefinition || + typeof(System.Collections.Generic.List<>) == genericTypeDefinition || + typeof(System.Collections.ICollection) == genericTypeDefinition || + typeof(System.Collections.IEnumerable) == genericTypeDefinition) + { + r_elem_type = p_array_type.GetGenericArguments()[0]; + return true; + } + } + + r_elem_type = null; + return false; + } + + /* TODO: Reflection and type checking each time is slow. This will be replaced with source generators. */ + + public static godot_variant mono_object_to_variant(object p_obj) + { + return mono_object_to_variant_impl(p_obj); + } + + public static godot_variant mono_object_to_variant_no_err(object p_obj) + { + return mono_object_to_variant_impl(p_obj); + } + + // TODO: Only called from C++. Remove once no longer needed. + private static unsafe void mono_object_to_variant_out(object p_obj, bool p_fail_with_err, godot_variant* r_ret) + => *r_ret = mono_object_to_variant_impl(p_obj, p_fail_with_err); + + private static unsafe godot_variant mono_object_to_variant_impl(object p_obj, bool p_fail_with_err = true) + { + if (p_obj == null) + return new godot_variant(); + + switch (p_obj) + { + case bool @bool: + return VariantUtils.CreateFromBool(@bool); + case char @char: + return VariantUtils.CreateFromInt(@char); + case SByte @int8: + return VariantUtils.CreateFromInt(@int8); + case Int16 @int16: + return VariantUtils.CreateFromInt(@int16); + case Int32 @int32: + return VariantUtils.CreateFromInt(@int32); + case Int64 @int64: + return VariantUtils.CreateFromInt(@int64); + case Byte @uint8: + return VariantUtils.CreateFromInt(@uint8); + case UInt16 @uint16: + return VariantUtils.CreateFromInt(@uint16); + case UInt32 @uint32: + return VariantUtils.CreateFromInt(@uint32); + case UInt64 @uint64: + return VariantUtils.CreateFromInt(@uint64); + case float @float: + return VariantUtils.CreateFromFloat(@float); + case double @double: + return VariantUtils.CreateFromFloat(@double); + case Vector2 @vector2: + return VariantUtils.CreateFromVector2(@vector2); + case Vector2i @vector2i: + return VariantUtils.CreateFromVector2i(@vector2i); + case Rect2 @rect2: + return VariantUtils.CreateFromRect2(@rect2); + case Rect2i @rect2i: + return VariantUtils.CreateFromRect2i(@rect2i); + case Transform2D @transform2D: + return VariantUtils.CreateFromTransform2D(@transform2D); + case Vector3 @vector3: + return VariantUtils.CreateFromVector3(@vector3); + case Vector3i @vector3i: + return VariantUtils.CreateFromVector3i(@vector3i); + case Vector4 @vector4: + return VariantUtils.CreateFromVector4(@vector4); + case Vector4i @vector4i: + return VariantUtils.CreateFromVector4i(@vector4i); + case Basis @basis: + return VariantUtils.CreateFromBasis(@basis); + case Quaternion @quaternion: + return VariantUtils.CreateFromQuaternion(@quaternion); + case Transform3D @transform3d: + return VariantUtils.CreateFromTransform3D(@transform3d); + case Projection @projection: + return VariantUtils.CreateFromProjection(@projection); + case AABB @aabb: + return VariantUtils.CreateFromAABB(@aabb); + case Color @color: + return VariantUtils.CreateFromColor(@color); + case Plane @plane: + return VariantUtils.CreateFromPlane(@plane); + case Callable @callable: + return VariantUtils.CreateFromCallableTakingOwnershipOfDisposableValue( + ConvertCallableToNative(ref @callable)); + case SignalInfo @signalInfo: + return VariantUtils.CreateFromSignalTakingOwnershipOfDisposableValue( + ConvertSignalToNative(ref @signalInfo)); + case Enum @enum: + return VariantUtils.CreateFromInt(Convert.ToInt64(@enum)); + case string @string: + { + return VariantUtils.CreateFromStringTakingOwnershipOfDisposableValue( + mono_string_to_godot(@string)); + } + case Byte[] byteArray: + { + using godot_packed_byte_array array = mono_array_to_PackedByteArray(byteArray); + return VariantUtils.CreateFromPackedByteArray(&array); + } + case Int32[] int32Array: + { + using godot_packed_int32_array array = mono_array_to_PackedInt32Array(int32Array); + return VariantUtils.CreateFromPackedInt32Array(&array); + } + case Int64[] int64Array: + { + using godot_packed_int64_array array = mono_array_to_PackedInt64Array(int64Array); + return VariantUtils.CreateFromPackedInt64Array(&array); + } + case float[] floatArray: + { + using godot_packed_float32_array array = mono_array_to_PackedFloat32Array(floatArray); + return VariantUtils.CreateFromPackedFloat32Array(&array); + } + case double[] doubleArray: + { + using godot_packed_float64_array array = mono_array_to_PackedFloat64Array(doubleArray); + return VariantUtils.CreateFromPackedFloat64Array(&array); + } + case string[] stringArray: + { + using godot_packed_string_array array = mono_array_to_PackedStringArray(stringArray); + return VariantUtils.CreateFromPackedStringArray(&array); + } + case Vector2[] vector2Array: + { + using godot_packed_vector2_array array = mono_array_to_PackedVector2Array(vector2Array); + return VariantUtils.CreateFromPackedVector2Array(&array); + } + case Vector3[] vector3Array: + { + using godot_packed_vector3_array array = mono_array_to_PackedVector3Array(vector3Array); + return VariantUtils.CreateFromPackedVector3Array(&array); + } + case Color[] colorArray: + { + using godot_packed_color_array array = mono_array_to_PackedColorArray(colorArray); + return VariantUtils.CreateFromPackedColorArray(&array); + } + case Godot.Object[] godotObjectArray: + { + // ReSharper disable once CoVariantArrayConversion + using godot_array array = mono_array_to_Array(godotObjectArray); + return VariantUtils.CreateFromArray(&array); + } + case object[] objectArray: // Last one to avoid catching others like string[] and Godot.Object[] + { + // The pattern match for `object[]` catches arrays on any reference type, + // so we need to check the actual type to make sure it's truly `object[]`. + if (objectArray.GetType() == typeof(object[])) + { + using godot_array array = mono_array_to_Array(objectArray); + return VariantUtils.CreateFromArray(&array); + } + + if (p_fail_with_err) + { + GD.PushError("Attempted to convert a managed array of unmarshallable element type to Variant."); + return new godot_variant(); + } + else + { + return new godot_variant(); + } + } + case Godot.Object godotObject: + return VariantUtils.CreateFromGodotObject(godotObject.NativeInstance); + case StringName stringName: + return VariantUtils.CreateFromStringName(ref stringName.NativeValue); + case NodePath nodePath: + return VariantUtils.CreateFromNodePath(ref nodePath.NativeValue); + case RID rid: + return VariantUtils.CreateFromRID(rid); + case Collections.Dictionary godotDictionary: + return VariantUtils.CreateFromDictionary(godotDictionary.NativeValue); + case Collections.Array godotArray: + return VariantUtils.CreateFromArray(godotArray.NativeValue); + case Collections.IGenericGodotDictionary genericGodotDictionary: + { + var godotDict = genericGodotDictionary.UnderlyingDictionary; + if (godotDict == null) + return new godot_variant(); + return VariantUtils.CreateFromDictionary(godotDict.NativeValue); + } + case Collections.IGenericGodotArray genericGodotArray: + { + var godotArray = genericGodotArray.UnderlyingArray; + if (godotArray == null) + return new godot_variant(); + return VariantUtils.CreateFromArray(godotArray.NativeValue); + } + default: + { + var type = p_obj.GetType(); + + if (type.IsGenericType) + { + var genericTypeDefinition = type.GetGenericTypeDefinition(); + + if (genericTypeDefinition == typeof(System.Collections.Generic.Dictionary<,>)) + { + // TODO: Validate key and value types are compatible with Variant +#if NET + Collections.IGenericGodotDictionary genericGodotDictionary = IDictionaryToGenericGodotDictionary((dynamic)p_obj); +#else + var genericArguments = type.GetGenericArguments(); + + // With .NET Standard we need a package reference for Microsoft.CSharp in order to + // use dynamic, so we have this workaround for now until we switch to .NET 5/6. + var method = typeof(Marshaling).GetMethod(nameof(IDictionaryToGenericGodotDictionary), + BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly)! + .MakeGenericMethod(genericArguments[0], genericArguments[1]); + + var genericGodotDictionary = (Collections.IGenericGodotDictionary)method + .Invoke(null, new[] {p_obj}); +#endif + + var godotDict = genericGodotDictionary.UnderlyingDictionary; + if (godotDict == null) + return new godot_variant(); + return VariantUtils.CreateFromDictionary(godotDict.NativeValue); + } + + if (genericTypeDefinition == typeof(System.Collections.Generic.List<>)) + { + // TODO: Validate element type is compatible with Variant +#if NET + var nativeGodotArray = mono_array_to_Array(System.Runtime.InteropServices.CollectionsMarshal.AsSpan((dynamic)p_obj)); +#else + // With .NET Standard we need a package reference for Microsoft.CSharp in order to + // use dynamic, so we have this workaround for now until we switch to .NET 5/6. + // Also CollectionsMarshal.AsSpan is not available with .NET Standard. + + var collection = (System.Collections.ICollection)p_obj; + var array = new object[collection.Count]; + collection.CopyTo(array, 0); + var nativeGodotArray = mono_array_to_Array(array); +#endif + return VariantUtils.CreateFromArray(&nativeGodotArray); + } + } + + break; + } + } + + if (p_fail_with_err) + { + GD.PushError("Attempted to convert an unmarshallable managed type to Variant. Name: '" + + p_obj.GetType().FullName + "."); + return new godot_variant(); + } + else + { + return new godot_variant(); + } + } + + private static Collections.Dictionary<TKey, TValue> IDictionaryToGenericGodotDictionary<TKey, TValue> + (IDictionary<TKey, TValue> dictionary) => new(dictionary); + + public static unsafe string variant_to_mono_string(godot_variant* p_var) + { + switch ((*p_var)._type) + { + case Variant.Type.Nil: + return null; // Otherwise, Variant -> String would return the string "Null" + case Variant.Type.String: + { + // We avoid the internal call if the stored type is the same we want. + return mono_string_from_godot(&(*p_var)._data._m_string); + } + default: + { + using godot_string godotString = NativeFuncs.godotsharp_variant_as_string(p_var); + return mono_string_from_godot(&godotString); + } + } + } + + public static unsafe object variant_to_mono_object_of_type(godot_variant* p_var, Type type) + { + // This function is only needed to set the value of properties. Fields have their own implementation, set_value_from_variant. + switch (Type.GetTypeCode(type)) + { + case TypeCode.Boolean: + return VariantUtils.ConvertToBool(p_var); + case TypeCode.Char: + return VariantUtils.ConvertToChar(p_var); + case TypeCode.SByte: + return VariantUtils.ConvertToInt8(p_var); + case TypeCode.Int16: + return VariantUtils.ConvertToInt16(p_var); + case TypeCode.Int32: + return VariantUtils.ConvertToInt32(p_var); + case TypeCode.Int64: + return VariantUtils.ConvertToInt64(p_var); + case TypeCode.Byte: + return VariantUtils.ConvertToUInt8(p_var); + case TypeCode.UInt16: + return VariantUtils.ConvertToUInt16(p_var); + case TypeCode.UInt32: + return VariantUtils.ConvertToUInt32(p_var); + case TypeCode.UInt64: + return VariantUtils.ConvertToUInt64(p_var); + case TypeCode.Single: + return VariantUtils.ConvertToFloat32(p_var); + case TypeCode.Double: + return VariantUtils.ConvertToFloat64(p_var); + case TypeCode.String: + return variant_to_mono_string(p_var); + default: + { + if (type == typeof(Vector2)) + return VariantUtils.ConvertToVector2(p_var); + + if (type == typeof(Vector2i)) + return VariantUtils.ConvertToVector2i(p_var); + + if (type == typeof(Rect2)) + return VariantUtils.ConvertToRect2(p_var); + + if (type == typeof(Rect2i)) + return VariantUtils.ConvertToRect2i(p_var); + + if (type == typeof(Transform2D)) + return VariantUtils.ConvertToTransform2D(p_var); + + if (type == typeof(Vector3)) + return VariantUtils.ConvertToVector3(p_var); + + if (type == typeof(Vector3i)) + return VariantUtils.ConvertToVector3i(p_var); + + if (type == typeof(Vector4)) + return VariantUtils.ConvertToVector4(p_var); + + if (type == typeof(Vector4i)) + return VariantUtils.ConvertToVector4i(p_var); + + if (type == typeof(Basis)) + return VariantUtils.ConvertToBasis(p_var); + + if (type == typeof(Quaternion)) + return VariantUtils.ConvertToQuaternion(p_var); + + if (type == typeof(Transform3D)) + return VariantUtils.ConvertToTransform3D(p_var); + + if (type == typeof(Projection)) + return VariantUtils.ConvertToProjection(p_var); + + if (type == typeof(AABB)) + return VariantUtils.ConvertToAABB(p_var); + + if (type == typeof(Color)) + return VariantUtils.ConvertToColor(p_var); + + if (type == typeof(Plane)) + return VariantUtils.ConvertToPlane(p_var); + + if (type == typeof(Callable)) + { + using godot_callable callable = NativeFuncs.godotsharp_variant_as_callable(p_var); + return ConvertCallableToManaged(&callable); + } + + if (type == typeof(SignalInfo)) + { + using godot_signal signal = NativeFuncs.godotsharp_variant_as_signal(p_var); + return ConvertSignalToManaged(&signal); + } + + if (type.IsEnum) + { + var enumUnderlyingType = type.GetEnumUnderlyingType(); + switch (Type.GetTypeCode(enumUnderlyingType)) + { + case TypeCode.SByte: + return VariantUtils.ConvertToInt8(p_var); + case TypeCode.Int16: + return VariantUtils.ConvertToInt16(p_var); + case TypeCode.Int32: + return VariantUtils.ConvertToInt32(p_var); + case TypeCode.Int64: + return VariantUtils.ConvertToInt64(p_var); + case TypeCode.Byte: + return VariantUtils.ConvertToUInt8(p_var); + case TypeCode.UInt16: + return VariantUtils.ConvertToUInt16(p_var); + case TypeCode.UInt32: + return VariantUtils.ConvertToUInt32(p_var); + case TypeCode.UInt64: + return VariantUtils.ConvertToUInt64(p_var); + default: + { + GD.PushError("Attempted to convert Variant to enum value of unsupported underlying type. Name: " + + type.FullName + " : " + enumUnderlyingType.FullName + "."); + return null; + } + } + } + + if (type.IsArray || type.IsSZArray) + return variant_to_mono_array_of_type(p_var, type); + else if (type.IsGenericType) + return variant_to_mono_object_of_genericinst(p_var, type); + else if (type == typeof(object)) + return variant_to_mono_object(p_var); + if (variant_to_mono_object_of_class(p_var, type, out object res)) + return res; + + break; + } + } + + GD.PushError("Attempted to convert Variant to unsupported type. Name: " + + type.FullName + "."); + return null; + } + + private static unsafe object variant_to_mono_array_of_type(godot_variant* p_var, Type type) + { + if (type == typeof(Byte[])) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_byte_array(p_var); + return PackedByteArray_to_mono_array(&packedArray); + } + + if (type == typeof(Int32[])) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int32_array(p_var); + return PackedInt32Array_to_mono_array(&packedArray); + } + + if (type == typeof(Int64[])) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int64_array(p_var); + return PackedInt64Array_to_mono_array(&packedArray); + } + + if (type == typeof(float[])) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float32_array(p_var); + return PackedFloat32Array_to_mono_array(&packedArray); + } + + if (type == typeof(double[])) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float64_array(p_var); + return PackedFloat64Array_to_mono_array(&packedArray); + } + + if (type == typeof(string[])) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_string_array(p_var); + return PackedStringArray_to_mono_array(&packedArray); + } + + if (type == typeof(Vector2[])) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector2_array(p_var); + return PackedVector2Array_to_mono_array(&packedArray); + } + + if (type == typeof(Vector3[])) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector3_array(p_var); + return PackedVector3Array_to_mono_array(&packedArray); + } + + if (type == typeof(Color[])) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_color_array(p_var); + return PackedColorArray_to_mono_array(&packedArray); + } + + if (typeof(Godot.Object[]).IsAssignableFrom(type)) + { + using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); + return Array_to_mono_array_of_type(&godotArray, type); + } + + if (type == typeof(object[])) + { + using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); + return Array_to_mono_array(&godotArray); + } + + GD.PushError("Attempted to convert Variant to array of unsupported element type. Name: " + + type.GetElementType()!.FullName + "."); + return null; + } + + private static unsafe bool variant_to_mono_object_of_class(godot_variant* p_var, Type type, out object res) + { + if (typeof(Godot.Object).IsAssignableFrom(type)) + { + res = InteropUtils.UnmanagedGetManaged(VariantUtils.ConvertToGodotObject(p_var)); + return true; + } + + if (typeof(StringName) == type) + { + res = StringName.CreateTakingOwnershipOfDisposableValue( + VariantUtils.ConvertToStringName(p_var)); + return true; + } + + if (typeof(NodePath) == type) + { + res = NodePath.CreateTakingOwnershipOfDisposableValue( + VariantUtils.ConvertToNodePath(p_var)); + return true; + } + + if (typeof(RID) == type) + { + res = VariantUtils.ConvertToRID(p_var); + return true; + } + + if (typeof(Collections.Dictionary) == type || typeof(System.Collections.IDictionary) == type) + { + res = Collections.Dictionary.CreateTakingOwnershipOfDisposableValue( + VariantUtils.ConvertToDictionary(p_var)); + return true; + } + + if (typeof(Collections.Array) == type || + typeof(System.Collections.ICollection) == type || + typeof(System.Collections.IEnumerable) == type) + { + res = Collections.Array.CreateTakingOwnershipOfDisposableValue( + VariantUtils.ConvertToArray(p_var)); + return true; + } + + res = null; + return false; + } + + private static unsafe object variant_to_mono_object_of_genericinst(godot_variant* p_var, Type type) + { + static object variant_to_generic_godot_collections_dictionary(godot_variant* p_var, Type fullType) + { + var underlyingDict = Collections.Dictionary.CreateTakingOwnershipOfDisposableValue( + VariantUtils.ConvertToDictionary(p_var)); + return Activator.CreateInstance(fullType, + BindingFlags.Public | BindingFlags.Instance, null, + args: new object[] {underlyingDict}, null); + } + + static object variant_to_generic_godot_collections_array(godot_variant* p_var, Type fullType) + { + var underlyingArray = Collections.Array.CreateTakingOwnershipOfDisposableValue( + VariantUtils.ConvertToArray(p_var)); + return Activator.CreateInstance(fullType, + BindingFlags.Public | BindingFlags.Instance, null, + args: new object[] {underlyingArray}, null); + } + + var genericTypeDefinition = type.GetGenericTypeDefinition(); + + if (genericTypeDefinition == typeof(Collections.Dictionary<,>)) + return variant_to_generic_godot_collections_dictionary(p_var, type); + + if (genericTypeDefinition == typeof(Collections.Array<>)) + return variant_to_generic_godot_collections_array(p_var, type); + + if (genericTypeDefinition == typeof(System.Collections.Generic.Dictionary<,>)) + { + using var godotDictionary = Collections.Dictionary.CreateTakingOwnershipOfDisposableValue( + VariantUtils.ConvertToDictionary(p_var)); + + var dictionary = (System.Collections.IDictionary)Activator.CreateInstance(type, + BindingFlags.Public | BindingFlags.Instance, null, + args: new object[] + { + /* capacity: */ godotDictionary.Count + }, null); + + foreach (System.Collections.DictionaryEntry pair in godotDictionary) + dictionary.Add(pair.Key, pair.Value); + + return dictionary; + } + + if (genericTypeDefinition == typeof(System.Collections.Generic.List<>)) + { + using var godotArray = Collections.Array.CreateTakingOwnershipOfDisposableValue( + VariantUtils.ConvertToArray(p_var)); + + var list = (System.Collections.IList)Activator.CreateInstance(type, + BindingFlags.Public | BindingFlags.Instance, null, + args: new object[] + { + /* capacity: */ godotArray.Count + }, null); + + foreach (object elem in godotArray) + list.Add(elem); + + return list; + } + + if (genericTypeDefinition == typeof(IDictionary<,>)) + { + var genericArgs = type.GetGenericArguments(); + var keyType = genericArgs[0]; + var valueType = genericArgs[1]; + var genericGodotDictionaryType = typeof(Collections.Dictionary<,>) + .MakeGenericType(keyType, valueType); + + return variant_to_generic_godot_collections_dictionary(p_var, genericGodotDictionaryType); + } + + if (genericTypeDefinition == typeof(ICollection<>) || genericTypeDefinition == typeof(IEnumerable<>)) + { + var elementType = type.GetGenericArguments()[0]; + var genericGodotArrayType = typeof(Collections.Array<>) + .MakeGenericType(elementType); + + return variant_to_generic_godot_collections_array(p_var, genericGodotArrayType); + } + + return null; + } + + public static unsafe object variant_to_mono_object(godot_variant* p_var) + { + switch ((*p_var)._type) + { + case Variant.Type.Bool: + return (bool)(*p_var)._data._bool; + case Variant.Type.Int: + return (*p_var)._data._int; + case Variant.Type.Float: + { +#if REAL_T_IS_DOUBLE + return (*p_var)._data._float; +#else + return (float)(*p_var)._data._float; +#endif + } + case Variant.Type.String: + return mono_string_from_godot(&(*p_var)._data._m_string); + case Variant.Type.Vector2: + return (*p_var)._data._m_vector2; + case Variant.Type.Vector2i: + return (*p_var)._data._m_vector2i; + case Variant.Type.Rect2: + return (*p_var)._data._m_rect2; + case Variant.Type.Rect2i: + return (*p_var)._data._m_rect2i; + case Variant.Type.Vector3: + return (*p_var)._data._m_vector3; + case Variant.Type.Vector3i: + return (*p_var)._data._m_vector3i; + case Variant.Type.Transform2d: + return *(*p_var)._data._transform2d; + case Variant.Type.Vector4: + return *(*p_var)._data._vector4; + case Variant.Type.Vector4i: + return *(*p_var)._data._vector4i; + case Variant.Type.Plane: + return (*p_var)._data._m_plane; + case Variant.Type.Quaternion: + return (*p_var)._data._m_quaternion; + case Variant.Type.Aabb: + return *(*p_var)._data._aabb; + case Variant.Type.Basis: + return *(*p_var)._data._basis; + case Variant.Type.Transform3d: + return *(*p_var)._data._transform3d; + case Variant.Type.Projection: + return *(*p_var)._data._projection; + case Variant.Type.Color: + return (*p_var)._data._m_color; + case Variant.Type.StringName: + { + // The Variant owns the value, so we need to make a copy + return StringName.CreateTakingOwnershipOfDisposableValue( + NativeFuncs.godotsharp_string_name_new_copy(&(*p_var)._data._m_string_name)); + } + case Variant.Type.NodePath: + { + // The Variant owns the value, so we need to make a copy + return NodePath.CreateTakingOwnershipOfDisposableValue( + NativeFuncs.godotsharp_node_path_new_copy(&(*p_var)._data._m_node_path)); + } + case Variant.Type.Rid: + return (*p_var)._data._m_rid; + case Variant.Type.Object: + return InteropUtils.UnmanagedGetManaged((*p_var)._data._m_obj_data.obj); + case Variant.Type.Callable: + return ConvertCallableToManaged(&(*p_var)._data._m_callable); + case Variant.Type.Signal: + return ConvertSignalToManaged(&(*p_var)._data._m_signal); + case Variant.Type.Dictionary: + { + // The Variant owns the value, so we need to make a copy + return Collections.Dictionary.CreateTakingOwnershipOfDisposableValue( + NativeFuncs.godotsharp_dictionary_new_copy(&(*p_var)._data._m_dictionary)); + } + case Variant.Type.Array: + { + // The Variant owns the value, so we need to make a copy + return Collections.Array.CreateTakingOwnershipOfDisposableValue( + NativeFuncs.godotsharp_array_new_copy(&(*p_var)._data._m_array)); + } + case Variant.Type.PackedByteArray: + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_byte_array(p_var); + return PackedByteArray_to_mono_array(&packedArray); + } + case Variant.Type.PackedInt32Array: + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int32_array(p_var); + return PackedInt32Array_to_mono_array(&packedArray); + } + case Variant.Type.PackedInt64Array: + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int64_array(p_var); + return PackedInt64Array_to_mono_array(&packedArray); + } + case Variant.Type.PackedFloat32Array: + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float32_array(p_var); + return PackedFloat32Array_to_mono_array(&packedArray); + } + case Variant.Type.PackedFloat64Array: + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float64_array(p_var); + return PackedFloat64Array_to_mono_array(&packedArray); + } + case Variant.Type.PackedStringArray: + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_string_array(p_var); + return PackedStringArray_to_mono_array(&packedArray); + } + case Variant.Type.PackedVector2Array: + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector2_array(p_var); + return PackedVector2Array_to_mono_array(&packedArray); + } + case Variant.Type.PackedVector3Array: + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector3_array(p_var); + return PackedVector3Array_to_mono_array(&packedArray); + } + case Variant.Type.PackedColorArray: + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_color_array(p_var); + return PackedColorArray_to_mono_array(&packedArray); + } + default: + return null; + } + } + + // String + + public static unsafe godot_string mono_string_to_godot(string p_mono_string) + { + if (p_mono_string == null) + return new godot_string(); + + fixed (char* methodChars = p_mono_string) + { + godot_string dest; + NativeFuncs.godotsharp_string_new_with_utf16_chars(&dest, methodChars); + return dest; + } + } + + public static unsafe string mono_string_from_godot(godot_string* p_string) + { + if ((*p_string)._ptr == IntPtr.Zero) + return string.Empty; + + const int sizeOfChar32 = 4; + byte* bytes = (byte*)(*p_string)._ptr; + int size = *((int*)(*p_string)._ptr - 1); + if (size == 0) + return string.Empty; + size -= 1; // zero at the end + int sizeInBytes = size * sizeOfChar32; + return System.Text.Encoding.UTF32.GetString(bytes, sizeInBytes); + } + + // Callable + + public static godot_callable ConvertCallableToNative(ref Callable p_managed_callable) + { + if (p_managed_callable.Delegate != null) + { + unsafe + { + godot_callable callable; + NativeFuncs.godotsharp_callable_new_with_delegate( + GCHandle.ToIntPtr(GCHandle.Alloc(p_managed_callable.Delegate)), &callable); + return callable; + } + } + else + { + unsafe + { + godot_string_name method; + + if (p_managed_callable.Method != null && !p_managed_callable.Method.IsEmpty) + { + godot_string_name src = p_managed_callable.Method.NativeValue; + method = NativeFuncs.godotsharp_string_name_new_copy(&src); + } + else + { + method = default; + } + + return new godot_callable + { + _method = method, // Takes ownership of disposable + _objectId = p_managed_callable.Target.GetInstanceId() + }; + } + } + } + + public static unsafe Callable ConvertCallableToManaged(godot_callable* p_callable) + { + IntPtr delegateGCHandle; + IntPtr godotObject; + godot_string_name name; + + if (NativeFuncs.godotsharp_callable_get_data_for_marshalling( + p_callable, &delegateGCHandle, &godotObject, &name)) + { + if (delegateGCHandle != IntPtr.Zero) + { + return new Callable((Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target); + } + else + { + return new Callable( + InteropUtils.UnmanagedGetManaged(godotObject), + StringName.CreateTakingOwnershipOfDisposableValue(name)); + } + } + + // Some other unsupported callable + return new Callable(); + } + + // SignalInfo + + public static godot_signal ConvertSignalToNative(ref SignalInfo p_managed_signal) + { + ulong ownerId = p_managed_signal.Owner.GetInstanceId(); + unsafe + { + godot_string_name name; + + if (p_managed_signal.Name != null && !p_managed_signal.Name.IsEmpty) + { + godot_string_name src = p_managed_signal.Name.NativeValue; + name = NativeFuncs.godotsharp_string_name_new_copy(&src); + } + else + { + name = default; + } + + return new godot_signal() + { + _name = name, + _objectId = ownerId + }; + } + } + + public static unsafe SignalInfo ConvertSignalToManaged(godot_signal* p_signal) + { + var owner = GD.InstanceFromId((*p_signal)._objectId); + var name = StringName.CreateTakingOwnershipOfDisposableValue( + NativeFuncs.godotsharp_string_name_new_copy(&(*p_signal)._name)); + return new SignalInfo(owner, name); + } + + // Array + + public static unsafe object[] Array_to_mono_array(godot_array* p_array) + { + var array = Collections.Array.CreateTakingOwnershipOfDisposableValue( + NativeFuncs.godotsharp_array_new_copy(p_array)); + + int length = array.Count; + var ret = new object[length]; + + array.CopyTo(ret, 0); // variant_to_mono_object handled by Collections.Array + + return ret; + } + + public static unsafe object Array_to_mono_array_of_type(godot_array* p_array, Type type) + { + var array = Collections.Array.CreateTakingOwnershipOfDisposableValue( + NativeFuncs.godotsharp_array_new_copy(p_array)); + + int length = array.Count; + object ret = Activator.CreateInstance(type, length); + + array.CopyTo((object[])ret, 0); // variant_to_mono_object handled by Collections.Array + + return ret; + } + + public static godot_array mono_array_to_Array(Span<object> p_array) + { + if (p_array.IsEmpty) + { + godot_array ret; + Collections.Array.godot_icall_Array_Ctor(out ret); + return ret; + } + + using var array = new Collections.Array(); + array.Resize(p_array.Length); + + for (int i = 0; i < p_array.Length; i++) + array[i] = p_array[i]; + + godot_array src = array.NativeValue; + unsafe + { + return NativeFuncs.godotsharp_array_new_copy(&src); + } + } + + // PackedByteArray + + public static unsafe byte[] PackedByteArray_to_mono_array(godot_packed_byte_array* p_array) + { + byte* buffer = (byte*)(*p_array)._ptr; + int size = *((int*)(*p_array)._ptr - 1); + var array = new byte[size]; + fixed (byte* dest = array) + Buffer.MemoryCopy(buffer, dest, size, size); + return array; + } + + public static unsafe godot_packed_byte_array mono_array_to_PackedByteArray(Span<byte> p_array) + { + if (p_array.IsEmpty) + return new godot_packed_byte_array(); + fixed (byte* src = p_array) + return NativeFuncs.godotsharp_packed_byte_array_new_mem_copy(src, p_array.Length); + } + + // PackedInt32Array + + public static unsafe int[] PackedInt32Array_to_mono_array(godot_packed_int32_array* p_array) + { + int* buffer = (int*)(*p_array)._ptr; + int size = *((int*)(*p_array)._ptr - 1); + int sizeInBytes = size * sizeof(int); + var array = new int[size]; + fixed (int* dest = array) + Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes); + return array; + } + + public static unsafe godot_packed_int32_array mono_array_to_PackedInt32Array(Span<int> p_array) + { + if (p_array.IsEmpty) + return new godot_packed_int32_array(); + fixed (int* src = p_array) + return NativeFuncs.godotsharp_packed_int32_array_new_mem_copy(src, p_array.Length); + } + + // PackedInt64Array + + public static unsafe long[] PackedInt64Array_to_mono_array(godot_packed_int64_array* p_array) + { + long* buffer = (long*)(*p_array)._ptr; + int size = *((int*)(*p_array)._ptr - 1); + int sizeInBytes = size * sizeof(long); + var array = new long[size]; + fixed (long* dest = array) + Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes); + return array; + } + + public static unsafe godot_packed_int64_array mono_array_to_PackedInt64Array(Span<long> p_array) + { + if (p_array.IsEmpty) + return new godot_packed_int64_array(); + fixed (long* src = p_array) + return NativeFuncs.godotsharp_packed_int64_array_new_mem_copy(src, p_array.Length); + } + + // PackedFloat32Array + + public static unsafe float[] PackedFloat32Array_to_mono_array(godot_packed_float32_array* p_array) + { + float* buffer = (float*)(*p_array)._ptr; + int size = *((int*)(*p_array)._ptr - 1); + int sizeInBytes = size * sizeof(float); + var array = new float[size]; + fixed (float* dest = array) + Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes); + return array; + } + + public static unsafe godot_packed_float32_array mono_array_to_PackedFloat32Array(Span<float> p_array) + { + if (p_array.IsEmpty) + return new godot_packed_float32_array(); + fixed (float* src = p_array) + return NativeFuncs.godotsharp_packed_float32_array_new_mem_copy(src, p_array.Length); + } + + // PackedFloat64Array + + public static unsafe double[] PackedFloat64Array_to_mono_array(godot_packed_float64_array* p_array) + { + double* buffer = (double*)(*p_array)._ptr; + int size = *((int*)(*p_array)._ptr - 1); + int sizeInBytes = size * sizeof(double); + var array = new double[size]; + fixed (double* dest = array) + Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes); + return array; + } + + public static unsafe godot_packed_float64_array mono_array_to_PackedFloat64Array(Span<double> p_array) + { + if (p_array.IsEmpty) + return new godot_packed_float64_array(); + fixed (double* src = p_array) + return NativeFuncs.godotsharp_packed_float64_array_new_mem_copy(src, p_array.Length); + } + + // PackedStringArray + + public static unsafe string[] PackedStringArray_to_mono_array(godot_packed_string_array* p_array) + { + godot_string* buffer = (godot_string*)(*p_array)._ptr; + if (buffer == null) + return new string[] { }; + int size = *((int*)(*p_array)._ptr - 1); + var array = new string[size]; + for (int i = 0; i < size; i++) + array[i] = mono_string_from_godot(&buffer[i]); + return array; + } + + public static unsafe godot_packed_string_array mono_array_to_PackedStringArray(Span<string> p_array) + { + godot_packed_string_array dest = new godot_packed_string_array(); + + if (p_array.IsEmpty) + return dest; + + /* TODO: Replace godotsharp_packed_string_array_add with a single internal call to + get the write address. We can't use `dest._ptr` directly for writing due to COW. */ + + for (int i = 0; i < p_array.Length; i++) + { + using godot_string godotStrElem = mono_string_to_godot(p_array[i]); + NativeFuncs.godotsharp_packed_string_array_add(&dest, &godotStrElem); + } + + return dest; + } + + // PackedVector2Array + + public static unsafe Vector2[] PackedVector2Array_to_mono_array(godot_packed_vector2_array* p_array) + { + Vector2* buffer = (Vector2*)(*p_array)._ptr; + int size = *((int*)(*p_array)._ptr - 1); + int sizeInBytes = size * sizeof(Vector2); + var array = new Vector2[size]; + fixed (Vector2* dest = array) + Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes); + return array; + } + + public static unsafe godot_packed_vector2_array mono_array_to_PackedVector2Array(Span<Vector2> p_array) + { + if (p_array.IsEmpty) + return new godot_packed_vector2_array(); + fixed (Vector2* src = p_array) + return NativeFuncs.godotsharp_packed_vector2_array_new_mem_copy(src, p_array.Length); + } + + // PackedVector3Array + + public static unsafe Vector3[] PackedVector3Array_to_mono_array(godot_packed_vector3_array* p_array) + { + Vector3* buffer = (Vector3*)(*p_array)._ptr; + int size = *((int*)(*p_array)._ptr - 1); + int sizeInBytes = size * sizeof(Vector3); + var array = new Vector3[size]; + fixed (Vector3* dest = array) + Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes); + return array; + } + + public static unsafe godot_packed_vector3_array mono_array_to_PackedVector3Array(Span<Vector3> p_array) + { + if (p_array.IsEmpty) + return new godot_packed_vector3_array(); + fixed (Vector3* src = p_array) + return NativeFuncs.godotsharp_packed_vector3_array_new_mem_copy(src, p_array.Length); + } + + // PackedColorArray + + public static unsafe Color[] PackedColorArray_to_mono_array(godot_packed_color_array* p_array) + { + Color* buffer = (Color*)(*p_array)._ptr; + int size = *((int*)(*p_array)._ptr - 1); + int sizeInBytes = size * sizeof(Color); + var array = new Color[size]; + fixed (Color* dest = array) + Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes); + return array; + } + + public static unsafe godot_packed_color_array mono_array_to_PackedColorArray(Span<Color> p_array) + { + if (p_array.IsEmpty) + return new godot_packed_color_array(); + fixed (Color* src = p_array) + return NativeFuncs.godotsharp_packed_color_array_new_mem_copy(src, p_array.Length); + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs new file mode 100644 index 0000000000..2f1056219d --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs @@ -0,0 +1,346 @@ +using System; +using System.Runtime.InteropServices; + +// ReSharper disable InconsistentNaming + +namespace Godot.NativeInterop +{ +#if !NET + // This improves P/Invoke performance. + // The attribute is not available with .NET Core and it's not needed there. + [System.Security.SuppressUnmanagedCodeSecurity] +#endif + internal static unsafe partial class NativeFuncs + { + private const string GodotDllName = "__Internal"; + + // Custom functions + + [DllImport(GodotDllName)] + public static extern IntPtr godotsharp_method_bind_get_method(ref godot_string_name p_classname, char* p_methodname); + +#if NET + [DllImport(GodotDllName)] + public static extern delegate* unmanaged<IntPtr> godotsharp_get_class_constructor(ref godot_string_name p_classname); +#else + // Workaround until we switch to .NET 5/6 + [DllImport(GodotDllName)] + public static extern IntPtr godotsharp_get_class_constructor(ref godot_string_name p_classname); + + [DllImport(GodotDllName)] + public static extern IntPtr godotsharp_invoke_class_constructor(IntPtr p_creation_func); +#endif + + [DllImport(GodotDllName)] + public static extern IntPtr godotsharp_engine_get_singleton(godot_string* p_name); + + [DllImport(GodotDllName)] + public static extern void godotsharp_ref_destroy(ref godot_ref p_instance); + + [DllImport(GodotDllName)] + public static extern void godotsharp_string_name_new_from_string(godot_string_name* dest, godot_string* name); + + [DllImport(GodotDllName)] + public static extern void godotsharp_node_path_new_from_string(godot_node_path* dest, godot_string* name); + + [DllImport(GodotDllName)] + public static extern void godotsharp_string_name_as_string(godot_string* r_dest, godot_string_name* p_name); + + [DllImport(GodotDllName)] + public static extern void godotsharp_node_path_as_string(godot_string* r_dest, godot_node_path* p_np); + + [DllImport(GodotDllName)] + public static extern godot_packed_byte_array godotsharp_packed_byte_array_new_mem_copy(byte* p_src, int p_length); + + [DllImport(GodotDllName)] + public static extern godot_packed_int32_array godotsharp_packed_int32_array_new_mem_copy(int* p_src, int p_length); + + [DllImport(GodotDllName)] + public static extern godot_packed_int64_array godotsharp_packed_int64_array_new_mem_copy(long* p_src, int p_length); + + [DllImport(GodotDllName)] + public static extern godot_packed_float32_array godotsharp_packed_float32_array_new_mem_copy(float* p_src, int p_length); + + [DllImport(GodotDllName)] + public static extern godot_packed_float64_array godotsharp_packed_float64_array_new_mem_copy(double* p_src, int p_length); + + [DllImport(GodotDllName)] + public static extern godot_packed_vector2_array godotsharp_packed_vector2_array_new_mem_copy(Vector2* p_src, int p_length); + + [DllImport(GodotDllName)] + public static extern godot_packed_vector3_array godotsharp_packed_vector3_array_new_mem_copy(Vector3* p_src, int p_length); + + [DllImport(GodotDllName)] + public static extern godot_packed_color_array godotsharp_packed_color_array_new_mem_copy(Color* p_src, int p_length); + + [DllImport(GodotDllName)] + public static extern void godotsharp_packed_string_array_add(godot_packed_string_array* r_dest, godot_string* p_element); + + [DllImport(GodotDllName)] + public static extern void godotsharp_callable_new_with_delegate(IntPtr p_delegate_handle, godot_callable* r_callable); + + [DllImport(GodotDllName)] + public static extern bool godotsharp_callable_get_data_for_marshalling(godot_callable* p_callable, IntPtr* r_delegate_handle, IntPtr* r_object, godot_string_name* r_name); + + // GDNative functions + + // gdnative.h + + [DllImport(GodotDllName)] + public static extern void godotsharp_method_bind_ptrcall(IntPtr p_method_bind, IntPtr p_instance, void** p_args, void* p_ret); + + [DllImport(GodotDllName)] + public static extern godot_variant godotsharp_method_bind_call(IntPtr p_method_bind, IntPtr p_instance, godot_variant** p_args, int p_arg_count, godot_variant_call_error* p_call_error); + + // variant.h + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_string_name(godot_variant* r_dest, godot_string_name* p_s); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_node_path(godot_variant* r_dest, godot_node_path* p_np); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_object(godot_variant* r_dest, IntPtr p_obj); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_transform2d(godot_variant* r_dest, Transform2D* p_t2d); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_vector4(godot_variant* r_dest, Vector4* p_vec4); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_vector4i(godot_variant* r_dest, Vector4i* p_vec4i); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_basis(godot_variant* r_dest, Basis* p_basis); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_transform3d(godot_variant* r_dest, Transform3D* p_trans); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_projection(godot_variant* r_dest, Projection* p_proj); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_aabb(godot_variant* r_dest, AABB* p_aabb); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_dictionary(godot_variant* r_dest, godot_dictionary* p_dict); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_array(godot_variant* r_dest, godot_array* p_arr); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_packed_byte_array(godot_variant* r_dest, godot_packed_byte_array* p_pba); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_packed_int32_array(godot_variant* r_dest, godot_packed_int32_array* p_pia); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_packed_int64_array(godot_variant* r_dest, godot_packed_int64_array* p_pia); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_packed_float32_array(godot_variant* r_dest, godot_packed_float32_array* p_pra); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_packed_float64_array(godot_variant* r_dest, godot_packed_float64_array* p_pra); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_packed_string_array(godot_variant* r_dest, godot_packed_string_array* p_psa); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_packed_vector2_array(godot_variant* r_dest, godot_packed_vector2_array* p_pv2a); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_packed_vector3_array(godot_variant* r_dest, godot_packed_vector3_array* p_pv3a); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_new_packed_color_array(godot_variant* r_dest, godot_packed_color_array* p_pca); + + [DllImport(GodotDllName)] + public static extern bool godotsharp_variant_as_bool(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern Int64 godotsharp_variant_as_int(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern double godotsharp_variant_as_float(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern godot_string godotsharp_variant_as_string(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern Vector2 godotsharp_variant_as_vector2(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern Vector2i godotsharp_variant_as_vector2i(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern Rect2 godotsharp_variant_as_rect2(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern Rect2i godotsharp_variant_as_rect2i(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern Vector3 godotsharp_variant_as_vector3(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern Vector3i godotsharp_variant_as_vector3i(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern Transform2D godotsharp_variant_as_transform2d(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern Vector4 godotsharp_variant_as_vector4(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern Vector4i godotsharp_variant_as_vector4i(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern Plane godotsharp_variant_as_plane(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern Quaternion godotsharp_variant_as_quaternion(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern AABB godotsharp_variant_as_aabb(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern Basis godotsharp_variant_as_basis(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern Transform3D godotsharp_variant_as_transform3d(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern Projection godotsharp_variant_as_projection(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern Color godotsharp_variant_as_color(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern godot_string_name godotsharp_variant_as_string_name(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern godot_node_path godotsharp_variant_as_node_path(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern RID godotsharp_variant_as_rid(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern godot_callable godotsharp_variant_as_callable(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern godot_signal godotsharp_variant_as_signal(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern godot_dictionary godotsharp_variant_as_dictionary(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern godot_array godotsharp_variant_as_array(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern godot_packed_byte_array godotsharp_variant_as_packed_byte_array(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern godot_packed_int32_array godotsharp_variant_as_packed_int32_array(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern godot_packed_int64_array godotsharp_variant_as_packed_int64_array(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern godot_packed_float32_array godotsharp_variant_as_packed_float32_array(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern godot_packed_float64_array godotsharp_variant_as_packed_float64_array(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern godot_packed_string_array godotsharp_variant_as_packed_string_array(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern godot_packed_vector2_array godotsharp_variant_as_packed_vector2_array(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern godot_packed_vector3_array godotsharp_variant_as_packed_vector3_array(godot_variant* p_self); + + [DllImport(GodotDllName)] + public static extern godot_packed_color_array godotsharp_variant_as_packed_color_array(godot_variant* p_self); + + // string.h + + [DllImport(GodotDllName)] + public static extern void godotsharp_string_new_with_utf16_chars(godot_string* r_dest, char* p_contents); + + // string_name.h + + [DllImport(GodotDllName)] + public static extern void godotsharp_string_name_new_copy(godot_string_name* r_dest, godot_string_name* p_src); + + // node_path.h + + [DllImport(GodotDllName)] + public static extern void godotsharp_node_path_new_copy(godot_node_path* r_dest, godot_node_path* p_src); + + // array.h + + [DllImport(GodotDllName)] + public static extern void godotsharp_array_new_copy(godot_array* r_dest, godot_array* p_src); + + // dictionary.h + + [DllImport(GodotDllName)] + public static extern void godotsharp_dictionary_new_copy(godot_dictionary* r_dest, godot_dictionary* p_src); + + // destroy functions + + [DllImport(GodotDllName)] + public static extern void godotsharp_packed_byte_array_destroy(ref godot_packed_byte_array p_self); + + [DllImport(GodotDllName)] + public static extern void godotsharp_packed_int32_array_destroy(ref godot_packed_int32_array p_self); + + [DllImport(GodotDllName)] + public static extern void godotsharp_packed_int64_array_destroy(ref godot_packed_int64_array p_self); + + [DllImport(GodotDllName)] + public static extern void godotsharp_packed_float32_array_destroy(ref godot_packed_float32_array p_self); + + [DllImport(GodotDllName)] + public static extern void godotsharp_packed_float64_array_destroy(ref godot_packed_float64_array p_self); + + [DllImport(GodotDllName)] + public static extern void godotsharp_packed_string_array_destroy(ref godot_packed_string_array p_self); + + [DllImport(GodotDllName)] + public static extern void godotsharp_packed_vector2_array_destroy(ref godot_packed_vector2_array p_self); + + [DllImport(GodotDllName)] + public static extern void godotsharp_packed_vector3_array_destroy(ref godot_packed_vector3_array p_self); + + [DllImport(GodotDllName)] + public static extern void godotsharp_packed_color_array_destroy(ref godot_packed_color_array p_self); + + [DllImport(GodotDllName)] + public static extern void godotsharp_variant_destroy(ref godot_variant p_self); + + [DllImport(GodotDllName)] + public static extern void godotsharp_string_destroy(ref godot_string p_self); + + [DllImport(GodotDllName)] + public static extern void godotsharp_string_name_destroy(ref godot_string_name p_self); + + [DllImport(GodotDllName)] + public static extern void godotsharp_node_path_destroy(ref godot_node_path p_self); + + [DllImport(GodotDllName)] + public static extern void godotsharp_signal_destroy(ref godot_signal p_self); + + [DllImport(GodotDllName)] + public static extern void godotsharp_callable_destroy(ref godot_callable p_self); + + [DllImport(GodotDllName)] + public static extern void godotsharp_array_destroy(ref godot_array p_self); + + [DllImport(GodotDllName)] + public static extern void godotsharp_dictionary_destroy(ref godot_dictionary p_self); + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs new file mode 100644 index 0000000000..70df79c1de --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs @@ -0,0 +1,70 @@ +using System; +using System.Runtime.CompilerServices; + +// ReSharper disable InconsistentNaming + +namespace Godot.NativeInterop +{ + internal static unsafe partial class NativeFuncs + { + public static godot_string_name godotsharp_string_name_new_copy(godot_string_name* src) + { + godot_string_name ret; + godotsharp_string_name_new_copy(&ret, src); + return ret; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_string_name godotsharp_string_name_new_copy(godot_string_name src) + => godotsharp_string_name_new_copy(&src); + + public static godot_node_path godotsharp_node_path_new_copy(godot_node_path* src) + { + godot_node_path ret; + godotsharp_node_path_new_copy(&ret, src); + return ret; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_node_path godotsharp_node_path_new_copy(godot_node_path src) + => godotsharp_node_path_new_copy(&src); + + public static godot_array godotsharp_array_new_copy(godot_array* src) + { + godot_array ret; + godotsharp_array_new_copy(&ret, src); + return ret; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_array godotsharp_array_new_copy(godot_array src) + => godotsharp_array_new_copy(&src); + + public static godot_dictionary godotsharp_dictionary_new_copy(godot_dictionary* src) + { + godot_dictionary ret; + godotsharp_dictionary_new_copy(&ret, src); + return ret; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_dictionary godotsharp_dictionary_new_copy(godot_dictionary src) + => godotsharp_dictionary_new_copy(&src); + + public static godot_string_name godotsharp_string_name_new_from_string(string name) + { + godot_string_name ret; + using godot_string src = Marshaling.mono_string_to_godot(name); + godotsharp_string_name_new_from_string(&ret, &src); + return ret; + } + + public static godot_node_path godotsharp_node_path_new_from_string(string name) + { + godot_node_path ret; + using godot_string src = Marshaling.mono_string_to_godot(name); + godotsharp_node_path_new_from_string(&ret, &src); + return ret; + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs new file mode 100644 index 0000000000..2814f9d506 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs @@ -0,0 +1,33 @@ +using System; + +namespace Godot.NativeInterop +{ + internal ref struct VariantSpanDisposer + { + private readonly Span<godot_variant> _variantSpan; + + // IMPORTANT: The span element must be default initialized. + // Make sure call Clear() on the span if it was created with stackalloc. + public VariantSpanDisposer(Span<godot_variant> variantSpan) + { + _variantSpan = variantSpan; + } + + public void Dispose() + { + for (int i = 0; i < _variantSpan.Length; i++) + _variantSpan[i].Dispose(); + } + } + + internal static class VariantSpanExtensions + { + // Used to make sure we always initialize the span values to the default, + // as we need that in order to safely dispose all elements after. + public static Span<godot_variant> Cleared(this Span<godot_variant> span) + { + span.Clear(); + return span; + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs new file mode 100644 index 0000000000..67f9e23893 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs @@ -0,0 +1,335 @@ +using System; +using System.Runtime.CompilerServices; + +// ReSharper disable InconsistentNaming + +namespace Godot.NativeInterop +{ + internal static class VariantUtils + { + public static godot_variant CreateFromRID(RID from) + => new() {_type = Variant.Type.Rid, _data = {_m_rid = from}}; + + public static godot_variant CreateFromBool(bool from) + => new() {_type = Variant.Type.Bool, _data = {_bool = from}}; + + public static godot_variant CreateFromInt(long from) + => new() {_type = Variant.Type.Int, _data = {_int = from}}; + + public static godot_variant CreateFromInt(ulong from) + => new() {_type = Variant.Type.Int, _data = {_int = (long)from}}; + + public static godot_variant CreateFromFloat(double from) + => new() {_type = Variant.Type.Float, _data = {_float = from}}; + + public static godot_variant CreateFromVector2(Vector2 from) + => new() {_type = Variant.Type.Vector2, _data = {_m_vector2 = from}}; + + public static godot_variant CreateFromVector2i(Vector2i from) + => new() {_type = Variant.Type.Vector2i, _data = {_m_vector2i = from}}; + + public static godot_variant CreateFromVector3(Vector3 from) + => new() {_type = Variant.Type.Vector3, _data = {_m_vector3 = from}}; + + public static godot_variant CreateFromVector3i(Vector3i from) + => new() {_type = Variant.Type.Vector3i, _data = {_m_vector3i = from}}; + + public static godot_variant CreateFromRect2(Rect2 from) + => new() {_type = Variant.Type.Rect2, _data = {_m_rect2 = from}}; + + public static godot_variant CreateFromRect2i(Rect2i from) + => new() {_type = Variant.Type.Rect2i, _data = {_m_rect2i = from}}; + + public static godot_variant CreateFromQuaternion(Quaternion from) + => new() {_type = Variant.Type.Quaternion, _data = {_m_quaternion = from}}; + + public static godot_variant CreateFromColor(Color from) + => new() {_type = Variant.Type.Color, _data = {_m_color = from}}; + + public static godot_variant CreateFromPlane(Plane from) + => new() {_type = Variant.Type.Plane, _data = {_m_plane = from}}; + + public static unsafe godot_variant CreateFromTransform2D(Transform2D from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_transform2d(&ret, &from); + return ret; + } + + public static unsafe godot_variant CreateFromVector4(Vector4 from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_vector4(&ret, &from); + return ret; + } + + public static unsafe godot_variant CreateFromVector4i(Vector4i from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_vector4i(&ret, &from); + return ret; + } + + public static unsafe godot_variant CreateFromBasis(Basis from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_basis(&ret, &from); + return ret; + } + + public static unsafe godot_variant CreateFromTransform3D(Transform3D from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_transform3d(&ret, &from); + return ret; + } + + public static unsafe godot_variant CreateFromProjection(Projection from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_projection(&ret, &from); + return ret; + } + + public static unsafe godot_variant CreateFromAABB(AABB from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_aabb(&ret, &from); + return ret; + } + + // Explicit name to make it very clear + public static godot_variant CreateFromCallableTakingOwnershipOfDisposableValue(godot_callable from) + => new() {_type = Variant.Type.Callable, _data = {_m_callable = from}}; + + // Explicit name to make it very clear + public static godot_variant CreateFromSignalTakingOwnershipOfDisposableValue(godot_signal from) + => new() {_type = Variant.Type.Signal, _data = {_m_signal = from}}; + + // Explicit name to make it very clear + public static godot_variant CreateFromStringTakingOwnershipOfDisposableValue(godot_string from) + => new() {_type = Variant.Type.String, _data = {_m_string = from}}; + + public static unsafe godot_variant CreateFromPackedByteArray(godot_packed_byte_array* from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_packed_byte_array(&ret, from); + return ret; + } + + public static unsafe godot_variant CreateFromPackedInt32Array(godot_packed_int32_array* from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_packed_int32_array(&ret, from); + return ret; + } + + public static unsafe godot_variant CreateFromPackedInt64Array(godot_packed_int64_array* from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_packed_int64_array(&ret, from); + return ret; + } + + public static unsafe godot_variant CreateFromPackedFloat32Array(godot_packed_float32_array* from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_packed_float32_array(&ret, from); + return ret; + } + + public static unsafe godot_variant CreateFromPackedFloat64Array(godot_packed_float64_array* from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_packed_float64_array(&ret, from); + return ret; + } + + public static unsafe godot_variant CreateFromPackedStringArray(godot_packed_string_array* from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_packed_string_array(&ret, from); + return ret; + } + + public static unsafe godot_variant CreateFromPackedVector2Array(godot_packed_vector2_array* from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_packed_vector2_array(&ret, from); + return ret; + } + + public static unsafe godot_variant CreateFromPackedVector3Array(godot_packed_vector3_array* from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_packed_vector3_array(&ret, from); + return ret; + } + + public static unsafe godot_variant CreateFromPackedColorArray(godot_packed_color_array* from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_packed_color_array(&ret, from); + return ret; + } + + public static unsafe godot_variant CreateFromArray(godot_array* from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_array(&ret, from); + return ret; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe godot_variant CreateFromArray(godot_array from) + => CreateFromArray(&from); + + public static unsafe godot_variant CreateFromDictionary(godot_dictionary* from) + { + godot_variant ret; + NativeFuncs.godotsharp_variant_new_dictionary(&ret, from); + return ret; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe godot_variant CreateFromDictionary(godot_dictionary from) + => CreateFromDictionary(&from); + + public static unsafe godot_variant CreateFromStringName(ref godot_string_name arg1) + { + godot_variant ret; + godot_string_name src = arg1; + NativeFuncs.godotsharp_variant_new_string_name(&ret, &src); + return ret; + } + + public static unsafe godot_variant CreateFromNodePath(ref godot_node_path arg1) + { + godot_variant ret; + godot_node_path src = arg1; + NativeFuncs.godotsharp_variant_new_node_path(&ret, &src); + return ret; + } + + public static unsafe godot_variant CreateFromGodotObject(IntPtr from) + { + if (from == IntPtr.Zero) + return new godot_variant(); + godot_variant ret; + NativeFuncs.godotsharp_variant_new_object(&ret, from); + return ret; + } + + // We avoid the internal call if the stored type is the same we want. + + public static unsafe bool ConvertToBool(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Bool ? (*p_var)._data._bool : NativeFuncs.godotsharp_variant_as_bool(p_var); + + public static unsafe char ConvertToChar(godot_variant* p_var) + => (char)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var)); + + public static unsafe sbyte ConvertToInt8(godot_variant* p_var) + => (sbyte)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var)); + + public static unsafe Int16 ConvertToInt16(godot_variant* p_var) + => (Int16)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var)); + + public static unsafe Int32 ConvertToInt32(godot_variant* p_var) + => (Int32)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var)); + + public static unsafe Int64 ConvertToInt64(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var); + + public static unsafe byte ConvertToUInt8(godot_variant* p_var) + => (byte)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var)); + + public static unsafe UInt16 ConvertToUInt16(godot_variant* p_var) + => (UInt16)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var)); + + public static unsafe UInt32 ConvertToUInt32(godot_variant* p_var) + => (UInt32)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var)); + + public static unsafe UInt64 ConvertToUInt64(godot_variant* p_var) + => (UInt64)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var)); + + public static unsafe float ConvertToFloat32(godot_variant* p_var) + => (float)((*p_var)._type == Variant.Type.Float ? (*p_var)._data._float : NativeFuncs.godotsharp_variant_as_float(p_var)); + + public static unsafe double ConvertToFloat64(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Float ? (*p_var)._data._float : NativeFuncs.godotsharp_variant_as_float(p_var); + + public static unsafe Vector2 ConvertToVector2(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Vector2 ? (*p_var)._data._m_vector2 : NativeFuncs.godotsharp_variant_as_vector2(p_var); + + public static unsafe Vector2i ConvertToVector2i(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Vector2i ? (*p_var)._data._m_vector2i : NativeFuncs.godotsharp_variant_as_vector2i(p_var); + + public static unsafe Rect2 ConvertToRect2(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Rect2 ? (*p_var)._data._m_rect2 : NativeFuncs.godotsharp_variant_as_rect2(p_var); + + public static unsafe Rect2i ConvertToRect2i(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Rect2i ? (*p_var)._data._m_rect2i : NativeFuncs.godotsharp_variant_as_rect2i(p_var); + + public static unsafe Transform2D ConvertToTransform2D(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Transform2d ? *(*p_var)._data._transform2d : NativeFuncs.godotsharp_variant_as_transform2d(p_var); + + public static unsafe Vector3 ConvertToVector3(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Vector3 ? (*p_var)._data._m_vector3 : NativeFuncs.godotsharp_variant_as_vector3(p_var); + + public static unsafe Vector3i ConvertToVector3i(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Vector3i ? (*p_var)._data._m_vector3i : NativeFuncs.godotsharp_variant_as_vector3i(p_var); + + public static unsafe Vector4 ConvertToVector4(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Vector4 ? *(*p_var)._data._vector4 : NativeFuncs.godotsharp_variant_as_vector4(p_var); + + public static unsafe Vector4i ConvertToVector4i(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Vector4i ? *(*p_var)._data._vector4i : NativeFuncs.godotsharp_variant_as_vector4i(p_var); + + public static unsafe Basis ConvertToBasis(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Basis ? *(*p_var)._data._basis : NativeFuncs.godotsharp_variant_as_basis(p_var); + + public static unsafe Quaternion ConvertToQuaternion(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Quaternion ? (*p_var)._data._m_quaternion : NativeFuncs.godotsharp_variant_as_quaternion(p_var); + + public static unsafe Transform3D ConvertToTransform3D(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Transform3d ? *(*p_var)._data._transform3d : NativeFuncs.godotsharp_variant_as_transform3d(p_var); + + public static unsafe Projection ConvertToProjection(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Projection ? *(*p_var)._data._projection : NativeFuncs.godotsharp_variant_as_projection(p_var); + + public static unsafe AABB ConvertToAABB(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Aabb ? *(*p_var)._data._aabb : NativeFuncs.godotsharp_variant_as_aabb(p_var); + + public static unsafe Color ConvertToColor(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Color ? (*p_var)._data._m_color : NativeFuncs.godotsharp_variant_as_color(p_var); + + public static unsafe Plane ConvertToPlane(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Plane ? (*p_var)._data._m_plane : NativeFuncs.godotsharp_variant_as_plane(p_var); + + public static unsafe IntPtr ConvertToGodotObject(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Object ? (*p_var)._data._m_obj_data.obj : IntPtr.Zero; + + public static unsafe RID ConvertToRID(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Rid ? (*p_var)._data._m_rid : NativeFuncs.godotsharp_variant_as_rid(p_var); + + public static unsafe godot_string_name ConvertToStringName(godot_variant* p_var) + => (*p_var)._type == Variant.Type.StringName ? + NativeFuncs.godotsharp_string_name_new_copy(&(*p_var)._data._m_string_name) : + NativeFuncs.godotsharp_variant_as_string_name(p_var); + + public static unsafe godot_node_path ConvertToNodePath(godot_variant* p_var) + => (*p_var)._type == Variant.Type.NodePath ? + NativeFuncs.godotsharp_node_path_new_copy(&(*p_var)._data._m_node_path) : + NativeFuncs.godotsharp_variant_as_node_path(p_var); + + public static unsafe godot_array ConvertToArray(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Array ? + NativeFuncs.godotsharp_array_new_copy(&(*p_var)._data._m_array) : + NativeFuncs.godotsharp_variant_as_array(p_var); + + public static unsafe godot_dictionary ConvertToDictionary(godot_variant* p_var) + => (*p_var)._type == Variant.Type.Dictionary ? + NativeFuncs.godotsharp_dictionary_new_copy(&(*p_var)._data._m_dictionary) : + NativeFuncs.godotsharp_variant_as_dictionary(p_var); + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs index 9ae01016cb..90e51e8a1a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.CompilerServices; +using Godot.NativeInterop; namespace Godot { @@ -39,22 +40,9 @@ namespace Godot /// new NodePath("/root/MyAutoload"); // If you have an autoloaded node or scene. /// </code> /// </example> - public sealed partial class NodePath : IDisposable + public sealed class NodePath : IDisposable { - private bool _disposed = false; - - private IntPtr ptr; - - internal static IntPtr GetPtr(NodePath instance) - { - if (instance == null) - throw new NullReferenceException($"The instance of type {nameof(NodePath)} is null."); - - if (instance._disposed) - throw new ObjectDisposedException(instance.GetType().FullName); - - return instance.ptr; - } + internal godot_node_path NativeValue; ~NodePath() { @@ -70,29 +58,27 @@ namespace Godot GC.SuppressFinalize(this); } - private void Dispose(bool disposing) + public void Dispose(bool disposing) { - if (_disposed) - return; - - if (ptr != IntPtr.Zero) - { - godot_icall_NodePath_Dtor(ptr); - ptr = IntPtr.Zero; - } - - _disposed = true; + // Always dispose `NativeValue` even if disposing is true + NativeValue.Dispose(); } - internal NodePath(IntPtr ptr) + private NodePath(godot_node_path nativeValueToOwn) { - this.ptr = ptr; + NativeValue = nativeValueToOwn; } + // Explicit name to make it very clear + internal static NodePath CreateTakingOwnershipOfDisposableValue(godot_node_path nativeValueToOwn) + => new NodePath(nativeValueToOwn); + /// <summary> /// Constructs an empty <see cref="NodePath"/>. /// </summary> - public NodePath() : this(string.Empty) { } + public NodePath() + { + } /// <summary> /// Constructs a <see cref="NodePath"/> from a string <paramref name="path"/>, @@ -125,7 +111,8 @@ namespace Godot /// <param name="path">A string that represents a path in a scene tree.</param> public NodePath(string path) { - ptr = godot_icall_NodePath_Ctor(path); + if (!string.IsNullOrEmpty(path)) + NativeValue = NativeFuncs.godotsharp_node_path_new_from_string(path); } /// <summary> @@ -144,9 +131,16 @@ namespace Godot /// Converts this <see cref="NodePath"/> to a string. /// </summary> /// <returns>A string representation of this <see cref="NodePath"/>.</returns> - public override string ToString() + public override unsafe string ToString() { - return godot_icall_NodePath_operator_String(GetPtr(this)); + if (IsEmpty) + return string.Empty; + + godot_string dest; + godot_node_path src = NativeValue; + NativeFuncs.godotsharp_node_path_as_string(&dest, &src); + using (dest) + return Marshaling.mono_string_from_godot(&dest); } /// <summary> @@ -166,7 +160,9 @@ namespace Godot /// <returns>The <see cref="NodePath"/> as a pure property path.</returns> public NodePath GetAsPropertyPath() { - return new NodePath(godot_icall_NodePath_get_as_property_path(GetPtr(this))); + godot_node_path propertyPath = default; + godot_icall_NodePath_get_as_property_path(ref NativeValue, ref propertyPath); + return CreateTakingOwnershipOfDisposableValue(propertyPath); } /// <summary> @@ -181,7 +177,7 @@ namespace Godot /// <returns>The names concatenated with <c>/</c>.</returns> public string GetConcatenatedNames() { - return godot_icall_NodePath_get_concatenated_names(GetPtr(this)); + return godot_icall_NodePath_get_concatenated_names(ref NativeValue); } /// <summary> @@ -195,9 +191,9 @@ namespace Godot /// </code> /// </example> /// <returns>The subnames concatenated with <c>:</c>.</returns> - public string GetConcatenatedSubnames() + public string GetConcatenatedSubNames() { - return godot_icall_NodePath_get_concatenated_subnames(GetPtr(this)); + return godot_icall_NodePath_get_concatenated_subnames(ref NativeValue); } /// <summary> @@ -215,28 +211,28 @@ namespace Godot /// <returns>The name at the given index <paramref name="idx"/>.</returns> public string GetName(int idx) { - return godot_icall_NodePath_get_name(GetPtr(this), idx); + return godot_icall_NodePath_get_name(ref NativeValue, idx); } /// <summary> /// Gets the number of node names which make up the path. - /// Subnames (see <see cref="GetSubnameCount"/>) are not included. + /// Subnames (see <see cref="GetSubNameCount"/>) are not included. /// For example, <c>"Path2D/PathFollow2D/Sprite2D"</c> has 3 names. /// </summary> /// <returns>The number of node names which make up the path.</returns> public int GetNameCount() { - return godot_icall_NodePath_get_name_count(GetPtr(this)); + return godot_icall_NodePath_get_name_count(ref NativeValue); } /// <summary> - /// Gets the resource or property name indicated by <paramref name="idx"/> (0 to <see cref="GetSubnameCount"/>). + /// Gets the resource or property name indicated by <paramref name="idx"/> (0 to <see cref="GetSubNameCount"/>). /// </summary> /// <param name="idx">The subname index.</param> /// <returns>The subname at the given index <paramref name="idx"/>.</returns> - public string GetSubname(int idx) + public string GetSubName(int idx) { - return godot_icall_NodePath_get_subname(GetPtr(this), idx); + return godot_icall_NodePath_get_subname(ref NativeValue, idx); } /// <summary> @@ -245,9 +241,9 @@ namespace Godot /// For example, <c>"Path2D/PathFollow2D/Sprite2D:texture:load_path"</c> has 2 subnames. /// </summary> /// <returns>The number of subnames in the path.</returns> - public int GetSubnameCount() + public int GetSubNameCount() { - return godot_icall_NodePath_get_subname_count(GetPtr(this)); + return godot_icall_NodePath_get_subname_count(ref NativeValue); } /// <summary> @@ -259,52 +255,37 @@ namespace Godot /// <returns>If the <see cref="NodePath"/> is an absolute path.</returns> public bool IsAbsolute() { - return godot_icall_NodePath_is_absolute(GetPtr(this)); + return godot_icall_NodePath_is_absolute(ref NativeValue); } /// <summary> /// Returns <see langword="true"/> if the node path is empty. /// </summary> /// <returns>If the <see cref="NodePath"/> is empty.</returns> - public bool IsEmpty() - { - return godot_icall_NodePath_is_empty(GetPtr(this)); - } - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern IntPtr godot_icall_NodePath_Ctor(string path); - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern void godot_icall_NodePath_Dtor(IntPtr ptr); - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern string godot_icall_NodePath_operator_String(IntPtr ptr); - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern IntPtr godot_icall_NodePath_get_as_property_path(IntPtr ptr); + public bool IsEmpty => godot_node_path.IsEmpty(in NativeValue); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern string godot_icall_NodePath_get_concatenated_names(IntPtr ptr); + private static extern void godot_icall_NodePath_get_as_property_path(ref godot_node_path ptr, ref godot_node_path dest); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern string godot_icall_NodePath_get_concatenated_subnames(IntPtr ptr); + private static extern string godot_icall_NodePath_get_concatenated_names(ref godot_node_path ptr); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern string godot_icall_NodePath_get_name(IntPtr ptr, int arg1); + private static extern string godot_icall_NodePath_get_concatenated_subnames(ref godot_node_path ptr); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern int godot_icall_NodePath_get_name_count(IntPtr ptr); + private static extern string godot_icall_NodePath_get_name(ref godot_node_path ptr, int arg1); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern string godot_icall_NodePath_get_subname(IntPtr ptr, int arg1); + private static extern int godot_icall_NodePath_get_name_count(ref godot_node_path ptr); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern int godot_icall_NodePath_get_subname_count(IntPtr ptr); + private static extern string godot_icall_NodePath_get_subname(ref godot_node_path ptr, int arg1); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern bool godot_icall_NodePath_is_absolute(IntPtr ptr); + private static extern int godot_icall_NodePath_get_subname_count(ref godot_node_path ptr); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern bool godot_icall_NodePath_is_empty(IntPtr ptr); + private static extern bool godot_icall_NodePath_is_absolute(ref godot_node_path ptr); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs index 746612477d..80d63581c1 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs @@ -7,38 +7,44 @@ namespace Godot { private bool _disposed = false; - private static StringName nativeName = "Object"; - - internal IntPtr ptr; - internal bool memoryOwn; + internal IntPtr NativePtr; + internal bool MemoryOwn; /// <summary> /// Constructs a new <see cref="Object"/>. /// </summary> public Object() : this(false) { - if (ptr == IntPtr.Zero) - ptr = godot_icall_Object_Ctor(this); + if (NativePtr == IntPtr.Zero) + { +#if NET + unsafe + { + ptr = NativeCtor(); + } +#else + NativePtr = _gd__invoke_class_constructor(NativeCtor); +#endif + NativeInterop.InteropUtils.TieManagedToUnmanaged(this, NativePtr); + } + _InitializeGodotScriptInstanceInternals(); } internal void _InitializeGodotScriptInstanceInternals() { - godot_icall_Object_ConnectEventSignals(ptr); + godot_icall_Object_ConnectEventSignals(NativePtr); } internal Object(bool memoryOwn) { - this.memoryOwn = memoryOwn; + this.MemoryOwn = memoryOwn; } /// <summary> /// The pointer to the native instance of this <see cref="Object"/>. /// </summary> - public IntPtr NativeInstance - { - get { return ptr; } - } + public IntPtr NativeInstance => NativePtr; internal static IntPtr GetPtr(Object instance) { @@ -48,7 +54,7 @@ namespace Godot if (instance._disposed) throw new ObjectDisposedException(instance.GetType().FullName); - return instance.ptr; + return instance.NativePtr; } ~Object() @@ -73,19 +79,19 @@ namespace Godot if (_disposed) return; - if (ptr != IntPtr.Zero) + if (NativePtr != IntPtr.Zero) { - if (memoryOwn) + if (MemoryOwn) { - memoryOwn = false; - godot_icall_RefCounted_Disposed(this, ptr, !disposing); + MemoryOwn = false; + godot_icall_RefCounted_Disposed(this, NativePtr, !disposing); } else { - godot_icall_Object_Disposed(this, ptr); + godot_icall_Object_Disposed(this, NativePtr); } - ptr = IntPtr.Zero; + this.NativePtr = IntPtr.Zero; } _disposed = true; @@ -137,13 +143,49 @@ namespace Godot /// </summary> public dynamic DynamicObject => new DynamicGodotObject(this); - internal static IntPtr __ClassDB_get_method(StringName type, string method) + internal static unsafe IntPtr ClassDB_get_method(StringName type, string method) + { + IntPtr methodBind; + fixed (char* methodChars = method) + { + methodBind = NativeInterop.NativeFuncs + .godotsharp_method_bind_get_method(ref type.NativeValue, methodChars); + } + + if (methodBind == IntPtr.Zero) + throw new NativeMethodBindNotFoundException(type + "." + method); + + return methodBind; + } + +#if NET + internal static unsafe delegate* unmanaged<IntPtr> _gd__ClassDB_get_constructor(StringName type) + { + // for some reason the '??' operator doesn't support 'delegate*' + var nativeConstructor = NativeInterop.NativeFuncs + .godotsharp_get_class_constructor(ref type.NativeValue); + + if (nativeConstructor == null) + throw new NativeConstructorNotFoundException(type); + + return nativeConstructor; + } +#else + internal static IntPtr ClassDB_get_constructor(StringName type) { - return godot_icall_Object_ClassDB_get_method(StringName.GetPtr(type), method); + // for some reason the '??' operator doesn't support 'delegate*' + var nativeConstructor = NativeInterop.NativeFuncs + .godotsharp_get_class_constructor(ref type.NativeValue); + + if (nativeConstructor == IntPtr.Zero) + throw new NativeConstructorNotFoundException(type); + + return nativeConstructor; } - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern IntPtr godot_icall_Object_Ctor(Object obj); + internal static IntPtr _gd__invoke_class_constructor(IntPtr ctorFuncPtr) + => NativeInterop.NativeFuncs.godotsharp_invoke_class_constructor(ctorFuncPtr); +#endif [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void godot_icall_Object_Disposed(Object obj, IntPtr ptr); @@ -156,9 +198,5 @@ namespace Godot [MethodImpl(MethodImplOptions.InternalCall)] internal static extern string godot_icall_Object_ToString(IntPtr ptr); - - // Used by the generated API - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern IntPtr godot_icall_Object_ClassDB_get_method(IntPtr type, string method); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs new file mode 100644 index 0000000000..eb2811c73d --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs @@ -0,0 +1,135 @@ +using System; + +#nullable enable + +namespace Godot +{ + public partial class Object + { + public class NativeMemberNotFoundException : Exception + { + public NativeMemberNotFoundException() + { + } + + public NativeMemberNotFoundException(string? message) : base(message) + { + } + + public NativeMemberNotFoundException(string? message, Exception? innerException) + : base(message, innerException) + { + } + } + + public class NativeConstructorNotFoundException : NativeMemberNotFoundException + { + private readonly string? _nativeClassName; + + // ReSharper disable once InconsistentNaming + private const string Arg_NativeConstructorNotFoundException = "Unable to find the native constructor."; + + public NativeConstructorNotFoundException() + : base(Arg_NativeConstructorNotFoundException) + { + } + + public NativeConstructorNotFoundException(string? nativeClassName) + : this(Arg_NativeConstructorNotFoundException, nativeClassName) + { + } + + public NativeConstructorNotFoundException(string? message, Exception? innerException) + : base(message, innerException) + { + } + + public NativeConstructorNotFoundException(string? message, string? nativeClassName) + : base(message) + { + _nativeClassName = nativeClassName; + } + + public NativeConstructorNotFoundException(string? message, string? nativeClassName, Exception? innerException) + : base(message, innerException) + { + _nativeClassName = nativeClassName; + } + + public override string Message + { + get + { + string s = base.Message; + + if (string.IsNullOrEmpty(s)) + { + s = Arg_NativeConstructorNotFoundException; + } + + if (!string.IsNullOrEmpty(_nativeClassName)) + { + s += " " + string.Format("(Class '{0}')", _nativeClassName); + } + + return s; + } + } + } + + public class NativeMethodBindNotFoundException : NativeMemberNotFoundException + { + private readonly string? _nativeMethodName; + + // ReSharper disable once InconsistentNaming + private const string Arg_NativeMethodBindNotFoundException = "Unable to find the native method bind."; + + public NativeMethodBindNotFoundException() + : base(Arg_NativeMethodBindNotFoundException) + { + } + + public NativeMethodBindNotFoundException(string? nativeMethodName) + : this(Arg_NativeMethodBindNotFoundException, nativeMethodName) + { + } + + public NativeMethodBindNotFoundException(string? message, Exception? innerException) + : base(message, innerException) + { + } + + public NativeMethodBindNotFoundException(string? message, string? nativeMethodName) + : base(message) + { + _nativeMethodName = nativeMethodName; + } + + public NativeMethodBindNotFoundException(string? message, string? nativeMethodName, Exception? innerException) + : base(message, innerException) + { + _nativeMethodName = nativeMethodName; + } + + public override string Message + { + get + { + string s = base.Message; + + if (string.IsNullOrEmpty(s)) + { + s = Arg_NativeMethodBindNotFoundException; + } + + if (!string.IsNullOrEmpty(_nativeMethodName)) + { + s += " " + string.Format("(Method '{0}')", _nativeMethodName); + } + + return s; + } + } + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs index 1588869ec0..a31fef8360 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs @@ -1,5 +1,7 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Godot.NativeInterop; namespace Godot { @@ -9,99 +11,32 @@ namespace Godot /// resource by themselves. They are used by and with the low-level Server /// classes such as <see cref="RenderingServer"/>. /// </summary> - public sealed partial class RID : IDisposable + [StructLayout(LayoutKind.Sequential)] + public struct RID { - private bool _disposed = false; + private ulong _id; // Default is 0 - internal IntPtr ptr; - - internal static IntPtr GetPtr(RID instance) - { - if (instance == null) - throw new NullReferenceException($"The instance of type {nameof(RID)} is null."); - - if (instance._disposed) - throw new ObjectDisposedException(instance.GetType().FullName); - - return instance.ptr; - } - - ~RID() - { - Dispose(false); - } - - /// <summary> - /// Disposes of this <see cref="RID"/>. - /// </summary> - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (_disposed) - return; - - if (ptr != IntPtr.Zero) - { - godot_icall_RID_Dtor(ptr); - ptr = IntPtr.Zero; - } - - _disposed = true; - } - - internal RID(IntPtr ptr) + internal RID(ulong id) { - this.ptr = ptr; - } - - /// <summary> - /// The pointer to the native instance of this <see cref="RID"/>. - /// </summary> - public IntPtr NativeInstance - { - get { return ptr; } - } - - internal RID() - { - this.ptr = IntPtr.Zero; + _id = id; } /// <summary> /// Constructs a new <see cref="RID"/> for the given <see cref="Object"/> <paramref name="from"/>. /// </summary> public RID(Object from) - { - this.ptr = godot_icall_RID_Ctor(Object.GetPtr(from)); - } + => _id = from is Resource res ? res.GetRid()._id : default; /// <summary> /// Returns the ID of the referenced resource. /// </summary> /// <returns>The ID of the referenced resource.</returns> - public int GetId() - { - return godot_icall_RID_get_id(GetPtr(this)); - } + public ulong Id => _id; /// <summary> /// Converts this <see cref="RID"/> to a string. /// </summary> /// <returns>A string representation of this RID.</returns> - public override string ToString() => "[RID]"; - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern IntPtr godot_icall_RID_Ctor(IntPtr from); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_RID_Dtor(IntPtr ptr); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern int godot_icall_RID_get_id(IntPtr ptr); + public override string ToString() => $"RID({Id})"; } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs index 2ba0493002..e485207fb4 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.CompilerServices; +using Godot.NativeInterop; namespace Godot { @@ -11,34 +12,22 @@ namespace Godot public SignalAwaiter(Object source, StringName signal, Object target) { - godot_icall_SignalAwaiter_connect(Object.GetPtr(source), StringName.GetPtr(signal), Object.GetPtr(target), this); + godot_icall_SignalAwaiter_connect(Object.GetPtr(source), ref signal.NativeValue, Object.GetPtr(target), this); } [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern Error godot_icall_SignalAwaiter_connect(IntPtr source, IntPtr signal, IntPtr target, SignalAwaiter awaiter); + internal static extern Error godot_icall_SignalAwaiter_connect(IntPtr source, ref godot_string_name signal, IntPtr target, SignalAwaiter awaiter); - public bool IsCompleted - { - get - { - return _completed; - } - } + public bool IsCompleted => _completed; public void OnCompleted(Action action) { this._action = action; } - public object[] GetResult() - { - return _result; - } + public object[] GetResult() => _result; - public IAwaiter<object[]> GetAwaiter() - { - return this; - } + public IAwaiter<object[]> GetAwaiter() => this; internal void SignalCallback(object[] args) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index a1f058ffe5..058c5447e2 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -214,7 +214,7 @@ namespace Godot /// <returns>The escaped string.</returns> public static string CEscape(this string instance) { - var sb = new StringBuilder(string.Copy(instance)); + var sb = new StringBuilder(instance); sb.Replace("\\", "\\\\"); sb.Replace("\a", "\\a"); @@ -239,7 +239,7 @@ namespace Godot /// <returns>The unescaped string.</returns> public static string CUnescape(this string instance) { - var sb = new StringBuilder(string.Copy(instance)); + var sb = new StringBuilder(instance); sb.Replace("\\a", "\a"); sb.Replace("\\b", "\b"); @@ -926,7 +926,7 @@ namespace Godot /// <returns>The escaped string.</returns> public static string JSONEscape(this string instance) { - var sb = new StringBuilder(string.Copy(instance)); + var sb = new StringBuilder(instance); sb.Replace("\\", "\\\\"); sb.Replace("\b", "\\b"); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs index b1d504410b..40d282eab4 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.CompilerServices; +using Godot.NativeInterop; namespace Godot { @@ -10,20 +11,9 @@ namespace Godot /// Comparing them is much faster than with regular strings, because only the pointers are compared, /// not the whole strings. /// </summary> - public sealed partial class StringName : IDisposable + public sealed class StringName : IDisposable { - private IntPtr ptr; - - internal static IntPtr GetPtr(StringName instance) - { - if (instance == null) - throw new NullReferenceException($"The instance of type {nameof(StringName)} is null."); - - if (instance.ptr == IntPtr.Zero) - throw new ObjectDisposedException(instance.GetType().FullName); - - return instance.ptr; - } + internal godot_string_name NativeValue; ~StringName() { @@ -39,35 +29,36 @@ namespace Godot GC.SuppressFinalize(this); } - private void Dispose(bool disposing) + public void Dispose(bool disposing) { - if (ptr != IntPtr.Zero) - { - godot_icall_StringName_Dtor(ptr); - ptr = IntPtr.Zero; - } + // Always dispose `NativeValue` even if disposing is true + NativeValue.Dispose(); } - internal StringName(IntPtr ptr) + private StringName(godot_string_name nativeValueToOwn) { - this.ptr = ptr; + NativeValue = nativeValueToOwn; } + // Explicit name to make it very clear + internal static StringName CreateTakingOwnershipOfDisposableValue(godot_string_name nativeValueToOwn) + => new StringName(nativeValueToOwn); + /// <summary> /// Constructs an empty <see cref="StringName"/>. /// </summary> public StringName() { - ptr = IntPtr.Zero; } /// <summary> /// Constructs a <see cref="StringName"/> from the given <paramref name="path"/> string. /// </summary> /// <param name="path">String to construct the <see cref="StringName"/> from.</param> - public StringName(string path) + public StringName(string name) { - ptr = path == null ? IntPtr.Zero : godot_icall_StringName_Ctor(path); + if (!string.IsNullOrEmpty(name)) + NativeValue = NativeFuncs.godotsharp_string_name_new_from_string(name); } /// <summary> @@ -86,30 +77,22 @@ namespace Godot /// Converts this <see cref="StringName"/> to a string. /// </summary> /// <returns>A string representation of this <see cref="StringName"/>.</returns> - public override string ToString() + public override unsafe string ToString() { - return ptr == IntPtr.Zero ? string.Empty : godot_icall_StringName_operator_String(GetPtr(this)); + if (IsEmpty) + return string.Empty; + + godot_string dest; + godot_string_name src = NativeValue; + NativeFuncs.godotsharp_string_name_as_string(&dest, &src); + using (dest) + return Marshaling.mono_string_from_godot(&dest); } /// <summary> /// Check whether this <see cref="StringName"/> is empty. /// </summary> /// <returns>If the <see cref="StringName"/> is empty.</returns> - public bool IsEmpty() - { - return ptr == IntPtr.Zero || godot_icall_StringName_is_empty(GetPtr(this)); - } - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern IntPtr godot_icall_StringName_Ctor(string path); - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern void godot_icall_StringName_Dtor(IntPtr ptr); - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern string godot_icall_StringName_operator_String(IntPtr ptr); - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern bool godot_icall_StringName_is_empty(IntPtr ptr); + public bool IsEmpty => godot_string_name.IsEmpty(in NativeValue); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index 4f55ce47e8..9683d8e812 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -7,11 +7,20 @@ <TargetFramework>netstandard2.1</TargetFramework> <DocumentationFile>$(OutputPath)/$(AssemblyName).xml</DocumentationFile> <EnableDefaultItems>false</EnableDefaultItems> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <LangVersion>9</LangVersion> + + <!-- Disabled temporarily as it pollutes the warnings, but we need to document public APIs. --> + <NoWarn>CS1591</NoWarn> </PropertyGroup> <PropertyGroup> <DefineConstants>$(DefineConstants);GODOT</DefineConstants> </PropertyGroup> <ItemGroup> + <PackageReference Include="ReflectionAnalyzers" Version="0.1.22-dev" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers" /> + <!--PackageReference Include="IDisposableAnalyzers" Version="3.4.13" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers" /--> + </ItemGroup> + <ItemGroup> <Compile Include="Core\AABB.cs" /> <Compile Include="Core\Array.cs" /> <Compile Include="Core\Attributes\AssemblyHasScriptsAttribute.cs" /> @@ -47,14 +56,22 @@ <Compile Include="Core\MarshalUtils.cs" /> <Compile Include="Core\Mathf.cs" /> <Compile Include="Core\MathfEx.cs" /> + <Compile Include="Core\NativeInterop\InteropUtils.cs" /> + <Compile Include="Core\NativeInterop\NativeFuncs.extended.cs" /> + <Compile Include="Core\NativeInterop\VariantSpanHelpers.cs" /> + <Compile Include="Core\NativeInterop\VariantUtils.cs" /> <Compile Include="Core\NodePath.cs" /> <Compile Include="Core\Object.base.cs" /> + <Compile Include="Core\Object.exceptions.cs" /> <Compile Include="Core\Plane.cs" /> <Compile Include="Core\Projection.cs" /> <Compile Include="Core\Quaternion.cs" /> <Compile Include="Core\Rect2.cs" /> <Compile Include="Core\Rect2i.cs" /> <Compile Include="Core\RID.cs" /> + <Compile Include="Core\NativeInterop\NativeFuncs.cs" /> + <Compile Include="Core\NativeInterop\InteropStructs.cs" /> + <Compile Include="Core\NativeInterop\Marshaling.cs" /> <Compile Include="Core\SignalInfo.cs" /> <Compile Include="Core\SignalAwaiter.cs" /> <Compile Include="Core\StringExtensions.cs" /> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj.DotSettings b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj.DotSettings new file mode 100644 index 0000000000..1add6cc77e --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj.DotSettings @@ -0,0 +1,5 @@ +<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> + <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=core/@EntryIndexedValue">True</s:Boolean> + <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generated/@EntryIndexedValue">True</s:Boolean> + <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generated_005Cgodotobjects/@EntryIndexedValue">True</s:Boolean> +</wpf:ResourceDictionary> diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj index a8c4ba96b5..1082c74448 100644 --- a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj @@ -7,6 +7,8 @@ <TargetFramework>netstandard2.1</TargetFramework> <DocumentationFile>$(OutputPath)/$(AssemblyName).xml</DocumentationFile> <EnableDefaultItems>false</EnableDefaultItems> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <LangVersion>9</LangVersion> </PropertyGroup> <PropertyGroup> <DefineConstants>$(DefineConstants);GODOT</DefineConstants> diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj.DotSettings b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj.DotSettings new file mode 100644 index 0000000000..c7ff6fd3ee --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj.DotSettings @@ -0,0 +1,4 @@ +<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> + <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generated/@EntryIndexedValue">True</s:Boolean> + <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generated_005Cgodotobjects/@EntryIndexedValue">True</s:Boolean> +</wpf:ResourceDictionary> diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp index 7b9dbc87cf..05a8ef20f9 100644 --- a/modules/mono/glue/base_object_glue.cpp +++ b/modules/mono/glue/base_object_glue.cpp @@ -28,8 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef MONO_GLUE_ENABLED - #include "core/object/class_db.h" #include "core/object/ref_counted.h" #include "core/string/string_name.h" @@ -43,12 +41,6 @@ #include "../signal_awaiter_utils.h" #include "arguments_vector.h" -Object *godot_icall_Object_Ctor(MonoObject *p_obj) { - Object *instance = memnew(Object); - GDMonoInternals::tie_managed_to_unmanaged(p_obj, instance); - return instance; -} - void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) { #ifdef DEBUG_ENABLED CRASH_COND(p_ptr == nullptr); @@ -133,12 +125,6 @@ void godot_icall_Object_ConnectEventSignals(Object *p_ptr) { } } -MethodBind *godot_icall_Object_ClassDB_get_method(StringName *p_type, MonoString *p_method) { - StringName type = p_type ? *p_type : StringName(); - StringName method(GDMonoMarshal::mono_string_to_godot(p_method)); - return ClassDB::get_method(type, method); -} - MonoObject *godot_icall_Object_weakref(Object *p_ptr) { if (!p_ptr) { return nullptr; @@ -240,11 +226,9 @@ MonoString *godot_icall_Object_ToString(Object *p_ptr) { } void godot_register_object_icalls() { - GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Ctor", godot_icall_Object_Ctor); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Disposed", godot_icall_Object_Disposed); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_RefCounted_Disposed", godot_icall_RefCounted_Disposed); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ConnectEventSignals", godot_icall_Object_ConnectEventSignals); - GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", godot_icall_Object_ClassDB_get_method); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ToString", godot_icall_Object_ToString); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_weakref", godot_icall_Object_weakref); GDMonoUtils::add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", godot_icall_SignalAwaiter_connect); @@ -253,5 +237,3 @@ void godot_register_object_icalls() { GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_GetMember", godot_icall_DynamicGodotObject_GetMember); GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMember", godot_icall_DynamicGodotObject_SetMember); } - -#endif // MONO_GLUE_ENABLED diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index 8a9f30459c..30adea60cc 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,8 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef MONO_GLUE_ENABLED - #include <mono/metadata/exception.h> #include "core/variant/array.h" @@ -39,28 +37,17 @@ #include "../mono_gd/gd_mono_marshal.h" #include "../mono_gd/gd_mono_utils.h" -Array *godot_icall_Array_Ctor() { - return memnew(Array); -} - -void godot_icall_Array_Dtor(Array *ptr) { - memdelete(ptr); -} - -MonoObject *godot_icall_Array_At(Array *ptr, int32_t index) { - if (index < 0 || index >= ptr->size()) { - GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range()); - return nullptr; - } - return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index)); +void godot_icall_Array_Ctor(Array *r_dest) { + memnew_placement(r_dest, Array); } -MonoObject *godot_icall_Array_At_Generic(Array *ptr, int32_t index, uint32_t type_encoding, GDMonoClass *type_class) { +void godot_icall_Array_At(Array *ptr, int32_t index, Variant *r_elem) { if (index < 0 || index >= ptr->size()) { GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range()); - return nullptr; + *r_elem = Variant(); + return; } - return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index), ManagedType(type_encoding, type_class)); + *r_elem = ptr->operator[](index); } void godot_icall_Array_SetAt(Array *ptr, int32_t index, MonoObject *value) { @@ -104,29 +91,27 @@ void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int32_t array_index) } } -Array *godot_icall_Array_Ctor_MonoArray(MonoArray *mono_array) { - Array *godot_array = memnew(Array); +void godot_icall_Array_Ctor_MonoArray(MonoArray *mono_array, Array *r_dest) { + memnew_placement(r_dest, Array); unsigned int count = mono_array_length(mono_array); - godot_array->resize(count); + r_dest->resize(count); for (unsigned int i = 0; i < count; i++) { MonoObject *item = mono_array_get(mono_array, MonoObject *, i); - godot_icall_Array_SetAt(godot_array, i, item); + godot_icall_Array_SetAt(r_dest, i, item); } - return godot_array; } -Array *godot_icall_Array_Duplicate(Array *ptr, MonoBoolean deep) { - return memnew(Array(ptr->duplicate(deep))); +void godot_icall_Array_Duplicate(Array *ptr, MonoBoolean deep, Array *r_dest) { + memnew_placement(r_dest, Array(ptr->duplicate(deep))); } -Array *godot_icall_Array_Concatenate(Array *left, Array *right) { +void godot_icall_Array_Concatenate(Array *left, Array *right, Array *r_dest) { int count = left->size() + right->size(); - Array *new_array = memnew(Array(left->duplicate(false))); - new_array->resize(count); + memnew_placement(r_dest, Array(left->duplicate(false))); + r_dest->resize(count); for (unsigned int i = 0; i < (unsigned int)right->size(); i++) { - new_array->operator[](i + left->size()) = right->operator[](i); + r_dest->operator[](i + left->size()) = right->operator[](i); } - return new_array; } int32_t godot_icall_Array_IndexOf(Array *ptr, MonoObject *item) { @@ -166,41 +151,15 @@ void godot_icall_Array_Shuffle(Array *ptr) { ptr->shuffle(); } -void godot_icall_Array_Generic_GetElementTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) { - MonoType *elem_type = mono_reflection_type_get_type(refltype); - - *type_encoding = mono_type_get_type(elem_type); - MonoClass *type_class_raw = mono_class_from_mono_type(elem_type); - *type_class = GDMono::get_singleton()->get_class(type_class_raw); -} - MonoString *godot_icall_Array_ToString(Array *ptr) { return GDMonoMarshal::mono_string_from_godot(Variant(*ptr).operator String()); } -Dictionary *godot_icall_Dictionary_Ctor() { - return memnew(Dictionary); -} - -void godot_icall_Dictionary_Dtor(Dictionary *ptr) { - memdelete(ptr); -} - -MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key) { - Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); - if (ret == nullptr) { - MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr()); -#ifdef DEBUG_ENABLED - CRASH_COND(!exc); -#endif - GDMonoUtils::runtime_object_init(exc, CACHED_CLASS(KeyNotFoundException)); - GDMonoUtils::set_pending_exception((MonoException *)exc); - return nullptr; - } - return GDMonoMarshal::variant_to_mono_object(ret); +void godot_icall_Dictionary_Ctor(Dictionary *r_dest) { + memnew_placement(r_dest, Dictionary); } -MonoObject *godot_icall_Dictionary_GetValue_Generic(Dictionary *ptr, MonoObject *key, uint32_t type_encoding, GDMonoClass *type_class) { +void godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key, Variant *r_value) { Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); if (ret == nullptr) { MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr()); @@ -209,42 +168,37 @@ MonoObject *godot_icall_Dictionary_GetValue_Generic(Dictionary *ptr, MonoObject #endif GDMonoUtils::runtime_object_init(exc, CACHED_CLASS(KeyNotFoundException)); GDMonoUtils::set_pending_exception((MonoException *)exc); - return nullptr; + *r_value = Variant(); + return; } - return GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class)); + *r_value = *ret; } void godot_icall_Dictionary_SetValue(Dictionary *ptr, MonoObject *key, MonoObject *value) { ptr->operator[](GDMonoMarshal::mono_object_to_variant(key)) = GDMonoMarshal::mono_object_to_variant(value); } -Array *godot_icall_Dictionary_Keys(Dictionary *ptr) { - return memnew(Array(ptr->keys())); +void godot_icall_Dictionary_Keys(Dictionary *ptr, Array *r_dest) { + memnew_placement(r_dest, Array(ptr->keys())); } -Array *godot_icall_Dictionary_Values(Dictionary *ptr) { - return memnew(Array(ptr->values())); +void godot_icall_Dictionary_Values(Dictionary *ptr, Array *r_dest) { + memnew_placement(r_dest, Array(ptr->values())); } int32_t godot_icall_Dictionary_Count(Dictionary *ptr) { return ptr->size(); } -int32_t godot_icall_Dictionary_KeyValuePairs(Dictionary *ptr, Array **keys, Array **values) { - *keys = godot_icall_Dictionary_Keys(ptr); - *values = godot_icall_Dictionary_Values(ptr); - return godot_icall_Dictionary_Count(ptr); -} - -void godot_icall_Dictionary_KeyValuePairAt(Dictionary *ptr, int index, MonoObject **key, MonoObject **value) { - *key = GDMonoMarshal::variant_to_mono_object(ptr->get_key_at_index(index)); - *value = GDMonoMarshal::variant_to_mono_object(ptr->get_value_at_index(index)); +int32_t godot_icall_Dictionary_KeyValuePairs(Dictionary *ptr, Array *keys, Array *values) { + memnew_placement(keys, Array(ptr->keys())); + memnew_placement(values, Array(ptr->values())); + return ptr->size(); } -void godot_icall_Dictionary_KeyValuePairAt_Generic(Dictionary *ptr, int index, MonoObject **key, MonoObject **value, uint32_t value_type_encoding, GDMonoClass *value_type_class) { - ManagedType type(value_type_encoding, value_type_class); - *key = GDMonoMarshal::variant_to_mono_object(ptr->get_key_at_index(index)); - *value = GDMonoMarshal::variant_to_mono_object(ptr->get_value_at_index(index), type); +void godot_icall_Dictionary_KeyValuePairAt(Dictionary *ptr, int index, Variant *r_key, Variant *r_value) { + memnew_placement(r_key, Variant(ptr->get_key_at_index(index))); + memnew_placement(r_value, Variant(ptr->get_value_at_index(index))); } void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) { @@ -271,8 +225,8 @@ MonoBoolean godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) return ptr->has(GDMonoMarshal::mono_object_to_variant(key)); } -Dictionary *godot_icall_Dictionary_Duplicate(Dictionary *ptr, MonoBoolean deep) { - return memnew(Dictionary(ptr->duplicate(deep))); +void godot_icall_Dictionary_Duplicate(Dictionary *ptr, MonoBoolean deep, Dictionary *r_dest) { + memnew_placement(r_dest, Dictionary(ptr->duplicate(deep))); } MonoBoolean godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) { @@ -292,34 +246,16 @@ MonoBoolean godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, Mono return false; } -MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) { - Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); - if (ret == nullptr) { - *value = nullptr; - return false; - } - *value = GDMonoMarshal::variant_to_mono_object(ret); - return true; -} - -MonoBoolean godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) { +MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, Variant *value) { Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); if (ret == nullptr) { - *value = nullptr; + *value = Variant(); return false; } - *value = GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class)); + *value = *ret; return true; } -void godot_icall_Dictionary_Generic_GetValueTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) { - MonoType *value_type = mono_reflection_type_get_type(refltype); - - *type_encoding = mono_type_get_type(value_type); - MonoClass *type_class_raw = mono_class_from_mono_type(value_type); - *type_class = GDMono::get_singleton()->get_class(type_class_raw); -} - MonoString *godot_icall_Dictionary_ToString(Dictionary *ptr) { return GDMonoMarshal::mono_string_from_godot(Variant(*ptr).operator String()); } @@ -327,9 +263,7 @@ MonoString *godot_icall_Dictionary_ToString(Dictionary *ptr) { void godot_register_collections_icalls() { GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor", godot_icall_Array_Ctor); GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor_MonoArray", godot_icall_Array_Ctor_MonoArray); - GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Dtor", godot_icall_Array_Dtor); GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_At", godot_icall_Array_At); - GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_At_Generic", godot_icall_Array_At_Generic); GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_SetAt", godot_icall_Array_SetAt); GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Count", godot_icall_Array_Count); GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Add", godot_icall_Array_Add); @@ -344,20 +278,16 @@ void godot_register_collections_icalls() { GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_RemoveAt", godot_icall_Array_RemoveAt); GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Resize", godot_icall_Array_Resize); GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Shuffle", godot_icall_Array_Shuffle); - GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Generic_GetElementTypeInfo", godot_icall_Array_Generic_GetElementTypeInfo); GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_ToString", godot_icall_Array_ToString); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Ctor", godot_icall_Dictionary_Ctor); - GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Dtor", godot_icall_Dictionary_Dtor); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue", godot_icall_Dictionary_GetValue); - GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue_Generic", godot_icall_Dictionary_GetValue_Generic); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_SetValue", godot_icall_Dictionary_SetValue); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", godot_icall_Dictionary_Keys); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", godot_icall_Dictionary_Values); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", godot_icall_Dictionary_Count); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairs", godot_icall_Dictionary_KeyValuePairs); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairAt", godot_icall_Dictionary_KeyValuePairAt); - GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairAt_Generic", godot_icall_Dictionary_KeyValuePairAt_Generic); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", godot_icall_Dictionary_Add); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", godot_icall_Dictionary_Clear); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", godot_icall_Dictionary_Contains); @@ -366,9 +296,5 @@ void godot_register_collections_icalls() { GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_RemoveKey", godot_icall_Dictionary_RemoveKey); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Remove", godot_icall_Dictionary_Remove); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue", godot_icall_Dictionary_TryGetValue); - GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue_Generic", godot_icall_Dictionary_TryGetValue_Generic); - GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Generic_GetValueTypeInfo", godot_icall_Dictionary_Generic_GetValueTypeInfo); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ToString", godot_icall_Dictionary_ToString); } - -#endif // MONO_GLUE_ENABLED diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp index 8b1c2b729e..b315831819 100644 --- a/modules/mono/glue/gd_glue.cpp +++ b/modules/mono/glue/gd_glue.cpp @@ -28,8 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef MONO_GLUE_ENABLED - #include "core/io/marshalls.h" #include "core/os/os.h" #include "core/string/ustring.h" @@ -41,10 +39,9 @@ #include "../mono_gd/gd_mono_marshal.h" #include "../mono_gd/gd_mono_utils.h" -MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes, MonoBoolean p_allow_objects) { +MonoObject *godot_icall_GD_bytes2var(PackedByteArray *p_bytes, MonoBoolean p_allow_objects) { Variant ret; - PackedByteArray varr = GDMonoMarshal::mono_array_to_PackedByteArray(p_bytes); - Error err = decode_variant(ret, varr.ptr(), varr.size(), nullptr, p_allow_objects); + Error err = decode_variant(ret, p_bytes->ptr(), p_bytes->size(), nullptr, p_allow_objects); if (err != OK) { ret = RTR("Not enough bytes for decoding bytes, or invalid format."); } @@ -285,18 +282,17 @@ void godot_icall_GD_pushwarning(MonoString *p_str) { WARN_PRINT(GDMonoMarshal::mono_string_to_godot(p_str)); } -MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_objects) { +void godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_objects, PackedByteArray *r_bytes) { + memnew_placement(r_bytes, PackedByteArray); + Variant var = GDMonoMarshal::mono_object_to_variant(p_var); - PackedByteArray barr; int len; Error err = encode_variant(var, nullptr, len, p_full_objects); - ERR_FAIL_COND_V_MSG(err != OK, nullptr, "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."); + ERR_FAIL_COND_MSG(err != OK, "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."); - barr.resize(len); - encode_variant(var, barr.ptrw(), len, p_full_objects); - - return GDMonoMarshal::PackedByteArray_to_mono_array(barr); + r_bytes->resize(len); + encode_variant(var, r_bytes->ptrw(), len, p_full_objects); } MonoString *godot_icall_GD_var2str(MonoObject *p_var) { @@ -344,5 +340,3 @@ void godot_register_gd_icalls() { // Dispatcher GDMonoUtils::add_internal_call("Godot.Dispatcher::godot_icall_DefaultGodotTaskScheduler", godot_icall_DefaultGodotTaskScheduler); } - -#endif // MONO_GLUE_ENABLED diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h deleted file mode 100644 index f9ad1a9893..0000000000 --- a/modules/mono/glue/glue_header.h +++ /dev/null @@ -1,91 +0,0 @@ -/*************************************************************************/ -/* glue_header.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef GLUE_HEADER_H -#define GLUE_HEADER_H - -#ifdef MONO_GLUE_ENABLED - -#include "../mono_gd/gd_mono_marshal.h" - -void godot_register_collections_icalls(); -void godot_register_gd_icalls(); -void godot_register_string_name_icalls(); -void godot_register_nodepath_icalls(); -void godot_register_callable_icalls(); -void godot_register_object_icalls(); -void godot_register_rid_icalls(); -void godot_register_string_icalls(); -void godot_register_scene_tree_icalls(); - -/** - * Registers internal calls that were not generated. This function is called - * from the generated GodotSharpBindings::register_generated_icalls() function. - */ -void godot_register_glue_header_icalls() { - godot_register_collections_icalls(); - godot_register_gd_icalls(); - godot_register_string_name_icalls(); - godot_register_nodepath_icalls(); - godot_register_callable_icalls(); - godot_register_object_icalls(); - godot_register_rid_icalls(); - godot_register_string_icalls(); - godot_register_scene_tree_icalls(); -} - -// Used by the generated glue - -#include "core/config/engine.h" -#include "core/object/class_db.h" -#include "core/object/method_bind.h" -#include "core/object/ref_counted.h" -#include "core/string/node_path.h" -#include "core/string/ustring.h" -#include "core/typedefs.h" -#include "core/variant/array.h" -#include "core/variant/dictionary.h" - -#include "../mono_gd/gd_mono_class.h" -#include "../mono_gd/gd_mono_internals.h" -#include "../mono_gd/gd_mono_utils.h" - -#define GODOTSHARP_INSTANCE_OBJECT(m_instance, m_type) \ - static ClassDB::ClassInfo *ci = nullptr; \ - if (!ci) { \ - ci = ClassDB::classes.getptr(m_type); \ - } \ - Object *m_instance = ci->creation_func(); - -#include "arguments_vector.h" - -#endif // MONO_GLUE_ENABLED - -#endif // GLUE_HEADER_H diff --git a/modules/mono/glue/nodepath_glue.cpp b/modules/mono/glue/node_path_glue.cpp index 16e1509eb0..770ed31260 100644 --- a/modules/mono/glue/nodepath_glue.cpp +++ b/modules/mono/glue/node_path_glue.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* nodepath_glue.cpp */ +/* node_path_glue.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,26 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef MONO_GLUE_ENABLED - #include "core/string/node_path.h" #include "core/string/ustring.h" #include "../mono_gd/gd_mono_marshal.h" -NodePath *godot_icall_NodePath_Ctor(MonoString *p_path) { - return memnew(NodePath(GDMonoMarshal::mono_string_to_godot(p_path))); -} - -void godot_icall_NodePath_Dtor(NodePath *p_ptr) { - ERR_FAIL_NULL(p_ptr); - memdelete(p_ptr); -} - -MonoString *godot_icall_NodePath_operator_String(NodePath *p_np) { - return GDMonoMarshal::mono_string_from_godot(p_np->operator String()); -} - MonoBoolean godot_icall_NodePath_is_absolute(NodePath *p_ptr) { return (MonoBoolean)p_ptr->is_absolute(); } @@ -76,18 +61,11 @@ MonoString *godot_icall_NodePath_get_concatenated_subnames(NodePath *p_ptr) { return GDMonoMarshal::mono_string_from_godot(p_ptr->get_concatenated_subnames()); } -NodePath *godot_icall_NodePath_get_as_property_path(NodePath *p_ptr) { - return memnew(NodePath(p_ptr->get_as_property_path())); +void godot_icall_NodePath_get_as_property_path(NodePath *p_ptr, NodePath *r_dest) { + *r_dest = p_ptr->get_as_property_path(); } -MonoBoolean godot_icall_NodePath_is_empty(NodePath *p_ptr) { - return (MonoBoolean)p_ptr->is_empty(); -} - -void godot_register_nodepath_icalls() { - GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_Ctor", godot_icall_NodePath_Ctor); - GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_Dtor", godot_icall_NodePath_Dtor); - GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_operator_String", godot_icall_NodePath_operator_String); +void godot_register_node_path_icalls() { GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_as_property_path", godot_icall_NodePath_get_as_property_path); GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_names", godot_icall_NodePath_get_concatenated_names); GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_subnames", godot_icall_NodePath_get_concatenated_subnames); @@ -96,7 +74,4 @@ void godot_register_nodepath_icalls() { GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname", godot_icall_NodePath_get_subname); GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname_count", godot_icall_NodePath_get_subname_count); GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_is_absolute", godot_icall_NodePath_is_absolute); - GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_is_empty", godot_icall_NodePath_is_empty); } - -#endif // MONO_GLUE_ENABLED diff --git a/modules/mono/glue/rid_glue.cpp b/modules/mono/glue/placeholder_glue.cpp index 3e09564539..edac231bb4 100644 --- a/modules/mono/glue/rid_glue.cpp +++ b/modules/mono/glue/placeholder_glue.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* rid_glue.cpp */ +/* placeholder_glue.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,37 +28,29 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef MONO_GLUE_ENABLED +#ifndef GLUE_HEADER_H +#define GLUE_HEADER_H -#include "core/io/resource.h" -#include "core/object/class_db.h" -#include "core/templates/rid.h" +#include "core/object/object.h" -#include "../mono_gd/gd_mono_marshal.h" +#include "../mono_gd/gd_mono_internals.h" +#include "../mono_gd/gd_mono_utils.h" -RID *godot_icall_RID_Ctor(Object *p_from) { - Resource *res_from = Object::cast_to<Resource>(p_from); - - if (res_from) { - return memnew(RID(res_from->get_rid())); - } - - return memnew(RID); -} - -void godot_icall_RID_Dtor(RID *p_ptr) { - ERR_FAIL_NULL(p_ptr); - memdelete(p_ptr); +MonoObject *godot_icall_InteropUtils_unmanaged_get_managed(Object *unmanaged) { + return GDMonoUtils::unmanaged_get_managed(unmanaged); } -uint32_t godot_icall_RID_get_id(RID *p_ptr) { - return p_ptr->get_id(); +void godot_icall_InteropUtils_tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { + GDMonoInternals::tie_managed_to_unmanaged(managed, unmanaged); } -void godot_register_rid_icalls() { - GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_Ctor", godot_icall_RID_Ctor); - GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_Dtor", godot_icall_RID_Dtor); - GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_get_id", godot_icall_RID_get_id); +void godot_register_placeholder_icalls() { + GDMonoUtils::add_internal_call( + "Godot.NativeInterop.InteropUtils::internal_unmanaged_get_managed", + godot_icall_InteropUtils_unmanaged_get_managed); + GDMonoUtils::add_internal_call( + "Godot.NativeInterop.InteropUtils::internal_tie_managed_to_unmanaged", + godot_icall_InteropUtils_tie_managed_to_unmanaged); } -#endif // MONO_GLUE_ENABLED +#endif // GLUE_HEADER_H diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp new file mode 100644 index 0000000000..a9c47f8880 --- /dev/null +++ b/modules/mono/glue/runtime_interop.cpp @@ -0,0 +1,786 @@ +/*************************************************************************/ +/* runtime_interop.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "core/config/engine.h" +#include "core/object/class_db.h" +#include "core/object/method_bind.h" +#include "core/string/string_name.h" + +#include "../interop_types.h" + +#include "modules/mono/managed_callable.h" +#include "modules/mono/signal_awaiter_utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +#define MAYBE_UNUSED [[maybe_unused]] +#else +#define MAYBE_UNUSED +#endif + +#ifdef __GNUC__ +#define GD_PINVOKE_EXPORT MAYBE_UNUSED __attribute__((visibility("default"))) +#elif defined(_WIN32) +#define GD_PINVOKE_EXPORT MAYBE_UNUSED __declspec(dllexport) +#else +#define GD_PINVOKE_EXPORT MAYBE_UNUSED +#endif + +typedef Object *(*godotsharp_class_creation_func)(); + +GD_PINVOKE_EXPORT MethodBind *godotsharp_method_bind_get_method(const StringName *p_classname, const char16_t *p_methodname) { + return ClassDB::get_method(*p_classname, StringName(String::utf16(p_methodname))); +} + +GD_PINVOKE_EXPORT godotsharp_class_creation_func godotsharp_get_class_constructor(const StringName *p_classname) { + ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(*p_classname); + if (class_info) { + return class_info->creation_func; + } + return nullptr; +} + +GD_PINVOKE_EXPORT Object *godotsharp_invoke_class_constructor(godotsharp_class_creation_func p_creation_func) { + return p_creation_func(); +} + +GD_PINVOKE_EXPORT Object *godotsharp_engine_get_singleton(const String *p_name) { + return Engine::get_singleton()->get_singleton_object(*p_name); +} + +GD_PINVOKE_EXPORT void godotsharp_ref_destroy(Ref<RefCounted> *p_instance) { + p_instance->~Ref(); +} + +GD_PINVOKE_EXPORT void godotsharp_string_name_new_from_string(StringName *r_dest, const String *p_name) { + memnew_placement(r_dest, StringName(*p_name)); +} + +GD_PINVOKE_EXPORT void godotsharp_node_path_new_from_string(NodePath *r_dest, const String *p_name) { + memnew_placement(r_dest, NodePath(*p_name)); +} + +GD_PINVOKE_EXPORT void godotsharp_string_name_as_string(String *r_dest, const StringName *p_name) { + memnew_placement(r_dest, String(p_name->operator String())); +} + +GD_PINVOKE_EXPORT void godotsharp_node_path_as_string(String *r_dest, const NodePath *p_np) { + memnew_placement(r_dest, String(p_np->operator String())); +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_packed_byte_array_new_mem_copy(const uint8_t *p_src, int32_t p_length) { + godot_packed_array ret; + memnew_placement(&ret, PackedByteArray); + PackedByteArray *array = reinterpret_cast<PackedByteArray *>(&ret); + array->resize(p_length); + uint8_t *dst = array->ptrw(); + memcpy(dst, p_src, p_length * sizeof(uint8_t)); + return ret; +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_packed_int32_array_new_mem_copy(const int32_t *p_src, int32_t p_length) { + godot_packed_array ret; + memnew_placement(&ret, PackedInt32Array); + PackedInt32Array *array = reinterpret_cast<PackedInt32Array *>(&ret); + array->resize(p_length); + int32_t *dst = array->ptrw(); + memcpy(dst, p_src, p_length * sizeof(int32_t)); + return ret; +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_packed_int64_array_new_mem_copy(const int64_t *p_src, int32_t p_length) { + godot_packed_array ret; + memnew_placement(&ret, PackedInt64Array); + PackedInt64Array *array = reinterpret_cast<PackedInt64Array *>(&ret); + array->resize(p_length); + int64_t *dst = array->ptrw(); + memcpy(dst, p_src, p_length * sizeof(int64_t)); + return ret; +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_packed_float32_array_new_mem_copy(const float *p_src, int32_t p_length) { + godot_packed_array ret; + memnew_placement(&ret, PackedFloat32Array); + PackedFloat32Array *array = reinterpret_cast<PackedFloat32Array *>(&ret); + array->resize(p_length); + float *dst = array->ptrw(); + memcpy(dst, p_src, p_length * sizeof(float)); + return ret; +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_packed_float64_array_new_mem_copy(const double *p_src, int32_t p_length) { + godot_packed_array ret; + memnew_placement(&ret, PackedFloat64Array); + PackedFloat64Array *array = reinterpret_cast<PackedFloat64Array *>(&ret); + array->resize(p_length); + double *dst = array->ptrw(); + memcpy(dst, p_src, p_length * sizeof(double)); + return ret; +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_packed_vector2_array_new_mem_copy(const Vector2 *p_src, int32_t p_length) { + godot_packed_array ret; + memnew_placement(&ret, PackedVector2Array); + PackedVector2Array *array = reinterpret_cast<PackedVector2Array *>(&ret); + array->resize(p_length); + Vector2 *dst = array->ptrw(); + memcpy(dst, p_src, p_length * sizeof(Vector2)); + return ret; +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_packed_vector3_array_new_mem_copy(const Vector3 *p_src, int32_t p_length) { + godot_packed_array ret; + memnew_placement(&ret, PackedVector3Array); + PackedVector3Array *array = reinterpret_cast<PackedVector3Array *>(&ret); + array->resize(p_length); + Vector3 *dst = array->ptrw(); + memcpy(dst, p_src, p_length * sizeof(Vector3)); + return ret; +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_packed_color_array_new_mem_copy(const Color *p_src, int32_t p_length) { + godot_packed_array ret; + memnew_placement(&ret, PackedColorArray); + PackedColorArray *array = reinterpret_cast<PackedColorArray *>(&ret); + array->resize(p_length); + Color *dst = array->ptrw(); + memcpy(dst, p_src, p_length * sizeof(Color)); + return ret; +} + +GD_PINVOKE_EXPORT void godotsharp_packed_string_array_add(PackedStringArray *r_dest, const String *p_element) { + r_dest->append(*p_element); +} + +GD_PINVOKE_EXPORT void godotsharp_callable_new_with_delegate(void *p_delegate_handle, Callable *r_callable) { + // TODO: Use pooling for ManagedCallable instances. + CallableCustom *managed_callable = memnew(ManagedCallable(p_delegate_handle)); + *r_callable = Callable(managed_callable); +} + +GD_PINVOKE_EXPORT bool godotsharp_callable_get_data_for_marshalling(const Callable *p_callable, + void **r_delegate_handle, Object **r_object, StringName *r_name) { + if (p_callable->is_custom()) { + CallableCustom *custom = p_callable->get_custom(); + CallableCustom::CompareEqualFunc compare_equal_func = custom->get_compare_equal_func(); + + if (compare_equal_func == ManagedCallable::compare_equal_func_ptr) { + ManagedCallable *managed_callable = static_cast<ManagedCallable *>(custom); + *r_delegate_handle = managed_callable->get_delegate(); + *r_object = nullptr; + *r_name = StringName(); + return true; + } else if (compare_equal_func == SignalAwaiterCallable::compare_equal_func_ptr) { + SignalAwaiterCallable *signal_awaiter_callable = static_cast<SignalAwaiterCallable *>(custom); + *r_delegate_handle = nullptr; + *r_object = ObjectDB::get_instance(signal_awaiter_callable->get_object()); + *r_name = signal_awaiter_callable->get_signal(); + return true; + } else if (compare_equal_func == EventSignalCallable::compare_equal_func_ptr) { + EventSignalCallable *event_signal_callable = static_cast<EventSignalCallable *>(custom); + *r_delegate_handle = nullptr; + *r_object = ObjectDB::get_instance(event_signal_callable->get_object()); + *r_name = event_signal_callable->get_signal(); + return true; + } + + // Some other CallableCustom. We only support ManagedCallable. + *r_delegate_handle = nullptr; + *r_object = nullptr; + *r_name = StringName(); + return false; + } else { + *r_delegate_handle = nullptr; + *r_object = ObjectDB::get_instance(p_callable->get_object_id()); + *r_name = p_callable->get_method(); + return true; + } +} + +// GDNative functions + +// gdnative.h + +GD_PINVOKE_EXPORT void godotsharp_method_bind_ptrcall(MethodBind *p_method_bind, Object *p_instance, const void **p_args, void *p_ret) { + p_method_bind->ptrcall(p_instance, p_args, p_ret); +} + +GD_PINVOKE_EXPORT godot_variant godotsharp_method_bind_call(MethodBind *p_method_bind, Object *p_instance, const godot_variant **p_args, const int p_arg_count, Callable::CallError *p_call_error) { + godot_variant ret; + memnew_placement(&ret, Variant()); + + Variant *ret_val = (Variant *)&ret; + + *ret_val = p_method_bind->call(p_instance, (const Variant **)p_args, p_arg_count, *p_call_error); + + return ret; +} + +// variant.h + +GD_PINVOKE_EXPORT void godotsharp_variant_new_string_name(godot_variant *r_dest, const StringName *p_s) { + memnew_placement(r_dest, Variant(*p_s)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_node_path(godot_variant *r_dest, const NodePath *p_np) { + memnew_placement(r_dest, Variant(*p_np)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_object(godot_variant *r_dest, const Object *p_obj) { + memnew_placement(r_dest, Variant(p_obj)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_transform2d(godot_variant *r_dest, const Transform2D *p_t2d) { + memnew_placement(r_dest, Variant(*p_t2d)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_vector4(godot_variant *r_dest, const Vector4 *p_vec4) { + memnew_placement(r_dest, Variant(*p_vec4)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_vector4i(godot_variant *r_dest, const Vector4i *p_vec4i) { + memnew_placement(r_dest, Variant(*p_vec4i)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_basis(godot_variant *r_dest, const Basis *p_basis) { + memnew_placement(r_dest, Variant(*p_basis)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_transform3d(godot_variant *r_dest, const Transform3D *p_trans) { + memnew_placement(r_dest, Variant(*p_trans)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_projection(godot_variant *r_dest, const Projection *p_proj) { + memnew_placement(r_dest, Variant(*p_proj)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_aabb(godot_variant *r_dest, const AABB *p_aabb) { + memnew_placement(r_dest, Variant(*p_aabb)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_dictionary(godot_variant *r_dest, const Dictionary *p_dict) { + memnew_placement(r_dest, Variant(*p_dict)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_array(godot_variant *r_dest, const Array *p_arr) { + memnew_placement(r_dest, Variant(*p_arr)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_byte_array(godot_variant *r_dest, const PackedByteArray *p_pba) { + memnew_placement(r_dest, Variant(*p_pba)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_int32_array(godot_variant *r_dest, const PackedInt32Array *p_pia) { + memnew_placement(r_dest, Variant(*p_pia)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_int64_array(godot_variant *r_dest, const PackedInt64Array *p_pia) { + memnew_placement(r_dest, Variant(*p_pia)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_float32_array(godot_variant *r_dest, const PackedFloat32Array *p_pra) { + memnew_placement(r_dest, Variant(*p_pra)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_float64_array(godot_variant *r_dest, const PackedFloat64Array *p_pra) { + memnew_placement(r_dest, Variant(*p_pra)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_string_array(godot_variant *r_dest, const PackedStringArray *p_psa) { + memnew_placement(r_dest, Variant(*p_psa)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_vector2_array(godot_variant *r_dest, const PackedVector2Array *p_pv2a) { + memnew_placement(r_dest, Variant(*p_pv2a)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_vector3_array(godot_variant *r_dest, const PackedVector3Array *p_pv3a) { + memnew_placement(r_dest, Variant(*p_pv3a)); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_color_array(godot_variant *r_dest, const PackedColorArray *p_pca) { + memnew_placement(r_dest, Variant(*p_pca)); +} + +GD_PINVOKE_EXPORT bool godotsharp_variant_as_bool(const Variant *p_self) { + return p_self->operator bool(); +} + +GD_PINVOKE_EXPORT int64_t godotsharp_variant_as_int(const Variant *p_self) { + return p_self->operator int64_t(); +} + +GD_PINVOKE_EXPORT double godotsharp_variant_as_float(const Variant *p_self) { + return p_self->operator double(); +} + +GD_PINVOKE_EXPORT godot_string godotsharp_variant_as_string(const Variant *p_self) { + godot_string raw_dest; + String *dest = (String *)&raw_dest; + memnew_placement(dest, String(p_self->operator String())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_vector2 godotsharp_variant_as_vector2(const Variant *p_self) { + godot_vector2 raw_dest; + Vector2 *dest = (Vector2 *)&raw_dest; + memnew_placement(dest, Vector2(p_self->operator Vector2())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_vector2i godotsharp_variant_as_vector2i(const Variant *p_self) { + godot_vector2i raw_dest; + Vector2i *dest = (Vector2i *)&raw_dest; + memnew_placement(dest, Vector2i(p_self->operator Vector2i())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_rect2 godotsharp_variant_as_rect2(const Variant *p_self) { + godot_rect2 raw_dest; + Rect2 *dest = (Rect2 *)&raw_dest; + memnew_placement(dest, Rect2(p_self->operator Rect2())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_rect2i godotsharp_variant_as_rect2i(const Variant *p_self) { + godot_rect2i raw_dest; + Rect2i *dest = (Rect2i *)&raw_dest; + memnew_placement(dest, Rect2i(p_self->operator Rect2i())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_vector3 godotsharp_variant_as_vector3(const Variant *p_self) { + godot_vector3 raw_dest; + Vector3 *dest = (Vector3 *)&raw_dest; + memnew_placement(dest, Vector3(p_self->operator Vector3())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_vector3i godotsharp_variant_as_vector3i(const Variant *p_self) { + godot_vector3i raw_dest; + Vector3i *dest = (Vector3i *)&raw_dest; + memnew_placement(dest, Vector3i(p_self->operator Vector3i())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_transform2d godotsharp_variant_as_transform2d(const Variant *p_self) { + godot_transform2d raw_dest; + Transform2D *dest = (Transform2D *)&raw_dest; + memnew_placement(dest, Transform2D(p_self->operator Transform2D())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_vector4 godotsharp_variant_as_vector4(const Variant *p_self) { + godot_vector4 raw_dest; + Vector4 *dest = (Vector4 *)&raw_dest; + memnew_placement(dest, Vector4(p_self->operator Vector4())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_vector4i godotsharp_variant_as_vector4i(const Variant *p_self) { + godot_vector4i raw_dest; + Vector4i *dest = (Vector4i *)&raw_dest; + memnew_placement(dest, Vector4i(p_self->operator Vector4i())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_plane godotsharp_variant_as_plane(const Variant *p_self) { + godot_plane raw_dest; + Plane *dest = (Plane *)&raw_dest; + memnew_placement(dest, Plane(p_self->operator Plane())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_quaternion godotsharp_variant_as_quaternion(const Variant *p_self) { + godot_quaternion raw_dest; + Quaternion *dest = (Quaternion *)&raw_dest; + memnew_placement(dest, Quaternion(p_self->operator Quaternion())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_aabb godotsharp_variant_as_aabb(const Variant *p_self) { + godot_aabb raw_dest; + AABB *dest = (AABB *)&raw_dest; + memnew_placement(dest, AABB(p_self->operator ::AABB())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_basis godotsharp_variant_as_basis(const Variant *p_self) { + godot_basis raw_dest; + Basis *dest = (Basis *)&raw_dest; + memnew_placement(dest, Basis(p_self->operator Basis())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_transform3d godotsharp_variant_as_transform3d(const Variant *p_self) { + godot_transform3d raw_dest; + Transform3D *dest = (Transform3D *)&raw_dest; + memnew_placement(dest, Transform3D(p_self->operator Transform3D())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_projection godotsharp_variant_as_projection(const Variant *p_self) { + godot_projection raw_dest; + Projection *dest = (Projection *)&raw_dest; + memnew_placement(dest, Projection(p_self->operator Projection())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_color godotsharp_variant_as_color(const Variant *p_self) { + godot_color raw_dest; + Color *dest = (Color *)&raw_dest; + memnew_placement(dest, Color(p_self->operator Color())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_string_name godotsharp_variant_as_string_name(const Variant *p_self) { + godot_string_name raw_dest; + StringName *dest = (StringName *)&raw_dest; + memnew_placement(dest, StringName(p_self->operator StringName())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_node_path godotsharp_variant_as_node_path(const Variant *p_self) { + godot_node_path raw_dest; + NodePath *dest = (NodePath *)&raw_dest; + memnew_placement(dest, NodePath(p_self->operator NodePath())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_rid godotsharp_variant_as_rid(const Variant *p_self) { + godot_rid raw_dest; + RID *dest = (RID *)&raw_dest; + memnew_placement(dest, RID(p_self->operator ::RID())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_callable godotsharp_variant_as_callable(const Variant *p_self) { + godot_callable raw_dest; + Callable *dest = (Callable *)&raw_dest; + memnew_placement(dest, Callable(p_self->operator Callable())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_signal godotsharp_variant_as_signal(const Variant *p_self) { + godot_signal raw_dest; + Signal *dest = (Signal *)&raw_dest; + memnew_placement(dest, Signal(p_self->operator Signal())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_dictionary godotsharp_variant_as_dictionary(const Variant *p_self) { + godot_dictionary raw_dest; + Dictionary *dest = (Dictionary *)&raw_dest; + memnew_placement(dest, Dictionary(p_self->operator Dictionary())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_array godotsharp_variant_as_array(const Variant *p_self) { + godot_array raw_dest; + Array *dest = (Array *)&raw_dest; + memnew_placement(dest, Array(p_self->operator Array())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_byte_array(const Variant *p_self) { + godot_packed_array raw_dest; + PackedByteArray *dest = (PackedByteArray *)&raw_dest; + memnew_placement(dest, PackedByteArray(p_self->operator PackedByteArray())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_int32_array(const Variant *p_self) { + godot_packed_array raw_dest; + PackedInt32Array *dest = (PackedInt32Array *)&raw_dest; + memnew_placement(dest, PackedInt32Array(p_self->operator PackedInt32Array())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_int64_array(const Variant *p_self) { + godot_packed_array raw_dest; + PackedInt64Array *dest = (PackedInt64Array *)&raw_dest; + memnew_placement(dest, PackedInt64Array(p_self->operator PackedInt64Array())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_float32_array(const Variant *p_self) { + godot_packed_array raw_dest; + PackedFloat32Array *dest = (PackedFloat32Array *)&raw_dest; + memnew_placement(dest, PackedFloat32Array(p_self->operator PackedFloat32Array())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_float64_array(const Variant *p_self) { + godot_packed_array raw_dest; + PackedFloat64Array *dest = (PackedFloat64Array *)&raw_dest; + memnew_placement(dest, PackedFloat64Array(p_self->operator PackedFloat64Array())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_string_array(const Variant *p_self) { + godot_packed_array raw_dest; + PackedStringArray *dest = (PackedStringArray *)&raw_dest; + memnew_placement(dest, PackedStringArray(p_self->operator PackedStringArray())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_vector2_array(const Variant *p_self) { + godot_packed_array raw_dest; + PackedVector2Array *dest = (PackedVector2Array *)&raw_dest; + memnew_placement(dest, PackedVector2Array(p_self->operator PackedVector2Array())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_vector3_array(const Variant *p_self) { + godot_packed_array raw_dest; + PackedVector3Array *dest = (PackedVector3Array *)&raw_dest; + memnew_placement(dest, PackedVector3Array(p_self->operator PackedVector3Array())); + return raw_dest; +} + +GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_color_array(const Variant *p_self) { + godot_packed_array raw_dest; + PackedColorArray *dest = (PackedColorArray *)&raw_dest; + memnew_placement(dest, PackedColorArray(p_self->operator PackedColorArray())); + return raw_dest; +} + +// string.h + +GD_PINVOKE_EXPORT void godotsharp_string_new_with_utf16_chars(String *r_dest, const char16_t *p_contents) { + memnew_placement(r_dest, String()); + r_dest->parse_utf16(p_contents); +} + +// string_name.h + +GD_PINVOKE_EXPORT void godotsharp_string_name_new_copy(StringName *r_dest, const StringName *p_src) { + memnew_placement(r_dest, StringName(*p_src)); +} + +// node_path.h + +GD_PINVOKE_EXPORT void godotsharp_node_path_new_copy(NodePath *r_dest, const NodePath *p_src) { + memnew_placement(r_dest, NodePath(*p_src)); +} + +// array.h + +GD_PINVOKE_EXPORT void godotsharp_array_new_copy(Array *r_dest, const Array *p_src) { + memnew_placement(r_dest, Array(*p_src)); +} + +// dictionary.h + +GD_PINVOKE_EXPORT void godotsharp_dictionary_new_copy(Dictionary *r_dest, const Dictionary *p_src) { + memnew_placement(r_dest, Dictionary(*p_src)); +} + +// destroy functions + +GD_PINVOKE_EXPORT void godotsharp_packed_byte_array_destroy(PackedByteArray *p_self) { + p_self->~PackedByteArray(); +} + +GD_PINVOKE_EXPORT void godotsharp_packed_int32_array_destroy(PackedInt32Array *p_self) { + p_self->~PackedInt32Array(); +} + +GD_PINVOKE_EXPORT void godotsharp_packed_int64_array_destroy(PackedInt64Array *p_self) { + p_self->~PackedInt64Array(); +} + +GD_PINVOKE_EXPORT void godotsharp_packed_float32_array_destroy(PackedFloat32Array *p_self) { + p_self->~PackedFloat32Array(); +} + +GD_PINVOKE_EXPORT void godotsharp_packed_float64_array_destroy(PackedFloat64Array *p_self) { + p_self->~PackedFloat64Array(); +} + +GD_PINVOKE_EXPORT void godotsharp_packed_string_array_destroy(PackedStringArray *p_self) { + p_self->~PackedStringArray(); +} + +GD_PINVOKE_EXPORT void godotsharp_packed_vector2_array_destroy(PackedVector2Array *p_self) { + p_self->~PackedVector2Array(); +} + +GD_PINVOKE_EXPORT void godotsharp_packed_vector3_array_destroy(PackedVector3Array *p_self) { + p_self->~PackedVector3Array(); +} + +GD_PINVOKE_EXPORT void godotsharp_packed_color_array_destroy(PackedColorArray *p_self) { + p_self->~PackedColorArray(); +} + +GD_PINVOKE_EXPORT void godotsharp_variant_destroy(Variant *p_self) { + p_self->~Variant(); +} + +GD_PINVOKE_EXPORT void godotsharp_string_destroy(String *p_self) { + p_self->~String(); +} + +GD_PINVOKE_EXPORT void godotsharp_string_name_destroy(StringName *p_self) { + p_self->~StringName(); +} + +GD_PINVOKE_EXPORT void godotsharp_node_path_destroy(NodePath *p_self) { + p_self->~NodePath(); +} + +GD_PINVOKE_EXPORT void godotsharp_signal_destroy(Signal *p_self) { + p_self->~Signal(); +} + +GD_PINVOKE_EXPORT void godotsharp_callable_destroy(Callable *p_self) { + p_self->~Callable(); +} + +GD_PINVOKE_EXPORT void godotsharp_array_destroy(Array *p_self) { + p_self->~Array(); +} + +GD_PINVOKE_EXPORT void godotsharp_dictionary_destroy(Dictionary *p_self) { + p_self->~Dictionary(); +} + +#ifdef __cplusplus +} +#endif + +// We need this to prevent the functions from being stripped. +void *godotsharp_pinvoke_funcs[101] = { + (void *)godotsharp_method_bind_get_method, + (void *)godotsharp_get_class_constructor, + (void *)godotsharp_invoke_class_constructor, + (void *)godotsharp_engine_get_singleton, + (void *)godotsharp_ref_destroy, + (void *)godotsharp_string_name_new_from_string, + (void *)godotsharp_node_path_new_from_string, + (void *)godotsharp_string_name_as_string, + (void *)godotsharp_node_path_as_string, + (void *)godotsharp_packed_byte_array_new_mem_copy, + (void *)godotsharp_packed_int32_array_new_mem_copy, + (void *)godotsharp_packed_int64_array_new_mem_copy, + (void *)godotsharp_packed_float32_array_new_mem_copy, + (void *)godotsharp_packed_float64_array_new_mem_copy, + (void *)godotsharp_packed_vector2_array_new_mem_copy, + (void *)godotsharp_packed_vector3_array_new_mem_copy, + (void *)godotsharp_packed_color_array_new_mem_copy, + (void *)godotsharp_packed_string_array_add, + (void *)godotsharp_callable_new_with_delegate, + (void *)godotsharp_callable_get_data_for_marshalling, + (void *)godotsharp_method_bind_ptrcall, + (void *)godotsharp_method_bind_call, + (void *)godotsharp_variant_new_string_name, + (void *)godotsharp_variant_new_node_path, + (void *)godotsharp_variant_new_object, + (void *)godotsharp_variant_new_transform2d, + (void *)godotsharp_variant_new_vector4, + (void *)godotsharp_variant_new_vector4i, + (void *)godotsharp_variant_new_basis, + (void *)godotsharp_variant_new_transform3d, + (void *)godotsharp_variant_new_projection, + (void *)godotsharp_variant_new_aabb, + (void *)godotsharp_variant_new_dictionary, + (void *)godotsharp_variant_new_array, + (void *)godotsharp_variant_new_packed_byte_array, + (void *)godotsharp_variant_new_packed_int32_array, + (void *)godotsharp_variant_new_packed_int64_array, + (void *)godotsharp_variant_new_packed_float32_array, + (void *)godotsharp_variant_new_packed_float64_array, + (void *)godotsharp_variant_new_packed_string_array, + (void *)godotsharp_variant_new_packed_vector2_array, + (void *)godotsharp_variant_new_packed_vector3_array, + (void *)godotsharp_variant_new_packed_color_array, + (void *)godotsharp_variant_as_bool, + (void *)godotsharp_variant_as_int, + (void *)godotsharp_variant_as_float, + (void *)godotsharp_variant_as_string, + (void *)godotsharp_variant_as_vector2, + (void *)godotsharp_variant_as_vector2i, + (void *)godotsharp_variant_as_rect2, + (void *)godotsharp_variant_as_rect2i, + (void *)godotsharp_variant_as_vector3, + (void *)godotsharp_variant_as_vector3i, + (void *)godotsharp_variant_as_transform2d, + (void *)godotsharp_variant_as_vector4, + (void *)godotsharp_variant_as_vector4i, + (void *)godotsharp_variant_as_plane, + (void *)godotsharp_variant_as_quaternion, + (void *)godotsharp_variant_as_aabb, + (void *)godotsharp_variant_as_basis, + (void *)godotsharp_variant_as_transform3d, + (void *)godotsharp_variant_as_projection, + (void *)godotsharp_variant_as_color, + (void *)godotsharp_variant_as_string_name, + (void *)godotsharp_variant_as_node_path, + (void *)godotsharp_variant_as_rid, + (void *)godotsharp_variant_as_callable, + (void *)godotsharp_variant_as_signal, + (void *)godotsharp_variant_as_dictionary, + (void *)godotsharp_variant_as_array, + (void *)godotsharp_variant_as_packed_byte_array, + (void *)godotsharp_variant_as_packed_int32_array, + (void *)godotsharp_variant_as_packed_int64_array, + (void *)godotsharp_variant_as_packed_float32_array, + (void *)godotsharp_variant_as_packed_float64_array, + (void *)godotsharp_variant_as_packed_string_array, + (void *)godotsharp_variant_as_packed_vector2_array, + (void *)godotsharp_variant_as_packed_vector3_array, + (void *)godotsharp_variant_as_packed_color_array, + (void *)godotsharp_string_new_with_utf16_chars, + (void *)godotsharp_string_name_new_copy, + (void *)godotsharp_node_path_new_copy, + (void *)godotsharp_array_new_copy, + (void *)godotsharp_dictionary_new_copy, + (void *)godotsharp_packed_byte_array_destroy, + (void *)godotsharp_packed_int32_array_destroy, + (void *)godotsharp_packed_int64_array_destroy, + (void *)godotsharp_packed_float32_array_destroy, + (void *)godotsharp_packed_float64_array_destroy, + (void *)godotsharp_packed_string_array_destroy, + (void *)godotsharp_packed_vector2_array_destroy, + (void *)godotsharp_packed_vector3_array_destroy, + (void *)godotsharp_packed_color_array_destroy, + (void *)godotsharp_variant_destroy, + (void *)godotsharp_string_destroy, + (void *)godotsharp_string_name_destroy, + (void *)godotsharp_node_path_destroy, + (void *)godotsharp_signal_destroy, + (void *)godotsharp_callable_destroy, + (void *)godotsharp_array_destroy, + (void *)godotsharp_dictionary_destroy +}; diff --git a/modules/mono/glue/scene_tree_glue.cpp b/modules/mono/glue/scene_tree_glue.cpp index c60e7c4869..55a46ad368 100644 --- a/modules/mono/glue/scene_tree_glue.cpp +++ b/modules/mono/glue/scene_tree_glue.cpp @@ -28,8 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef MONO_GLUE_ENABLED - #include "core/object/class_db.h" #include "core/string/string_name.h" #include "core/variant/array.h" @@ -40,9 +38,10 @@ #include "../mono_gd/gd_mono_marshal.h" #include "../mono_gd/gd_mono_utils.h" -Array *godot_icall_SceneTree_get_nodes_in_group_Generic(SceneTree *ptr, StringName *group, MonoReflectionType *refltype) { +void godot_icall_SceneTree_get_nodes_in_group_Generic(SceneTree *ptr, StringName *group, MonoReflectionType *refltype, Array *r_dest) { + memnew_placement(r_dest, Array); + List<Node *> nodes; - Array ret; // Retrieve all the nodes in the group ptr->get_nodes_in_group(*group, &nodes); @@ -58,7 +57,7 @@ Array *godot_icall_SceneTree_get_nodes_in_group_Generic(SceneTree *ptr, StringNa StringName native_class_name = GDMonoUtils::get_native_godot_class_name(klass); for (int i = 0; i < nodes.size(); ++i) { if (ClassDB::is_parent_class(nodes[i]->get_class(), native_class_name)) { - ret.push_back(nodes[i]); + r_dest->push_back(nodes[i]); } } } else { @@ -69,18 +68,14 @@ Array *godot_icall_SceneTree_get_nodes_in_group_Generic(SceneTree *ptr, StringNa if (si != nullptr) { MonoObject *obj = si->get_mono_object(); if (obj != nullptr && mono_object_get_class(obj) == mono_class) { - ret.push_back(nodes[i]); + r_dest->push_back(nodes[i]); } } } } } - - return memnew(Array(ret)); } void godot_register_scene_tree_icalls() { GDMonoUtils::add_internal_call("Godot.SceneTree::godot_icall_SceneTree_get_nodes_in_group_Generic", godot_icall_SceneTree_get_nodes_in_group_Generic); } - -#endif // MONO_GLUE_ENABLED diff --git a/modules/mono/glue/string_glue.cpp b/modules/mono/glue/string_glue.cpp index fc6b13ceb3..fe1c0b5f8c 100644 --- a/modules/mono/glue/string_glue.cpp +++ b/modules/mono/glue/string_glue.cpp @@ -28,8 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef MONO_GLUE_ENABLED - #include "core/string/ustring.h" #include "core/templates/vector.h" #include "core/variant/variant.h" @@ -81,5 +79,3 @@ void godot_register_string_icalls() { GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_text", godot_icall_String_sha256_text); GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_simplify_path", godot_icall_String_simplify_path); } - -#endif // MONO_GLUE_ENABLED diff --git a/modules/mono/glue/string_name_glue.cpp b/modules/mono/glue/string_name_glue.cpp deleted file mode 100644 index 46d15316ba..0000000000 --- a/modules/mono/glue/string_name_glue.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************/ -/* string_name_glue.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifdef MONO_GLUE_ENABLED - -#include "core/string/string_name.h" -#include "core/string/ustring.h" - -#include "../mono_gd/gd_mono_marshal.h" - -StringName *godot_icall_StringName_Ctor(MonoString *p_path) { - return memnew(StringName(GDMonoMarshal::mono_string_to_godot(p_path))); -} - -void godot_icall_StringName_Dtor(StringName *p_ptr) { - ERR_FAIL_NULL(p_ptr); - memdelete(p_ptr); -} - -MonoString *godot_icall_StringName_operator_String(StringName *p_np) { - return GDMonoMarshal::mono_string_from_godot(p_np->operator String()); -} - -MonoBoolean godot_icall_StringName_is_empty(StringName *p_ptr) { - return (MonoBoolean)(*p_ptr == StringName()); -} - -void godot_register_string_name_icalls() { - GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_Ctor", godot_icall_StringName_Ctor); - GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_Dtor", godot_icall_StringName_Dtor); - GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_operator_String", godot_icall_StringName_operator_String); - GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_is_empty", godot_icall_StringName_is_empty); -} - -#endif // MONO_GLUE_ENABLED |