|
@@ -1,5 +1,7 @@
|
|
|
using System;
|
|
|
using System.Runtime.InteropServices;
|
|
|
+using Godot.Collections;
|
|
|
+using Array = System.Array;
|
|
|
|
|
|
// ReSharper disable InconsistentNaming
|
|
|
|
|
@@ -148,6 +150,15 @@ namespace Godot.NativeInterop
|
|
|
{
|
|
|
if (typeof(Godot.Object).IsAssignableFrom(type))
|
|
|
return Variant.Type.Object;
|
|
|
+
|
|
|
+ // We use `IsAssignableFrom` with our helper interfaces to detect generic Godot collections
|
|
|
+ // because `GetGenericTypeDefinition` is not supported in NativeAOT reflection-free mode.
|
|
|
+
|
|
|
+ if (typeof(IGenericGodotDictionary).IsAssignableFrom(type))
|
|
|
+ return Variant.Type.Dictionary;
|
|
|
+
|
|
|
+ if (typeof(IGenericGodotArray).IsAssignableFrom(type))
|
|
|
+ return Variant.Type.Array;
|
|
|
}
|
|
|
else if (type == typeof(Variant))
|
|
|
{
|
|
@@ -183,407 +194,6 @@ namespace Godot.NativeInterop
|
|
|
return Variant.Type.Nil;
|
|
|
}
|
|
|
|
|
|
- /* TODO: Reflection and type checking each time is slow. This will be replaced with source generators. */
|
|
|
- public static godot_variant ConvertManagedObjectToVariant(object? p_obj)
|
|
|
- {
|
|
|
- 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 short @int16:
|
|
|
- return VariantUtils.CreateFromInt(@int16);
|
|
|
- case int @int32:
|
|
|
- return VariantUtils.CreateFromInt(@int32);
|
|
|
- case long @int64:
|
|
|
- return VariantUtils.CreateFromInt(@int64);
|
|
|
- case byte @uint8:
|
|
|
- return VariantUtils.CreateFromInt(@uint8);
|
|
|
- case ushort @uint16:
|
|
|
- return VariantUtils.CreateFromInt(@uint16);
|
|
|
- case uint @uint32:
|
|
|
- return VariantUtils.CreateFromInt(@uint32);
|
|
|
- case ulong @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.CreateFromCallable(@callable);
|
|
|
- case SignalInfo @signalInfo:
|
|
|
- return VariantUtils.CreateFromSignalInfo(@signalInfo);
|
|
|
- case Enum @enum:
|
|
|
- return VariantUtils.CreateFromInt(Convert.ToInt64(@enum));
|
|
|
- case string @string:
|
|
|
- return VariantUtils.CreateFromString(@string);
|
|
|
- case byte[] byteArray:
|
|
|
- return VariantUtils.CreateFromPackedByteArray(byteArray);
|
|
|
- case int[] int32Array:
|
|
|
- return VariantUtils.CreateFromPackedInt32Array(int32Array);
|
|
|
- case long[] int64Array:
|
|
|
- return VariantUtils.CreateFromPackedInt64Array(int64Array);
|
|
|
- case float[] floatArray:
|
|
|
- return VariantUtils.CreateFromPackedFloat32Array(floatArray);
|
|
|
- case double[] doubleArray:
|
|
|
- return VariantUtils.CreateFromPackedFloat64Array(doubleArray);
|
|
|
- case string[] stringArray:
|
|
|
- return VariantUtils.CreateFromPackedStringArray(stringArray);
|
|
|
- case Vector2[] vector2Array:
|
|
|
- return VariantUtils.CreateFromPackedVector2Array(vector2Array);
|
|
|
- case Vector3[] vector3Array:
|
|
|
- return VariantUtils.CreateFromPackedVector3Array(vector3Array);
|
|
|
- case Color[] colorArray:
|
|
|
- return VariantUtils.CreateFromPackedColorArray(colorArray);
|
|
|
- case StringName[] stringNameArray:
|
|
|
- return VariantUtils.CreateFromSystemArrayOfStringName(stringNameArray);
|
|
|
- case NodePath[] nodePathArray:
|
|
|
- return VariantUtils.CreateFromSystemArrayOfNodePath(nodePathArray);
|
|
|
- case RID[] ridArray:
|
|
|
- return VariantUtils.CreateFromSystemArrayOfRID(ridArray);
|
|
|
- case Godot.Object[] godotObjectArray:
|
|
|
- return VariantUtils.CreateFromSystemArrayOfGodotObject(godotObjectArray);
|
|
|
- case Godot.Object godotObject:
|
|
|
- return VariantUtils.CreateFromGodotObject(godotObject);
|
|
|
- case StringName stringName:
|
|
|
- return VariantUtils.CreateFromStringName(stringName);
|
|
|
- case NodePath nodePath:
|
|
|
- return VariantUtils.CreateFromNodePath(nodePath);
|
|
|
- case RID rid:
|
|
|
- return VariantUtils.CreateFromRID(rid);
|
|
|
- case Collections.Dictionary godotDictionary:
|
|
|
- return VariantUtils.CreateFromDictionary(godotDictionary);
|
|
|
- case Collections.Array godotArray:
|
|
|
- return VariantUtils.CreateFromArray(godotArray);
|
|
|
- case Collections.IGenericGodotDictionary godotDictionary:
|
|
|
- return VariantUtils.CreateFromDictionary(godotDictionary.UnderlyingDictionary);
|
|
|
- case Collections.IGenericGodotArray godotArray:
|
|
|
- return VariantUtils.CreateFromArray(godotArray.UnderlyingArray);
|
|
|
- case Variant variant:
|
|
|
- return NativeFuncs.godotsharp_variant_new_copy((godot_variant)variant.NativeVar);
|
|
|
- }
|
|
|
-
|
|
|
- GD.PushError("Attempted to convert an unmarshallable managed type to Variant. Name: '" +
|
|
|
- p_obj.GetType().FullName + ".");
|
|
|
- return new godot_variant();
|
|
|
- }
|
|
|
-
|
|
|
- public static object? ConvertVariantToManagedObjectOfType(in 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 VariantUtils.ConvertToStringObject(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))
|
|
|
- return VariantUtils.ConvertToCallableManaged(p_var);
|
|
|
-
|
|
|
- if (type == typeof(SignalInfo))
|
|
|
- return VariantUtils.ConvertToSignalInfo(p_var);
|
|
|
-
|
|
|
- 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 ConvertVariantToSystemArrayOfType(p_var, type);
|
|
|
- }
|
|
|
- else if (type.IsGenericType)
|
|
|
- {
|
|
|
- if (typeof(Godot.Object).IsAssignableFrom(type))
|
|
|
- {
|
|
|
- var godotObject = VariantUtils.ConvertToGodotObject(p_var);
|
|
|
-
|
|
|
- if (!type.IsInstanceOfType(godotObject))
|
|
|
- {
|
|
|
- GD.PushError("Invalid cast when marshaling Godot.Object type." +
|
|
|
- $" `{godotObject.GetType()}` is not assignable to `{type.FullName}`.");
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- return godotObject;
|
|
|
- }
|
|
|
-
|
|
|
- return null;
|
|
|
- }
|
|
|
- else if (type == typeof(Variant))
|
|
|
- {
|
|
|
- return Variant.CreateCopyingBorrowed(p_var);
|
|
|
- }
|
|
|
-
|
|
|
- if (ConvertVariantToManagedObjectOfClass(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 object? ConvertVariantToSystemArrayOfType(in godot_variant p_var, Type type)
|
|
|
- {
|
|
|
- if (type == typeof(byte[]))
|
|
|
- return VariantUtils.ConvertAsPackedByteArrayToSystemArray(p_var);
|
|
|
-
|
|
|
- if (type == typeof(int[]))
|
|
|
- return VariantUtils.ConvertAsPackedInt32ArrayToSystemArray(p_var);
|
|
|
-
|
|
|
- if (type == typeof(long[]))
|
|
|
- return VariantUtils.ConvertAsPackedInt64ArrayToSystemArray(p_var);
|
|
|
-
|
|
|
- if (type == typeof(float[]))
|
|
|
- return VariantUtils.ConvertAsPackedFloat32ArrayToSystemArray(p_var);
|
|
|
-
|
|
|
- if (type == typeof(double[]))
|
|
|
- return VariantUtils.ConvertAsPackedFloat64ArrayToSystemArray(p_var);
|
|
|
-
|
|
|
- if (type == typeof(string[]))
|
|
|
- return VariantUtils.ConvertAsPackedStringArrayToSystemArray(p_var);
|
|
|
-
|
|
|
- if (type == typeof(Vector2[]))
|
|
|
- return VariantUtils.ConvertAsPackedVector2ArrayToSystemArray(p_var);
|
|
|
-
|
|
|
- if (type == typeof(Vector3[]))
|
|
|
- return VariantUtils.ConvertAsPackedVector3ArrayToSystemArray(p_var);
|
|
|
-
|
|
|
- if (type == typeof(Color[]))
|
|
|
- return VariantUtils.ConvertAsPackedColorArrayToSystemArray(p_var);
|
|
|
-
|
|
|
- if (type == typeof(StringName[]))
|
|
|
- return VariantUtils.ConvertToSystemArrayOfStringName(p_var);
|
|
|
-
|
|
|
- if (type == typeof(NodePath[]))
|
|
|
- return VariantUtils.ConvertToSystemArrayOfNodePath(p_var);
|
|
|
-
|
|
|
- if (type == typeof(RID[]))
|
|
|
- return VariantUtils.ConvertToSystemArrayOfRID(p_var);
|
|
|
-
|
|
|
- if (typeof(Godot.Object[]).IsAssignableFrom(type))
|
|
|
- return VariantUtils.ConvertToSystemArrayOfGodotObject(p_var, type);
|
|
|
-
|
|
|
- GD.PushError("Attempted to convert Variant to array of unsupported element type. Name: " +
|
|
|
- type.GetElementType()!.FullName + ".");
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- private static bool ConvertVariantToManagedObjectOfClass(in godot_variant p_var, Type type,
|
|
|
- out object? res)
|
|
|
- {
|
|
|
- if (typeof(Godot.Object).IsAssignableFrom(type))
|
|
|
- {
|
|
|
- if (p_var.Type == Variant.Type.Nil)
|
|
|
- {
|
|
|
- res = null;
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- if (p_var.Type != Variant.Type.Object)
|
|
|
- {
|
|
|
- GD.PushError("Invalid cast when marshaling Godot.Object type." +
|
|
|
- $" Variant type is `{p_var.Type}`; expected `{p_var.Object}`.");
|
|
|
- res = null;
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- var godotObjectPtr = VariantUtils.ConvertToGodotObjectPtr(p_var);
|
|
|
-
|
|
|
- if (godotObjectPtr == IntPtr.Zero)
|
|
|
- {
|
|
|
- res = null;
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- var godotObject = InteropUtils.UnmanagedGetManaged(godotObjectPtr);
|
|
|
-
|
|
|
- if (!type.IsInstanceOfType(godotObject))
|
|
|
- {
|
|
|
- GD.PushError("Invalid cast when marshaling Godot.Object type." +
|
|
|
- $" `{godotObject.GetType()}` is not assignable to `{type.FullName}`.");
|
|
|
- res = null;
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- res = godotObject;
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- if (typeof(StringName) == type)
|
|
|
- {
|
|
|
- res = VariantUtils.ConvertToStringNameObject(p_var);
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- if (typeof(NodePath) == type)
|
|
|
- {
|
|
|
- res = VariantUtils.ConvertToNodePathObject(p_var);
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- if (typeof(RID) == type)
|
|
|
- {
|
|
|
- res = VariantUtils.ConvertToRID(p_var);
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- if (typeof(Collections.Dictionary) == type)
|
|
|
- {
|
|
|
- res = VariantUtils.ConvertToDictionaryObject(p_var);
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- if (typeof(Collections.Array) == type)
|
|
|
- {
|
|
|
- res = VariantUtils.ConvertToArrayObject(p_var);
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- res = null;
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
// String
|
|
|
|
|
|
public static unsafe godot_string ConvertStringToNative(string? p_mono_string)
|