C#: Replace most conversions between Variant and System.Object
This commit replaces most usages of `ConvertManagedObjectToVariant` and `ConvertVariantToManagedObjectOfType`, by using the `Godot.Variant` struct instead of `System.Object`. The most notable change is to the `GetGodotPropertyDefaultValues` method that's generated for scripts. The dictionary it returns now stores `Godot.Variant` values. Remaining usages are: - The `DelegateUtils` class, for the serialization of closure display classes during assembly reloading by the editor. These display classes are compiler generated classes to store values captured by a closure. Since it's generated by the compiler, the only way we have to access the fields is through reflection. This leads to using `System.Object`. - Converting parameters when invoking constructors from the engine. This will be replaced with source generators in the future. - Legacy support for old `GetGodotPropertyDefaultValues` return values. We need to keep supporting the old version of this generated method for some time. Otherwise, if loading a project built with the previous version, it could lead to the loss of exported property values. Ideally, we should remove this legacy support before a stable release.
This commit is contained in:
parent
3afeb28560
commit
f86c6b6ac4
@ -368,7 +368,7 @@ namespace Godot.SourceGenerators
|
||||
source.Append(VariantUtils, ".ConvertToSignalInfo(", inputExpr, ")"),
|
||||
MarshalType.Enum =>
|
||||
source.Append("(", typeSymbol.FullQualifiedNameIncludeGlobal(),
|
||||
")", VariantUtils, ".ConvertToInt32(", inputExpr, ")"),
|
||||
")", VariantUtils, ".ConvertToInt64(", inputExpr, ")"),
|
||||
MarshalType.ByteArray =>
|
||||
source.Append(VariantUtils, ".ConvertAsPackedByteArrayToSystemArray(", inputExpr, ")"),
|
||||
MarshalType.Int32Array =>
|
||||
@ -491,7 +491,7 @@ namespace Godot.SourceGenerators
|
||||
MarshalType.SignalInfo =>
|
||||
source.Append(VariantUtils, ".CreateFromSignalInfo(", inputExpr, ")"),
|
||||
MarshalType.Enum =>
|
||||
source.Append(VariantUtils, ".CreateFromInt((int)", inputExpr, ")"),
|
||||
source.Append(VariantUtils, ".CreateFromInt((long)", inputExpr, ")"),
|
||||
MarshalType.ByteArray =>
|
||||
source.Append(VariantUtils, ".CreateFromPackedByteArray(", inputExpr, ")"),
|
||||
MarshalType.Int32Array =>
|
||||
|
@ -174,7 +174,8 @@ namespace Godot.SourceGenerators
|
||||
}
|
||||
else
|
||||
{
|
||||
var propertyGet = propertyDeclarationSyntax.AccessorList?.Accessors.Where(a => a.Keyword.IsKind(SyntaxKind.GetKeyword)).FirstOrDefault();
|
||||
var propertyGet = propertyDeclarationSyntax.AccessorList?.Accessors
|
||||
.Where(a => a.Keyword.IsKind(SyntaxKind.GetKeyword)).FirstOrDefault();
|
||||
if (propertyGet != null)
|
||||
{
|
||||
if (propertyGet.ExpressionBody != null)
|
||||
@ -200,7 +201,8 @@ namespace Godot.SourceGenerators
|
||||
{
|
||||
var returns = propertyGet.DescendantNodes().OfType<ReturnStatementSyntax>();
|
||||
if (returns.Count() == 1)
|
||||
{// Generate only single return
|
||||
{
|
||||
// Generate only single return
|
||||
var returnStatementSyntax = returns.Single();
|
||||
if (returnStatementSyntax.Expression is IdentifierNameSyntax identifierNameSyntax)
|
||||
{
|
||||
@ -277,7 +279,8 @@ namespace Godot.SourceGenerators
|
||||
{
|
||||
source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
|
||||
|
||||
string dictionaryType = "System.Collections.Generic.Dictionary<Godot.StringName, object>";
|
||||
string dictionaryType =
|
||||
"global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant>";
|
||||
|
||||
source.Append("#if TOOLS\n");
|
||||
source.Append(" internal new static ");
|
||||
@ -304,7 +307,7 @@ namespace Godot.SourceGenerators
|
||||
source.Append(" values.Add(PropertyName.");
|
||||
source.Append(exportedMember.Name);
|
||||
source.Append(", ");
|
||||
source.Append(defaultValueLocalName);
|
||||
source.AppendManagedToVariantExpr(defaultValueLocalName, exportedMember.Type);
|
||||
source.Append(");\n");
|
||||
}
|
||||
|
||||
|
@ -455,7 +455,7 @@ namespace GodotTools
|
||||
_menuPopup.IdPressed += _MenuOptionPressed;
|
||||
|
||||
// External editor settings
|
||||
EditorDef("mono/editor/external_editor", ExternalEditorId.None);
|
||||
EditorDef("mono/editor/external_editor", Variant.From(ExternalEditorId.None));
|
||||
|
||||
string settingsHintStr = "Disabled";
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
using Godot;
|
||||
using Godot.NativeInterop;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
@ -8,30 +9,31 @@ namespace GodotTools.Internals
|
||||
{
|
||||
public static float EditorScale => Internal.godot_icall_Globals_EditorScale();
|
||||
|
||||
public static unsafe object GlobalDef(string setting, object defaultValue, bool restartIfChanged = false)
|
||||
// ReSharper disable once UnusedMethodReturnValue.Global
|
||||
public static Variant GlobalDef(string setting, Variant defaultValue, bool restartIfChanged = false)
|
||||
{
|
||||
using godot_string settingIn = Marshaling.ConvertStringToNative(setting);
|
||||
using godot_variant defaultValueIn = Marshaling.ConvertManagedObjectToVariant(defaultValue);
|
||||
Internal.godot_icall_Globals_GlobalDef(settingIn, defaultValueIn, restartIfChanged, out godot_variant result);
|
||||
using (result)
|
||||
return Marshaling.ConvertVariantToManagedObject(result);
|
||||
using godot_variant defaultValueIn = defaultValue.CopyNativeVariant();
|
||||
Internal.godot_icall_Globals_GlobalDef(settingIn, defaultValueIn, restartIfChanged,
|
||||
out godot_variant result);
|
||||
return Variant.CreateTakingOwnershipOfDisposableValue(result);
|
||||
}
|
||||
|
||||
public static unsafe object EditorDef(string setting, object defaultValue, bool restartIfChanged = false)
|
||||
// ReSharper disable once UnusedMethodReturnValue.Global
|
||||
public static Variant EditorDef(string setting, Variant defaultValue, bool restartIfChanged = false)
|
||||
{
|
||||
using godot_string settingIn = Marshaling.ConvertStringToNative(setting);
|
||||
using godot_variant defaultValueIn = Marshaling.ConvertManagedObjectToVariant(defaultValue);
|
||||
Internal.godot_icall_Globals_EditorDef(settingIn, defaultValueIn, restartIfChanged, out godot_variant result);
|
||||
using (result)
|
||||
return Marshaling.ConvertVariantToManagedObject(result);
|
||||
using godot_variant defaultValueIn = defaultValue.CopyNativeVariant();
|
||||
Internal.godot_icall_Globals_EditorDef(settingIn, defaultValueIn, restartIfChanged,
|
||||
out godot_variant result);
|
||||
return Variant.CreateTakingOwnershipOfDisposableValue(result);
|
||||
}
|
||||
|
||||
public static object EditorShortcut(string setting)
|
||||
public static Variant EditorShortcut(string setting)
|
||||
{
|
||||
using godot_string settingIn = Marshaling.ConvertStringToNative(setting);
|
||||
Internal.godot_icall_Globals_EditorShortcut(settingIn, out godot_variant result);
|
||||
using (result)
|
||||
return Marshaling.ConvertVariantToManagedObject(result);
|
||||
return Variant.CreateTakingOwnershipOfDisposableValue(result);
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
|
@ -159,7 +159,7 @@ namespace Godot.Bridge
|
||||
|
||||
for (int i = 0; i < paramCount; i++)
|
||||
{
|
||||
invokeParams[i] = Marshaling.ConvertVariantToManagedObjectOfType(
|
||||
invokeParams[i] = DelegateUtils.RuntimeTypeConversionHelper.ConvertToObjectOfType(
|
||||
*args[i], parameters[i].ParameterType);
|
||||
}
|
||||
|
||||
@ -832,7 +832,8 @@ namespace Godot.Bridge
|
||||
}
|
||||
else
|
||||
{
|
||||
interopProperties = ((godotsharp_property_info*)NativeMemory.Alloc((nuint)length, (nuint)sizeof(godotsharp_property_info)))!;
|
||||
interopProperties = ((godotsharp_property_info*)NativeMemory.Alloc(
|
||||
(nuint)length, (nuint)sizeof(godotsharp_property_info)))!;
|
||||
}
|
||||
|
||||
try
|
||||
@ -858,8 +859,8 @@ namespace Godot.Bridge
|
||||
|
||||
addPropInfoFunc(scriptPtr, ¤tClassName, interopProperties, length);
|
||||
|
||||
// We're borrowing the StringName's without making an owning copy, so the
|
||||
// managed collection needs to be kept alive until `addPropInfoFunc` returns.
|
||||
// We're borrowing the native value of the StringName entries.
|
||||
// The dictionary needs to be kept alive until `addPropInfoFunc` returns.
|
||||
GC.KeepAlive(properties);
|
||||
}
|
||||
finally
|
||||
@ -884,12 +885,7 @@ namespace Godot.Bridge
|
||||
{
|
||||
// Careful with padding...
|
||||
public godot_string_name Name; // Not owned
|
||||
public godot_variant Value;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Value.Dispose();
|
||||
}
|
||||
public godot_variant Value; // Not owned
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
@ -928,10 +924,35 @@ namespace Godot.Bridge
|
||||
if (getGodotPropertyDefaultValuesMethod == null)
|
||||
return;
|
||||
|
||||
var defaultValues = (Dictionary<StringName, object>?)
|
||||
getGodotPropertyDefaultValuesMethod.Invoke(null, null);
|
||||
var defaultValuesObj = getGodotPropertyDefaultValuesMethod.Invoke(null, null);
|
||||
|
||||
if (defaultValues == null || defaultValues.Count <= 0)
|
||||
if (defaultValuesObj == null)
|
||||
return;
|
||||
|
||||
Dictionary<StringName, Variant> defaultValues;
|
||||
|
||||
if (defaultValuesObj is Dictionary<StringName, object> defaultValuesLegacy)
|
||||
{
|
||||
// We have to support this for some time, otherwise this could cause data loss for projects
|
||||
// built with previous releases. Ideally, we should remove this before Godot 4.0 stable.
|
||||
|
||||
if (defaultValuesLegacy.Count <= 0)
|
||||
return;
|
||||
|
||||
defaultValues = new();
|
||||
|
||||
foreach (var pair in defaultValuesLegacy)
|
||||
{
|
||||
defaultValues[pair.Key] = Variant.CreateTakingOwnershipOfDisposableValue(
|
||||
DelegateUtils.RuntimeTypeConversionHelper.ConvertToVariant(pair.Value));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultValues = (Dictionary<StringName, Variant>)defaultValuesObj;
|
||||
}
|
||||
|
||||
if (defaultValues.Count <= 0)
|
||||
return;
|
||||
|
||||
int length = defaultValues.Count;
|
||||
@ -952,7 +973,8 @@ namespace Godot.Bridge
|
||||
}
|
||||
else
|
||||
{
|
||||
interopDefaultValues = ((godotsharp_property_def_val_pair*)NativeMemory.Alloc((nuint)length, (nuint)sizeof(godotsharp_property_def_val_pair)))!;
|
||||
interopDefaultValues = ((godotsharp_property_def_val_pair*)NativeMemory.Alloc(
|
||||
(nuint)length, (nuint)sizeof(godotsharp_property_def_val_pair)))!;
|
||||
}
|
||||
|
||||
try
|
||||
@ -963,7 +985,7 @@ namespace Godot.Bridge
|
||||
godotsharp_property_def_val_pair interopProperty = new()
|
||||
{
|
||||
Name = (godot_string_name)defaultValuePair.Key.NativeValue, // Not owned
|
||||
Value = Marshaling.ConvertManagedObjectToVariant(defaultValuePair.Value)
|
||||
Value = (godot_variant)defaultValuePair.Value.NativeVar // Not owned
|
||||
};
|
||||
|
||||
interopDefaultValues[i] = interopProperty;
|
||||
@ -973,15 +995,12 @@ namespace Godot.Bridge
|
||||
|
||||
addDefValFunc(scriptPtr, interopDefaultValues, length);
|
||||
|
||||
// We're borrowing the StringName's without making an owning copy, so the
|
||||
// managed collection needs to be kept alive until `addDefValFunc` returns.
|
||||
// We're borrowing the native value of the StringName and Variant entries.
|
||||
// The dictionary needs to be kept alive until `addDefValFunc` returns.
|
||||
GC.KeepAlive(defaultValues);
|
||||
}
|
||||
finally
|
||||
{
|
||||
for (int i = 0; i < length; i++)
|
||||
interopDefaultValues[i].Dispose();
|
||||
|
||||
if (!useStack)
|
||||
NativeMemory.Free(interopDefaultValues);
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ namespace Godot
|
||||
writer.Write(field.Name);
|
||||
|
||||
var fieldValue = field.GetValue(target);
|
||||
using var fieldValueVariant = Marshaling.ConvertManagedObjectToVariant(fieldValue);
|
||||
using var fieldValueVariant = RuntimeTypeConversionHelper.ConvertToVariant(fieldValue);
|
||||
byte[] valueBuffer = VarToBytes(fieldValueVariant);
|
||||
writer.Write(valueBuffer.Length);
|
||||
writer.Write(valueBuffer);
|
||||
@ -443,7 +443,14 @@ namespace Godot
|
||||
|
||||
FieldInfo? fieldInfo = targetType.GetField(name,
|
||||
BindingFlags.Instance | BindingFlags.Public);
|
||||
fieldInfo?.SetValue(recreatedTarget, GD.BytesToVar(valueBuffer));
|
||||
|
||||
if (fieldInfo != null)
|
||||
{
|
||||
var variantValue = GD.BytesToVar(valueBuffer);
|
||||
object? managedValue = RuntimeTypeConversionHelper.ConvertToObjectOfType(
|
||||
(godot_variant)variantValue.NativeVar, fieldInfo.FieldType);
|
||||
fieldInfo.SetValue(recreatedTarget, managedValue);
|
||||
}
|
||||
}
|
||||
|
||||
@delegate = Delegate.CreateDelegate(delegateType, recreatedTarget, methodInfo,
|
||||
@ -537,5 +544,269 @@ namespace Godot
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
internal static class RuntimeTypeConversionHelper
|
||||
{
|
||||
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
|
||||
public static godot_variant ConvertToVariant(object? obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return default;
|
||||
|
||||
switch (obj)
|
||||
{
|
||||
case bool @bool:
|
||||
return VariantUtils.CreateFrom(@bool);
|
||||
case char @char:
|
||||
return VariantUtils.CreateFrom(@char);
|
||||
case sbyte int8:
|
||||
return VariantUtils.CreateFrom(int8);
|
||||
case short int16:
|
||||
return VariantUtils.CreateFrom(int16);
|
||||
case int int32:
|
||||
return VariantUtils.CreateFrom(int32);
|
||||
case long int64:
|
||||
return VariantUtils.CreateFrom(int64);
|
||||
case byte uint8:
|
||||
return VariantUtils.CreateFrom(uint8);
|
||||
case ushort uint16:
|
||||
return VariantUtils.CreateFrom(uint16);
|
||||
case uint uint32:
|
||||
return VariantUtils.CreateFrom(uint32);
|
||||
case ulong uint64:
|
||||
return VariantUtils.CreateFrom(uint64);
|
||||
case float @float:
|
||||
return VariantUtils.CreateFrom(@float);
|
||||
case double @double:
|
||||
return VariantUtils.CreateFrom(@double);
|
||||
case Vector2 vector2:
|
||||
return VariantUtils.CreateFrom(vector2);
|
||||
case Vector2i vector2I:
|
||||
return VariantUtils.CreateFrom(vector2I);
|
||||
case Rect2 rect2:
|
||||
return VariantUtils.CreateFrom(rect2);
|
||||
case Rect2i rect2I:
|
||||
return VariantUtils.CreateFrom(rect2I);
|
||||
case Transform2D transform2D:
|
||||
return VariantUtils.CreateFrom(transform2D);
|
||||
case Vector3 vector3:
|
||||
return VariantUtils.CreateFrom(vector3);
|
||||
case Vector3i vector3I:
|
||||
return VariantUtils.CreateFrom(vector3I);
|
||||
case Vector4 vector4:
|
||||
return VariantUtils.CreateFrom(vector4);
|
||||
case Vector4i vector4I:
|
||||
return VariantUtils.CreateFrom(vector4I);
|
||||
case Basis basis:
|
||||
return VariantUtils.CreateFrom(basis);
|
||||
case Quaternion quaternion:
|
||||
return VariantUtils.CreateFrom(quaternion);
|
||||
case Transform3D transform3d:
|
||||
return VariantUtils.CreateFrom(transform3d);
|
||||
case Projection projection:
|
||||
return VariantUtils.CreateFrom(projection);
|
||||
case AABB aabb:
|
||||
return VariantUtils.CreateFrom(aabb);
|
||||
case Color color:
|
||||
return VariantUtils.CreateFrom(color);
|
||||
case Plane plane:
|
||||
return VariantUtils.CreateFrom(plane);
|
||||
case Callable callable:
|
||||
return VariantUtils.CreateFrom(callable);
|
||||
case SignalInfo signalInfo:
|
||||
return VariantUtils.CreateFrom(signalInfo);
|
||||
case string @string:
|
||||
return VariantUtils.CreateFrom(@string);
|
||||
case byte[] byteArray:
|
||||
return VariantUtils.CreateFrom(byteArray);
|
||||
case int[] int32Array:
|
||||
return VariantUtils.CreateFrom(int32Array);
|
||||
case long[] int64Array:
|
||||
return VariantUtils.CreateFrom(int64Array);
|
||||
case float[] floatArray:
|
||||
return VariantUtils.CreateFrom(floatArray);
|
||||
case double[] doubleArray:
|
||||
return VariantUtils.CreateFrom(doubleArray);
|
||||
case string[] stringArray:
|
||||
return VariantUtils.CreateFrom(stringArray);
|
||||
case Vector2[] vector2Array:
|
||||
return VariantUtils.CreateFrom(vector2Array);
|
||||
case Vector3[] vector3Array:
|
||||
return VariantUtils.CreateFrom(vector3Array);
|
||||
case Color[] colorArray:
|
||||
return VariantUtils.CreateFrom(colorArray);
|
||||
case StringName[] stringNameArray:
|
||||
return VariantUtils.CreateFrom(stringNameArray);
|
||||
case NodePath[] nodePathArray:
|
||||
return VariantUtils.CreateFrom(nodePathArray);
|
||||
case RID[] ridArray:
|
||||
return VariantUtils.CreateFrom(ridArray);
|
||||
case Godot.Object[] godotObjectArray:
|
||||
return VariantUtils.CreateFrom(godotObjectArray);
|
||||
case StringName stringName:
|
||||
return VariantUtils.CreateFrom(stringName);
|
||||
case NodePath nodePath:
|
||||
return VariantUtils.CreateFrom(nodePath);
|
||||
case RID rid:
|
||||
return VariantUtils.CreateFrom(rid);
|
||||
case Collections.Dictionary godotDictionary:
|
||||
return VariantUtils.CreateFrom(godotDictionary);
|
||||
case Collections.Array godotArray:
|
||||
return VariantUtils.CreateFrom(godotArray);
|
||||
case Variant variant:
|
||||
return VariantUtils.CreateFrom(variant);
|
||||
case Godot.Object godotObject:
|
||||
return VariantUtils.CreateFrom(godotObject);
|
||||
case Enum @enum:
|
||||
return VariantUtils.CreateFrom(Convert.ToInt64(@enum));
|
||||
case Collections.IGenericGodotDictionary godotDictionary:
|
||||
return VariantUtils.CreateFrom(godotDictionary.UnderlyingDictionary);
|
||||
case Collections.IGenericGodotArray godotArray:
|
||||
return VariantUtils.CreateFrom(godotArray.UnderlyingArray);
|
||||
}
|
||||
|
||||
GD.PushError("Attempted to convert an unmarshallable managed type to Variant. Name: '" +
|
||||
obj.GetType().FullName + ".");
|
||||
return new godot_variant();
|
||||
}
|
||||
|
||||
private delegate object? ConvertToSystemObjectFunc(in godot_variant managed);
|
||||
|
||||
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
|
||||
// ReSharper disable once RedundantNameQualifier
|
||||
private static readonly System.Collections.Generic.Dictionary<Type, ConvertToSystemObjectFunc>
|
||||
ToSystemObjectFuncByType = new()
|
||||
{
|
||||
[typeof(bool)] = (in godot_variant variant) => VariantUtils.ConvertTo<bool>(variant),
|
||||
[typeof(char)] = (in godot_variant variant) => VariantUtils.ConvertTo<char>(variant),
|
||||
[typeof(sbyte)] = (in godot_variant variant) => VariantUtils.ConvertTo<sbyte>(variant),
|
||||
[typeof(short)] = (in godot_variant variant) => VariantUtils.ConvertTo<short>(variant),
|
||||
[typeof(int)] = (in godot_variant variant) => VariantUtils.ConvertTo<int>(variant),
|
||||
[typeof(long)] = (in godot_variant variant) => VariantUtils.ConvertTo<long>(variant),
|
||||
[typeof(byte)] = (in godot_variant variant) => VariantUtils.ConvertTo<byte>(variant),
|
||||
[typeof(ushort)] = (in godot_variant variant) => VariantUtils.ConvertTo<ushort>(variant),
|
||||
[typeof(uint)] = (in godot_variant variant) => VariantUtils.ConvertTo<uint>(variant),
|
||||
[typeof(ulong)] = (in godot_variant variant) => VariantUtils.ConvertTo<ulong>(variant),
|
||||
[typeof(float)] = (in godot_variant variant) => VariantUtils.ConvertTo<float>(variant),
|
||||
[typeof(double)] = (in godot_variant variant) => VariantUtils.ConvertTo<double>(variant),
|
||||
[typeof(Vector2)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector2>(variant),
|
||||
[typeof(Vector2i)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector2i>(variant),
|
||||
[typeof(Rect2)] = (in godot_variant variant) => VariantUtils.ConvertTo<Rect2>(variant),
|
||||
[typeof(Rect2i)] = (in godot_variant variant) => VariantUtils.ConvertTo<Rect2i>(variant),
|
||||
[typeof(Transform2D)] = (in godot_variant variant) => VariantUtils.ConvertTo<Transform2D>(variant),
|
||||
[typeof(Vector3)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector3>(variant),
|
||||
[typeof(Vector3i)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector3i>(variant),
|
||||
[typeof(Basis)] = (in godot_variant variant) => VariantUtils.ConvertTo<Basis>(variant),
|
||||
[typeof(Quaternion)] = (in godot_variant variant) => VariantUtils.ConvertTo<Quaternion>(variant),
|
||||
[typeof(Transform3D)] = (in godot_variant variant) => VariantUtils.ConvertTo<Transform3D>(variant),
|
||||
[typeof(Vector4)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector4>(variant),
|
||||
[typeof(Vector4i)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector4i>(variant),
|
||||
[typeof(AABB)] = (in godot_variant variant) => VariantUtils.ConvertTo<AABB>(variant),
|
||||
[typeof(Color)] = (in godot_variant variant) => VariantUtils.ConvertTo<Color>(variant),
|
||||
[typeof(Plane)] = (in godot_variant variant) => VariantUtils.ConvertTo<Plane>(variant),
|
||||
[typeof(Callable)] = (in godot_variant variant) => VariantUtils.ConvertTo<Callable>(variant),
|
||||
[typeof(SignalInfo)] = (in godot_variant variant) => VariantUtils.ConvertTo<SignalInfo>(variant),
|
||||
[typeof(string)] = (in godot_variant variant) => VariantUtils.ConvertTo<string>(variant),
|
||||
[typeof(byte[])] = (in godot_variant variant) => VariantUtils.ConvertTo<byte[]>(variant),
|
||||
[typeof(int[])] = (in godot_variant variant) => VariantUtils.ConvertTo<int[]>(variant),
|
||||
[typeof(long[])] = (in godot_variant variant) => VariantUtils.ConvertTo<long[]>(variant),
|
||||
[typeof(float[])] = (in godot_variant variant) => VariantUtils.ConvertTo<float[]>(variant),
|
||||
[typeof(double[])] = (in godot_variant variant) => VariantUtils.ConvertTo<double[]>(variant),
|
||||
[typeof(string[])] = (in godot_variant variant) => VariantUtils.ConvertTo<string[]>(variant),
|
||||
[typeof(Vector2[])] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector2[]>(variant),
|
||||
[typeof(Vector3[])] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector3[]>(variant),
|
||||
[typeof(Color[])] = (in godot_variant variant) => VariantUtils.ConvertTo<Color[]>(variant),
|
||||
[typeof(StringName[])] =
|
||||
(in godot_variant variant) => VariantUtils.ConvertTo<StringName[]>(variant),
|
||||
[typeof(NodePath[])] = (in godot_variant variant) => VariantUtils.ConvertTo<NodePath[]>(variant),
|
||||
[typeof(RID[])] = (in godot_variant variant) => VariantUtils.ConvertTo<RID[]>(variant),
|
||||
[typeof(StringName)] = (in godot_variant variant) => VariantUtils.ConvertTo<StringName>(variant),
|
||||
[typeof(NodePath)] = (in godot_variant variant) => VariantUtils.ConvertTo<NodePath>(variant),
|
||||
[typeof(RID)] = (in godot_variant variant) => VariantUtils.ConvertTo<RID>(variant),
|
||||
[typeof(Godot.Collections.Dictionary)] = (in godot_variant variant) =>
|
||||
VariantUtils.ConvertTo<Godot.Collections.Dictionary>(variant),
|
||||
[typeof(Godot.Collections.Array)] =
|
||||
(in godot_variant variant) => VariantUtils.ConvertTo<Godot.Collections.Array>(variant),
|
||||
[typeof(Variant)] = (in godot_variant variant) => VariantUtils.ConvertTo<Variant>(variant),
|
||||
};
|
||||
|
||||
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
|
||||
public static object? ConvertToObjectOfType(in godot_variant variant, Type type)
|
||||
{
|
||||
if (ToSystemObjectFuncByType.TryGetValue(type, out var func))
|
||||
return func(variant);
|
||||
|
||||
if (typeof(Godot.Object).IsAssignableFrom(type))
|
||||
return Convert.ChangeType(VariantUtils.ConvertTo<Godot.Object>(variant), type);
|
||||
|
||||
if (type.IsEnum)
|
||||
{
|
||||
var enumUnderlyingType = type.GetEnumUnderlyingType();
|
||||
|
||||
switch (Type.GetTypeCode(enumUnderlyingType))
|
||||
{
|
||||
case TypeCode.SByte:
|
||||
return Enum.ToObject(type, VariantUtils.ConvertToInt8(variant));
|
||||
case TypeCode.Int16:
|
||||
return Enum.ToObject(type, VariantUtils.ConvertToInt16(variant));
|
||||
case TypeCode.Int32:
|
||||
return Enum.ToObject(type, VariantUtils.ConvertToInt32(variant));
|
||||
case TypeCode.Int64:
|
||||
return Enum.ToObject(type, VariantUtils.ConvertToInt64(variant));
|
||||
case TypeCode.Byte:
|
||||
return Enum.ToObject(type, VariantUtils.ConvertToUInt8(variant));
|
||||
case TypeCode.UInt16:
|
||||
return Enum.ToObject(type, VariantUtils.ConvertToUInt16(variant));
|
||||
case TypeCode.UInt32:
|
||||
return Enum.ToObject(type, VariantUtils.ConvertToUInt32(variant));
|
||||
case TypeCode.UInt64:
|
||||
return Enum.ToObject(type, VariantUtils.ConvertToUInt64(variant));
|
||||
default:
|
||||
{
|
||||
GD.PushError(
|
||||
"Attempted to convert Variant to enum value of unsupported underlying type. Name: " +
|
||||
type.FullName + " : " + enumUnderlyingType.FullName + ".");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
var genericTypeDef = type.GetGenericTypeDefinition();
|
||||
|
||||
if (genericTypeDef == typeof(Godot.Collections.Dictionary<,>))
|
||||
{
|
||||
var ctor = type.GetConstructor(BindingFlags.Default,
|
||||
new[] { typeof(Godot.Collections.Dictionary) });
|
||||
|
||||
if (ctor == null)
|
||||
throw new InvalidOperationException("Dictionary constructor not found");
|
||||
|
||||
return ctor.Invoke(new object?[]
|
||||
{
|
||||
VariantUtils.ConvertTo<Godot.Collections.Dictionary>(variant)
|
||||
});
|
||||
}
|
||||
|
||||
if (genericTypeDef == typeof(Godot.Collections.Array<>))
|
||||
{
|
||||
var ctor = type.GetConstructor(BindingFlags.Default,
|
||||
new[] { typeof(Godot.Collections.Array) });
|
||||
|
||||
if (ctor == null)
|
||||
throw new InvalidOperationException("Array constructor not found");
|
||||
|
||||
return ctor.Invoke(new object?[]
|
||||
{
|
||||
VariantUtils.ConvertTo<Godot.Collections.Array>(variant)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
GD.PushError($"Attempted to convert Variant to unsupported type. Name: {type.FullName}.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -4,6 +4,8 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Godot.NativeInterop;
|
||||
|
||||
#nullable enable
|
||||
|
||||
public partial class VariantUtils
|
||||
{
|
||||
private static Exception UnsupportedType<T>() => new InvalidOperationException(
|
||||
|
Loading…
Reference in New Issue
Block a user