summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs6
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs6
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs38
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs6
-rw-r--r--modules/mono/editor/bindings_generator.cpp15
-rw-r--r--modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs361
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs378
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs976
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs16
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj1
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Variant.cs16
13 files changed, 1792 insertions, 31 deletions
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs
index a5b4cb81f6..ac9f59aa99 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs
@@ -99,5 +99,11 @@ namespace Godot.SourceGenerators.Sample
[Export] private Godot.Collections.Array field_GodotArray =
new() { "foo", 10, Vector2.Up, Colors.Chocolate };
+
+ [Export] private Godot.Collections.Dictionary<string, bool> field_GodotGenericDictionary =
+ new() { { "foo", true }, { "bar", false } };
+
+ [Export] private Godot.Collections.Array<int> field_GodotGenericArray =
+ new() { 0, 1, 2, 3, 4, 5, 6 };
}
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs
index eb35c88260..4a0e8075f0 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs
@@ -99,5 +99,11 @@ namespace Godot.SourceGenerators.Sample
[Export] private Godot.Collections.Array property_GodotArray { get; set; } =
new() { "foo", 10, Vector2.Up, Colors.Chocolate };
+
+ [Export] private Godot.Collections.Dictionary<string, bool> property_GodotGenericDictionary { get; set; } =
+ new() { { "foo", true }, { "bar", false } };
+
+ [Export] private Godot.Collections.Array<int> property_GodotGenericArray { get; set; } =
+ new() { 0, 1, 2, 3, 4, 5, 6 };
}
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs
index 3f767c8a5f..15f5803bf0 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs
@@ -67,5 +67,7 @@ namespace Godot.SourceGenerators
RID,
GodotDictionary,
GodotArray,
+ GodotGenericDictionary,
+ GodotGenericArray,
}
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
index 4300037796..ca84518c0c 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
@@ -78,6 +78,8 @@ namespace Godot.SourceGenerators
MarshalType.RID => VariantType.Rid,
MarshalType.GodotDictionary => VariantType.Dictionary,
MarshalType.GodotArray => VariantType.Array,
+ MarshalType.GodotGenericDictionary => VariantType.Dictionary,
+ MarshalType.GodotGenericArray => VariantType.Array,
_ => null
};
@@ -214,13 +216,17 @@ namespace Godot.SourceGenerators
_ => null
};
case "Collections"
- when !(type is INamedTypeSymbol { IsGenericType: true }) &&
- type.ContainingNamespace.FullQualifiedName() ==
- "Godot.Collections":
+ when type.ContainingNamespace.FullQualifiedName() == "Godot.Collections":
return type switch
{
- { Name: "Dictionary" } => MarshalType.GodotDictionary,
- { Name: "Array" } => MarshalType.GodotArray,
+ { Name: "Dictionary" } =>
+ type is INamedTypeSymbol { IsGenericType: false } ?
+ MarshalType.GodotDictionary :
+ MarshalType.GodotGenericDictionary,
+ { Name: "Array" } =>
+ type is INamedTypeSymbol { IsGenericType: false } ?
+ MarshalType.GodotArray :
+ MarshalType.GodotGenericArray,
_ => null
};
}
@@ -283,6 +289,10 @@ namespace Godot.SourceGenerators
string c, string d, string e, string f, string g)
=> source.Append(a).Append(b).Append(c).Append(d).Append(e).Append(f).Append(g);
+ private static StringBuilder Append(this StringBuilder source, string a, string b,
+ string c, string d, string e, string f, string g, string h)
+ => source.Append(a).Append(b).Append(c).Append(d).Append(e).Append(f).Append(g).Append(h);
+
private const string VariantUtils = "global::Godot.NativeInterop.VariantUtils";
public static StringBuilder AppendNativeVariantToManagedExpr(this StringBuilder source,
@@ -397,6 +407,13 @@ namespace Godot.SourceGenerators
source.Append(VariantUtils, ".ConvertToDictionaryObject(", inputExpr, ")"),
MarshalType.GodotArray =>
source.Append(VariantUtils, ".ConvertToArrayObject(", inputExpr, ")"),
+ MarshalType.GodotGenericDictionary =>
+ source.Append(VariantUtils, ".ConvertToDictionaryObject<",
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ", ",
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedName(), ">(", inputExpr, ")"),
+ MarshalType.GodotGenericArray =>
+ source.Append(VariantUtils, ".ConvertToArrayObject<",
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ">(", inputExpr, ")"),
_ => throw new ArgumentOutOfRangeException(nameof(marshalType), marshalType,
"Received unexpected marshal type")
};
@@ -511,6 +528,10 @@ namespace Godot.SourceGenerators
source.Append(VariantUtils, ".CreateFromDictionary(", inputExpr, ")"),
MarshalType.GodotArray =>
source.Append(VariantUtils, ".CreateFromArray(", inputExpr, ")"),
+ MarshalType.GodotGenericDictionary =>
+ source.Append(VariantUtils, ".CreateFromDictionary(", inputExpr, ")"),
+ MarshalType.GodotGenericArray =>
+ source.Append(VariantUtils, ".CreateFromArray(", inputExpr, ")"),
_ => throw new ArgumentOutOfRangeException(nameof(marshalType), marshalType,
"Received unexpected marshal type")
};
@@ -576,6 +597,11 @@ namespace Godot.SourceGenerators
MarshalType.RID => source.Append(inputExpr, ".AsRID()"),
MarshalType.GodotDictionary => source.Append(inputExpr, ".AsGodotDictionary()"),
MarshalType.GodotArray => source.Append(inputExpr, ".AsGodotArray()"),
+ MarshalType.GodotGenericDictionary => source.Append(inputExpr, ".AsGodotDictionary<",
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ", ",
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedName(), ">()"),
+ MarshalType.GodotGenericArray => source.Append(inputExpr, ".AsGodotArray<",
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ">()"),
_ => throw new ArgumentOutOfRangeException(nameof(marshalType), marshalType,
"Received unexpected marshal type")
};
@@ -636,6 +662,8 @@ namespace Godot.SourceGenerators
case MarshalType.RID:
case MarshalType.GodotDictionary:
case MarshalType.GodotArray:
+ case MarshalType.GodotGenericDictionary:
+ case MarshalType.GodotGenericArray:
return source.Append("Variant.CreateFrom(", inputExpr, ")");
case MarshalType.Enum:
return source.Append("Variant.CreateFrom((long)", inputExpr, ")");
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
index a8128be909..96d1fc28bf 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
@@ -58,7 +58,7 @@ namespace GodotTools.Build
}
// TODO Use List once we have proper serialization.
- private Godot.Collections.Array _issues = new();
+ private Godot.Collections.Array<BuildIssue> _issues = new();
private ItemList _issuesList;
private PopupMenu _issuesListContextMenu;
private TextEdit _buildLog;
@@ -128,7 +128,7 @@ namespace GodotTools.Build
if (issueIndex < 0 || issueIndex >= _issues.Count)
throw new IndexOutOfRangeException("Issue index out of range");
- var issue = (BuildIssue)_issues[issueIndex];
+ BuildIssue issue = _issues[issueIndex];
if (string.IsNullOrEmpty(issue.ProjectFile) && string.IsNullOrEmpty(issue.File))
return;
@@ -162,7 +162,7 @@ namespace GodotTools.Build
{
for (int i = 0; i < _issues.Count; i++)
{
- var issue = (BuildIssue)_issues[i];
+ BuildIssue issue = _issues[i];
if (!(issue.Warning ? WarningsVisible : ErrorsVisible))
continue;
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index b879c95fa1..73d8f23081 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -2891,13 +2891,8 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
String() + "Return type is reference but hint is not '" _STR(PROPERTY_HINT_RESOURCE_TYPE) "'." +
" Are you returning a reference type by pointer? Method: '" + itype.name + "." + imethod.name + "'.");
} else if (return_info.type == Variant::ARRAY && return_info.hint == PROPERTY_HINT_ARRAY_TYPE) {
-// TODO: Enable once generic Array is re-implemented
-#if 0
imethod.return_type.cname = Variant::get_type_name(return_info.type) + "_@generic";
imethod.return_type.generic_type_parameters.push_back(TypeReference(return_info.hint_string));
-#else
- imethod.return_type.cname = Variant::get_type_name(return_info.type);
-#endif
} else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) {
imethod.return_type.cname = return_info.hint_string;
} else if (return_info.type == Variant::NIL && return_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
@@ -2928,13 +2923,8 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
} else if (arginfo.class_name != StringName()) {
iarg.type.cname = arginfo.class_name;
} else if (arginfo.type == Variant::ARRAY && arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
-// TODO: Enable once generic Array is re-implemented
-#if 0
iarg.type.cname = Variant::get_type_name(arginfo.type) + "_@generic";
iarg.type.generic_type_parameters.push_back(TypeReference(arginfo.hint_string));
-#else
- iarg.type.cname = Variant::get_type_name(arginfo.type);
-#endif
} else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
iarg.type.cname = arginfo.hint_string;
} else if (arginfo.type == Variant::NIL) {
@@ -3041,13 +3031,8 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
} else if (arginfo.class_name != StringName()) {
iarg.type.cname = arginfo.class_name;
} else if (arginfo.type == Variant::ARRAY && arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
-// TODO: Enable once generic Array is re-implemented
-#if 0
iarg.type.cname = Variant::get_type_name(arginfo.type) + "_@generic";
iarg.type.generic_type_parameters.push_back(TypeReference(arginfo.hint_string));
-#else
- iarg.type.cname = Variant::get_type_name(arginfo.type);
-#endif
} else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
iarg.type.cname = arginfo.hint_string;
} else if (arginfo.type == Variant::NIL) {
diff --git a/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs b/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs
index a1b93e7daa..bb482e0d6a 100644
--- a/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs
+++ b/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs
@@ -55,7 +55,7 @@ public partial class VisualShaderNode_CLASS_ : _BASE_
return 0;
}
- public override string _GetCode(Godot.Collections.Array inputVars, Godot.Collections.Array outputVars, Shader.Mode mode, VisualShader.Type type)
+ public override string _GetCode(Godot.Collections.Array<string> inputVars, Godot.Collections.Array<string> outputVars, Shader.Mode mode, VisualShader.Type type)
{
return "";
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
index 51d7d8195b..81991c6626 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using Godot.NativeInterop;
@@ -424,13 +425,6 @@ namespace Godot.Collections
}
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal object GetAtAsType(int index, Type type)
- {
- GetVariantBorrowElementAt(index, out godot_variant borrowElem);
- return Marshaling.ConvertVariantToManagedObjectOfType(borrowElem, type);
- }
-
// IEnumerable
/// <summary>
@@ -479,4 +473,357 @@ namespace Godot.Collections
elem = NativeValue.DangerousSelfRef.Elements[index];
}
}
+
+ /// <summary>
+ /// Typed 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 arrays or <see cref="List{T}"/>.
+ /// </summary>
+ /// <typeparam name="T">The type of the array.</typeparam>
+ [SuppressMessage("ReSharper", "RedundantExtendsListEntry")]
+ [SuppressMessage("Naming", "CA1710", MessageId = "Identifiers should have correct suffix")]
+ public sealed class Array<T> :
+ IList<T>,
+ IReadOnlyList<T>,
+ ICollection<T>,
+ IEnumerable<T>
+ {
+ // 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 unsafe delegate* managed<in T, godot_variant> _convertToVariantCallback;
+ private static unsafe delegate* managed<in godot_variant, T> _convertToManagedCallback;
+
+ // ReSharper restore StaticMemberInGenericType
+
+ static unsafe Array()
+ {
+ _convertToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<T>();
+ _convertToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<T>();
+ }
+
+ private static unsafe void ValidateVariantConversionCallbacks()
+ {
+ if (_convertToVariantCallback == null || _convertToManagedCallback == null)
+ {
+ throw new InvalidOperationException(
+ $"The array element type is not supported for conversion to Variant: '{typeof(T).FullName}'");
+ }
+ }
+
+ private readonly Array _underlyingArray;
+
+ internal ref godot_array.movable NativeValue
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => ref _underlyingArray.NativeValue;
+ }
+
+ /// <summary>
+ /// Constructs a new empty <see cref="Array{T}"/>.
+ /// </summary>
+ public Array()
+ {
+ ValidateVariantConversionCallbacks();
+
+ _underlyingArray = new Array();
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="Array{T}"/> from the given collection's elements.
+ /// </summary>
+ /// <param name="collection">The collection of elements to construct from.</param>
+ /// <returns>A new Godot Array.</returns>
+ public Array(IEnumerable<T> collection)
+ {
+ ValidateVariantConversionCallbacks();
+
+ if (collection == null)
+ throw new ArgumentNullException(nameof(collection));
+
+ _underlyingArray = new Array();
+
+ foreach (T element in collection)
+ Add(element);
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="Array{T}"/> from the given items.
+ /// </summary>
+ /// <param name="array">The items to put in the new array.</param>
+ /// <returns>A new Godot Array.</returns>
+ public Array(T[] array) : this()
+ {
+ ValidateVariantConversionCallbacks();
+
+ if (array == null)
+ throw new ArgumentNullException(nameof(array));
+
+ _underlyingArray = new Array();
+
+ foreach (T element in array)
+ Add(element);
+ }
+
+ /// <summary>
+ /// Constructs a typed <see cref="Array{T}"/> from an untyped <see cref="Array"/>.
+ /// </summary>
+ /// <param name="array">The untyped array to construct from.</param>
+ public Array(Array array)
+ {
+ ValidateVariantConversionCallbacks();
+
+ _underlyingArray = array;
+ }
+
+ // 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"/>.
+ /// </summary>
+ /// <param name="from">The typed array to convert.</param>
+ public static explicit operator Array(Array<T> from)
+ {
+ return from?._underlyingArray;
+ }
+
+ /// <summary>
+ /// Duplicates this <see cref="Array{T}"/>.
+ /// </summary>
+ /// <param name="deep">If <see langword="true"/>, performs a deep copy.</param>
+ /// <returns>A new Godot Array.</returns>
+ public Array<T> Duplicate(bool deep = false)
+ {
+ return new Array<T>(_underlyingArray.Duplicate(deep));
+ }
+
+ /// <summary>
+ /// Resizes this <see cref="Array{T}"/> to the given size.
+ /// </summary>
+ /// <param name="newSize">The new size of the array.</param>
+ /// <returns><see cref="Error.Ok"/> if successful, or an error code.</returns>
+ public Error Resize(int newSize)
+ {
+ return _underlyingArray.Resize(newSize);
+ }
+
+ /// <summary>
+ /// Shuffles the contents of this <see cref="Array{T}"/> into a random order.
+ /// </summary>
+ public void Shuffle()
+ {
+ _underlyingArray.Shuffle();
+ }
+
+ /// <summary>
+ /// Concatenates these two <see cref="Array{T}"/>s.
+ /// </summary>
+ /// <param name="left">The first array.</param>
+ /// <param name="right">The second array.</param>
+ /// <returns>A new Godot Array with the contents of both arrays.</returns>
+ public static Array<T> operator +(Array<T> left, Array<T> right)
+ {
+ if (left == null)
+ {
+ if (right == null)
+ return new Array<T>();
+
+ return right.Duplicate(deep: false);
+ }
+
+ if (right == null)
+ return left.Duplicate(deep: false);
+
+ return new Array<T>(left._underlyingArray + right._underlyingArray);
+ }
+
+ // IList<T>
+
+ /// <summary>
+ /// Returns the value at the given <paramref name="index"/>.
+ /// </summary>
+ /// <value>The value at the given <paramref name="index"/>.</value>
+ public unsafe T this[int index]
+ {
+ get
+ {
+ _underlyingArray.GetVariantBorrowElementAt(index, out godot_variant borrowElem);
+ return _convertToManagedCallback(borrowElem);
+ }
+ set
+ {
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException(nameof(index));
+ var self = (godot_array)_underlyingArray.NativeValue;
+ godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref self);
+ godot_variant* itemPtr = &ptrw[index];
+ (*itemPtr).Dispose();
+ *itemPtr = _convertToVariantCallback(value);
+ }
+ }
+
+ /// <summary>
+ /// Searches this <see cref="Array{T}"/> for an item
+ /// and returns its index or -1 if not found.
+ /// </summary>
+ /// <param name="item">The item to search for.</param>
+ /// <returns>The index of the item, or -1 if not found.</returns>
+ public unsafe int IndexOf(T item)
+ {
+ using var variantValue = _convertToVariantCallback(item);
+ var self = (godot_array)_underlyingArray.NativeValue;
+ return NativeFuncs.godotsharp_array_index_of(ref self, variantValue);
+ }
+
+ /// <summary>
+ /// Inserts a new item at a given position in the <see cref="Array{T}"/>.
+ /// The position must be a valid position of an existing item,
+ /// or the position at the end of the array.
+ /// Existing items will be moved to the right.
+ /// </summary>
+ /// <param name="index">The index to insert at.</param>
+ /// <param name="item">The item to insert.</param>
+ public unsafe void Insert(int index, T item)
+ {
+ if (index < 0 || index > Count)
+ throw new ArgumentOutOfRangeException(nameof(index));
+
+ using var variantValue = _convertToVariantCallback(item);
+ var self = (godot_array)_underlyingArray.NativeValue;
+ NativeFuncs.godotsharp_array_insert(ref self, index, variantValue);
+ }
+
+ /// <summary>
+ /// Removes an element from this <see cref="Array{T}"/> by index.
+ /// </summary>
+ /// <param name="index">The index of the element to remove.</param>
+ public void RemoveAt(int index)
+ {
+ _underlyingArray.RemoveAt(index);
+ }
+
+ // ICollection<T>
+
+ /// <summary>
+ /// Returns the number of elements in this <see cref="Array{T}"/>.
+ /// This is also known as the size or length of the array.
+ /// </summary>
+ /// <returns>The number of elements.</returns>
+ public int Count => _underlyingArray.Count;
+
+ bool ICollection<T>.IsReadOnly => false;
+
+ /// <summary>
+ /// Adds an item to the end of this <see cref="Array{T}"/>.
+ /// This is the same as <c>append</c> or <c>push_back</c> in GDScript.
+ /// </summary>
+ /// <param name="item">The item to add.</param>
+ /// <returns>The new size after adding the item.</returns>
+ public unsafe void Add(T item)
+ {
+ using var variantValue = _convertToVariantCallback(item);
+ var self = (godot_array)_underlyingArray.NativeValue;
+ _ = NativeFuncs.godotsharp_array_add(ref self, variantValue);
+ }
+
+ /// <summary>
+ /// Erases all items from this <see cref="Array{T}"/>.
+ /// </summary>
+ public void Clear()
+ {
+ _underlyingArray.Clear();
+ }
+
+ /// <summary>
+ /// Checks if this <see cref="Array{T}"/> contains the given item.
+ /// </summary>
+ /// <param name="item">The item to look for.</param>
+ /// <returns>Whether or not this array contains the given item.</returns>
+ public bool Contains(T item) => IndexOf(item) != -1;
+
+ /// <summary>
+ /// Copies the elements of this <see cref="Array{T}"/> to the given
+ /// C# array, starting at the given index.
+ /// </summary>
+ /// <param name="array">The C# array to copy to.</param>
+ /// <param name="arrayIndex">The index to start at.</param>
+ public void CopyTo(T[] array, int arrayIndex)
+ {
+ if (array == null)
+ throw new ArgumentNullException(nameof(array), "Value cannot be null.");
+
+ if (arrayIndex < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(arrayIndex),
+ "Number was less than the array's lower bound in the first dimension.");
+ }
+
+ int count = 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] = this[i];
+ arrayIndex++;
+ }
+ }
+
+ /// <summary>
+ /// Removes the first occurrence of the specified value
+ /// from this <see cref="Array{T}"/>.
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ /// <returns>A <see langword="bool"/> indicating success or failure.</returns>
+ public bool Remove(T item)
+ {
+ int index = IndexOf(item);
+ if (index >= 0)
+ {
+ RemoveAt(index);
+ return true;
+ }
+
+ return false;
+ }
+
+ // IEnumerable<T>
+
+ /// <summary>
+ /// Gets an enumerator for this <see cref="Array{T}"/>.
+ /// </summary>
+ /// <returns>An enumerator.</returns>
+ public IEnumerator<T> GetEnumerator()
+ {
+ int count = _underlyingArray.Count;
+
+ for (int i = 0; i < count; i++)
+ {
+ yield return this[i];
+ }
+ }
+
+ 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() => _underlyingArray.ToString();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Array<T> from) => Variant.CreateFrom(from);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Array<T>(Variant from) => from.AsGodotArray<T>();
+ }
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
index c3d500119a..fa8c94ed18 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
using Godot.NativeInterop;
namespace Godot.Collections
@@ -341,4 +343,380 @@ namespace Godot.Collections
return Marshaling.ConvertStringToManaged(str);
}
}
+
+ /// <summary>
+ /// Typed wrapper around Godot's Dictionary class, a dictionary 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.Collections.Generic.Dictionary{TKey, TValue}"/>.
+ /// </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>,
+ IReadOnlyDictionary<TKey, TValue>
+ {
+ // 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 unsafe delegate* managed<in TKey, godot_variant> _convertKeyToVariantCallback;
+ private static unsafe delegate* managed<in godot_variant, TKey> _convertKeyToManagedCallback;
+ private static unsafe delegate* managed<in TValue, godot_variant> _convertValueToVariantCallback;
+ private static unsafe delegate* managed<in godot_variant, TValue> _convertValueToManagedCallback;
+
+ // ReSharper restore StaticMemberInGenericType
+
+ static unsafe Dictionary()
+ {
+ _convertKeyToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TKey>();
+ _convertKeyToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TKey>();
+ _convertValueToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TValue>();
+ _convertValueToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TValue>();
+ }
+
+ private static unsafe void ValidateVariantConversionCallbacks()
+ {
+ if (_convertKeyToVariantCallback == null || _convertKeyToManagedCallback == null)
+ {
+ throw new InvalidOperationException(
+ $"The dictionary key type is not supported for conversion to Variant: '{typeof(TKey).FullName}'");
+ }
+
+ if (_convertValueToVariantCallback == null || _convertValueToManagedCallback == null)
+ {
+ throw new InvalidOperationException(
+ $"The dictionary value type is not supported for conversion to Variant: '{typeof(TValue).FullName}'");
+ }
+ }
+
+ private readonly Dictionary _underlyingDict;
+
+ internal ref godot_dictionary.movable NativeValue
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => ref _underlyingDict.NativeValue;
+ }
+
+ /// <summary>
+ /// Constructs a new empty <see cref="Dictionary{TKey, TValue}"/>.
+ /// </summary>
+ public Dictionary()
+ {
+ ValidateVariantConversionCallbacks();
+
+ _underlyingDict = new Dictionary();
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="Dictionary{TKey, TValue}"/> from the given dictionary's elements.
+ /// </summary>
+ /// <param name="dictionary">The dictionary to construct from.</param>
+ /// <returns>A new Godot Dictionary.</returns>
+ public Dictionary(IDictionary<TKey, TValue> dictionary)
+ {
+ ValidateVariantConversionCallbacks();
+
+ if (dictionary == null)
+ throw new ArgumentNullException(nameof(dictionary));
+
+ _underlyingDict = new Dictionary();
+
+ foreach (KeyValuePair<TKey, TValue> entry in dictionary)
+ Add(entry.Key, entry.Value);
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="Dictionary{TKey, TValue}"/> from the given dictionary's elements.
+ /// </summary>
+ /// <param name="dictionary">The dictionary to construct from.</param>
+ /// <returns>A new Godot Dictionary.</returns>
+ public Dictionary(Dictionary dictionary)
+ {
+ ValidateVariantConversionCallbacks();
+
+ _underlyingDict = dictionary;
+ }
+
+ // 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"/>.
+ /// </summary>
+ /// <param name="from">The typed dictionary to convert.</param>
+ public static explicit operator Dictionary(Dictionary<TKey, TValue> from)
+ {
+ return from?._underlyingDict;
+ }
+
+ /// <summary>
+ /// Duplicates this <see cref="Dictionary{TKey, TValue}"/>.
+ /// </summary>
+ /// <param name="deep">If <see langword="true"/>, performs a deep copy.</param>
+ /// <returns>A new Godot Dictionary.</returns>
+ public Dictionary<TKey, TValue> Duplicate(bool deep = false)
+ {
+ return new Dictionary<TKey, TValue>(_underlyingDict.Duplicate(deep));
+ }
+
+ // IDictionary<TKey, TValue>
+
+ /// <summary>
+ /// Returns the value at the given <paramref name="key"/>.
+ /// </summary>
+ /// <value>The value at the given <paramref name="key"/>.</value>
+ public unsafe TValue this[TKey key]
+ {
+ get
+ {
+ using var variantKey = _convertKeyToVariantCallback(key);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+
+ if (NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
+ variantKey, out godot_variant value).ToBool())
+ {
+ using (value)
+ return _convertValueToManagedCallback(value);
+ }
+ else
+ {
+ throw new KeyNotFoundException();
+ }
+ }
+ set
+ {
+ using var variantKey = _convertKeyToVariantCallback(key);
+ using var variantValue = _convertValueToVariantCallback(value);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ NativeFuncs.godotsharp_dictionary_set_value(ref self,
+ variantKey, variantValue);
+ }
+ }
+
+ /// <summary>
+ /// Gets the collection of keys in this <see cref="Dictionary{TKey, TValue}"/>.
+ /// </summary>
+ public ICollection<TKey> Keys
+ {
+ get
+ {
+ godot_array keyArray;
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ NativeFuncs.godotsharp_dictionary_keys(ref self, out keyArray);
+ return Array<TKey>.CreateTakingOwnershipOfDisposableValue(keyArray);
+ }
+ }
+
+ /// <summary>
+ /// Gets the collection of elements in this <see cref="Dictionary{TKey, TValue}"/>.
+ /// </summary>
+ public ICollection<TValue> Values
+ {
+ get
+ {
+ godot_array valuesArray;
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ NativeFuncs.godotsharp_dictionary_values(ref self, out valuesArray);
+ return Array<TValue>.CreateTakingOwnershipOfDisposableValue(valuesArray);
+ }
+ }
+
+ IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => Keys;
+
+ IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => Values;
+
+ private unsafe KeyValuePair<TKey, TValue> GetKeyValuePair(int index)
+ {
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref self, index,
+ out godot_variant key,
+ out godot_variant value);
+ using (key)
+ using (value)
+ {
+ return new KeyValuePair<TKey, TValue>(
+ _convertKeyToManagedCallback(key),
+ _convertValueToManagedCallback(value));
+ }
+ }
+
+ /// <summary>
+ /// Adds an object <paramref name="value"/> at key <paramref name="key"/>
+ /// to this <see cref="Dictionary{TKey, TValue}"/>.
+ /// </summary>
+ /// <param name="key">The key at which to add the object.</param>
+ /// <param name="value">The object to add.</param>
+ public unsafe void Add(TKey key, TValue value)
+ {
+ using var variantKey = _convertKeyToVariantCallback(key);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+
+ if (NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool())
+ throw new ArgumentException("An element with the same key already exists", nameof(key));
+
+ using var variantValue = _convertValueToVariantCallback(value);
+ NativeFuncs.godotsharp_dictionary_add(ref self, variantKey, variantValue);
+ }
+
+ /// <summary>
+ /// Checks if this <see cref="Dictionary{TKey, TValue}"/> 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 unsafe bool ContainsKey(TKey key)
+ {
+ using var variantKey = _convertKeyToVariantCallback(key);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ return NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool();
+ }
+
+ /// <summary>
+ /// Removes an element from this <see cref="Dictionary{TKey, TValue}"/> by key.
+ /// </summary>
+ /// <param name="key">The key of the element to remove.</param>
+ public unsafe bool Remove(TKey key)
+ {
+ using var variantKey = _convertKeyToVariantCallback(key);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ return NativeFuncs.godotsharp_dictionary_remove_key(ref self, variantKey).ToBool();
+ }
+
+ /// <summary>
+ /// Gets the object at the given <paramref name="key"/>.
+ /// </summary>
+ /// <param name="key">The key of the element to get.</param>
+ /// <param name="value">The value at the given <paramref name="key"/>.</param>
+ /// <returns>If an object was found for the given <paramref name="key"/>.</returns>
+ public unsafe bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
+ {
+ using var variantKey = _convertKeyToVariantCallback(key);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
+ variantKey, out godot_variant retValue).ToBool();
+
+ using (retValue)
+ value = found ? _convertValueToManagedCallback(retValue) : default;
+
+ return found;
+ }
+
+ // ICollection<KeyValuePair<TKey, TValue>>
+
+ /// <summary>
+ /// Returns the number of elements in this <see cref="Dictionary{TKey, TValue}"/>.
+ /// This is also known as the size or length of the dictionary.
+ /// </summary>
+ /// <returns>The number of elements.</returns>
+ public int Count => _underlyingDict.Count;
+
+ bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false;
+
+ void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
+ => Add(item.Key, item.Value);
+
+ /// <summary>
+ /// Erases all the items from this <see cref="Dictionary{TKey, TValue}"/>.
+ /// </summary>
+ public void Clear() => _underlyingDict.Clear();
+
+ unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
+ {
+ using var variantKey = _convertKeyToVariantCallback(item.Key);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
+ variantKey, out godot_variant retValue).ToBool();
+
+ using (retValue)
+ {
+ if (!found)
+ return false;
+
+ using var variantValue = _convertValueToVariantCallback(item.Value);
+ return NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool();
+ }
+ }
+
+ /// <summary>
+ /// Copies the elements of this <see cref="Dictionary{TKey, TValue}"/> to the given
+ /// untyped C# array, starting at the given index.
+ /// </summary>
+ /// <param name="array">The array to copy to.</param>
+ /// <param name="arrayIndex">The index to start at.</param>
+ public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
+ {
+ if (array == null)
+ throw new ArgumentNullException(nameof(array), "Value cannot be null.");
+
+ if (arrayIndex < 0)
+ throw new ArgumentOutOfRangeException(nameof(arrayIndex),
+ "Number was less than the array's lower bound in the first dimension.");
+
+ int count = 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] = GetKeyValuePair(i);
+ arrayIndex++;
+ }
+ }
+
+ unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
+ {
+ using var variantKey = _convertKeyToVariantCallback(item.Key);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
+ variantKey, out godot_variant retValue).ToBool();
+
+ using (retValue)
+ {
+ if (!found)
+ return false;
+
+ using var variantValue = _convertValueToVariantCallback(item.Value);
+ if (NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool())
+ {
+ return NativeFuncs.godotsharp_dictionary_remove_key(
+ ref self, variantKey).ToBool();
+ }
+
+ return false;
+ }
+ }
+
+ // IEnumerable<KeyValuePair<TKey, TValue>>
+
+ /// <summary>
+ /// Gets an enumerator for this <see cref="Dictionary{TKey, TValue}"/>.
+ /// </summary>
+ /// <returns>An enumerator.</returns>
+ public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
+ {
+ for (int i = 0; i < Count; i++)
+ {
+ yield return GetKeyValuePair(i);
+ }
+ }
+
+ 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() => _underlyingDict.ToString();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Dictionary<TKey, TValue> from) => Variant.CreateFrom(from);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Dictionary<TKey, TValue>(Variant from) => from.AsGodotDictionary<TKey, TValue>();
+ }
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs
new file mode 100644
index 0000000000..2b5bf2e142
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs
@@ -0,0 +1,976 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+namespace Godot.NativeInterop;
+
+internal static unsafe class VariantConversionCallbacks
+{
+ [SuppressMessage("ReSharper", "RedundantNameQualifier")]
+ internal static delegate* <in T, godot_variant> GetToVariantCallback<T>()
+ {
+ static godot_variant FromBool(in bool @bool) =>
+ VariantUtils.CreateFromBool(@bool);
+
+ static godot_variant FromChar(in char @char) =>
+ VariantUtils.CreateFromInt(@char);
+
+ static godot_variant FromInt8(in sbyte @int8) =>
+ VariantUtils.CreateFromInt(@int8);
+
+ static godot_variant FromInt16(in short @int16) =>
+ VariantUtils.CreateFromInt(@int16);
+
+ static godot_variant FromInt32(in int @int32) =>
+ VariantUtils.CreateFromInt(@int32);
+
+ static godot_variant FromInt64(in long @int64) =>
+ VariantUtils.CreateFromInt(@int64);
+
+ static godot_variant FromUInt8(in byte @uint8) =>
+ VariantUtils.CreateFromInt(@uint8);
+
+ static godot_variant FromUInt16(in ushort @uint16) =>
+ VariantUtils.CreateFromInt(@uint16);
+
+ static godot_variant FromUInt32(in uint @uint32) =>
+ VariantUtils.CreateFromInt(@uint32);
+
+ static godot_variant FromUInt64(in ulong @uint64) =>
+ VariantUtils.CreateFromInt(@uint64);
+
+ static godot_variant FromFloat(in float @float) =>
+ VariantUtils.CreateFromFloat(@float);
+
+ static godot_variant FromDouble(in double @double) =>
+ VariantUtils.CreateFromFloat(@double);
+
+ static godot_variant FromVector2(in Vector2 @vector2) =>
+ VariantUtils.CreateFromVector2(@vector2);
+
+ static godot_variant FromVector2I(in Vector2i vector2I) =>
+ VariantUtils.CreateFromVector2i(vector2I);
+
+ static godot_variant FromRect2(in Rect2 @rect2) =>
+ VariantUtils.CreateFromRect2(@rect2);
+
+ static godot_variant FromRect2I(in Rect2i rect2I) =>
+ VariantUtils.CreateFromRect2i(rect2I);
+
+ static godot_variant FromTransform2D(in Transform2D @transform2D) =>
+ VariantUtils.CreateFromTransform2D(@transform2D);
+
+ static godot_variant FromVector3(in Vector3 @vector3) =>
+ VariantUtils.CreateFromVector3(@vector3);
+
+ static godot_variant FromVector3I(in Vector3i vector3I) =>
+ VariantUtils.CreateFromVector3i(vector3I);
+
+ static godot_variant FromBasis(in Basis @basis) =>
+ VariantUtils.CreateFromBasis(@basis);
+
+ static godot_variant FromQuaternion(in Quaternion @quaternion) =>
+ VariantUtils.CreateFromQuaternion(@quaternion);
+
+ static godot_variant FromTransform3D(in Transform3D @transform3d) =>
+ VariantUtils.CreateFromTransform3D(@transform3d);
+
+ static godot_variant FromAabb(in AABB @aabb) =>
+ VariantUtils.CreateFromAABB(@aabb);
+
+ static godot_variant FromColor(in Color @color) =>
+ VariantUtils.CreateFromColor(@color);
+
+ static godot_variant FromPlane(in Plane @plane) =>
+ VariantUtils.CreateFromPlane(@plane);
+
+ static godot_variant FromCallable(in Callable @callable) =>
+ VariantUtils.CreateFromCallable(@callable);
+
+ static godot_variant FromSignalInfo(in SignalInfo @signalInfo) =>
+ VariantUtils.CreateFromSignalInfo(@signalInfo);
+
+ static godot_variant FromString(in string @string) =>
+ VariantUtils.CreateFromString(@string);
+
+ static godot_variant FromByteArray(in byte[] byteArray) =>
+ VariantUtils.CreateFromPackedByteArray(byteArray);
+
+ static godot_variant FromInt32Array(in int[] int32Array) =>
+ VariantUtils.CreateFromPackedInt32Array(int32Array);
+
+ static godot_variant FromInt64Array(in long[] int64Array) =>
+ VariantUtils.CreateFromPackedInt64Array(int64Array);
+
+ static godot_variant FromFloatArray(in float[] floatArray) =>
+ VariantUtils.CreateFromPackedFloat32Array(floatArray);
+
+ static godot_variant FromDoubleArray(in double[] doubleArray) =>
+ VariantUtils.CreateFromPackedFloat64Array(doubleArray);
+
+ static godot_variant FromStringArray(in string[] stringArray) =>
+ VariantUtils.CreateFromPackedStringArray(stringArray);
+
+ static godot_variant FromVector2Array(in Vector2[] vector2Array) =>
+ VariantUtils.CreateFromPackedVector2Array(vector2Array);
+
+ static godot_variant FromVector3Array(in Vector3[] vector3Array) =>
+ VariantUtils.CreateFromPackedVector3Array(vector3Array);
+
+ static godot_variant FromColorArray(in Color[] colorArray) =>
+ VariantUtils.CreateFromPackedColorArray(colorArray);
+
+ static godot_variant FromStringNameArray(in StringName[] stringNameArray) =>
+ VariantUtils.CreateFromSystemArrayOfStringName(stringNameArray);
+
+ static godot_variant FromNodePathArray(in NodePath[] nodePathArray) =>
+ VariantUtils.CreateFromSystemArrayOfNodePath(nodePathArray);
+
+ static godot_variant FromRidArray(in RID[] ridArray) =>
+ VariantUtils.CreateFromSystemArrayOfRID(ridArray);
+
+ static godot_variant FromGodotObject(in Godot.Object godotObject) =>
+ VariantUtils.CreateFromGodotObject(godotObject);
+
+ static godot_variant FromStringName(in StringName stringName) =>
+ VariantUtils.CreateFromStringName(stringName);
+
+ static godot_variant FromNodePath(in NodePath nodePath) =>
+ VariantUtils.CreateFromNodePath(nodePath);
+
+ static godot_variant FromRid(in RID rid) =>
+ VariantUtils.CreateFromRID(rid);
+
+ static godot_variant FromGodotDictionary(in Collections.Dictionary godotDictionary) =>
+ VariantUtils.CreateFromDictionary(godotDictionary);
+
+ static godot_variant FromGodotArray(in Collections.Array godotArray) =>
+ VariantUtils.CreateFromArray(godotArray);
+
+ static godot_variant FromVariant(in Variant variant) =>
+ NativeFuncs.godotsharp_variant_new_copy((godot_variant)variant.NativeVar);
+
+ var typeOfT = typeof(T);
+
+ if (typeOfT == typeof(bool))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in bool, godot_variant>)
+ &FromBool;
+ }
+
+ if (typeOfT == typeof(char))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in char, godot_variant>)
+ &FromChar;
+ }
+
+ if (typeOfT == typeof(sbyte))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in sbyte, godot_variant>)
+ &FromInt8;
+ }
+
+ if (typeOfT == typeof(short))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in short, godot_variant>)
+ &FromInt16;
+ }
+
+ if (typeOfT == typeof(int))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in int, godot_variant>)
+ &FromInt32;
+ }
+
+ if (typeOfT == typeof(long))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in long, godot_variant>)
+ &FromInt64;
+ }
+
+ if (typeOfT == typeof(byte))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in byte, godot_variant>)
+ &FromUInt8;
+ }
+
+ if (typeOfT == typeof(ushort))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in ushort, godot_variant>)
+ &FromUInt16;
+ }
+
+ if (typeOfT == typeof(uint))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in uint, godot_variant>)
+ &FromUInt32;
+ }
+
+ if (typeOfT == typeof(ulong))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in ulong, godot_variant>)
+ &FromUInt64;
+ }
+
+ if (typeOfT == typeof(float))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in float, godot_variant>)
+ &FromFloat;
+ }
+
+ if (typeOfT == typeof(double))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in double, godot_variant>)
+ &FromDouble;
+ }
+
+ if (typeOfT == typeof(Vector2))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Vector2, godot_variant>)
+ &FromVector2;
+ }
+
+ if (typeOfT == typeof(Vector2i))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Vector2i, godot_variant>)
+ &FromVector2I;
+ }
+
+ if (typeOfT == typeof(Rect2))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Rect2, godot_variant>)
+ &FromRect2;
+ }
+
+ if (typeOfT == typeof(Rect2i))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Rect2i, godot_variant>)
+ &FromRect2I;
+ }
+
+ if (typeOfT == typeof(Transform2D))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Transform2D, godot_variant>)
+ &FromTransform2D;
+ }
+
+ if (typeOfT == typeof(Vector3))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Vector3, godot_variant>)
+ &FromVector3;
+ }
+
+ if (typeOfT == typeof(Vector3i))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Vector3i, godot_variant>)
+ &FromVector3I;
+ }
+
+ if (typeOfT == typeof(Basis))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Basis, godot_variant>)
+ &FromBasis;
+ }
+
+ if (typeOfT == typeof(Quaternion))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Quaternion, godot_variant>)
+ &FromQuaternion;
+ }
+
+ if (typeOfT == typeof(Transform3D))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Transform3D, godot_variant>)
+ &FromTransform3D;
+ }
+
+ if (typeOfT == typeof(AABB))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in AABB, godot_variant>)
+ &FromAabb;
+ }
+
+ if (typeOfT == typeof(Color))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Color, godot_variant>)
+ &FromColor;
+ }
+
+ if (typeOfT == typeof(Plane))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Plane, godot_variant>)
+ &FromPlane;
+ }
+
+ if (typeOfT == typeof(Callable))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Callable, godot_variant>)
+ &FromCallable;
+ }
+
+ if (typeOfT == typeof(SignalInfo))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in SignalInfo, godot_variant>)
+ &FromSignalInfo;
+ }
+
+ if (typeOfT.IsEnum)
+ {
+ var enumUnderlyingType = typeOfT.GetEnumUnderlyingType();
+
+ switch (Type.GetTypeCode(enumUnderlyingType))
+ {
+ case TypeCode.SByte:
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in sbyte, godot_variant>)
+ &FromInt8;
+ }
+ case TypeCode.Int16:
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in short, godot_variant>)
+ &FromInt16;
+ }
+ case TypeCode.Int32:
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in int, godot_variant>)
+ &FromInt32;
+ }
+ case TypeCode.Int64:
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in long, godot_variant>)
+ &FromInt64;
+ }
+ case TypeCode.Byte:
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in byte, godot_variant>)
+ &FromUInt8;
+ }
+ case TypeCode.UInt16:
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in ushort, godot_variant>)
+ &FromUInt16;
+ }
+ case TypeCode.UInt32:
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in uint, godot_variant>)
+ &FromUInt32;
+ }
+ case TypeCode.UInt64:
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in ulong, godot_variant>)
+ &FromUInt64;
+ }
+ default:
+ return null;
+ }
+ }
+
+ if (typeOfT == typeof(string))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in string, godot_variant>)
+ &FromString;
+ }
+
+ if (typeOfT == typeof(byte[]))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in byte[], godot_variant>)
+ &FromByteArray;
+ }
+
+ if (typeOfT == typeof(int[]))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in int[], godot_variant>)
+ &FromInt32Array;
+ }
+
+ if (typeOfT == typeof(long[]))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in long[], godot_variant>)
+ &FromInt64Array;
+ }
+
+ if (typeOfT == typeof(float[]))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in float[], godot_variant>)
+ &FromFloatArray;
+ }
+
+ if (typeOfT == typeof(double[]))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in double[], godot_variant>)
+ &FromDoubleArray;
+ }
+
+ if (typeOfT == typeof(string[]))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in string[], godot_variant>)
+ &FromStringArray;
+ }
+
+ if (typeOfT == typeof(Vector2[]))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Vector2[], godot_variant>)
+ &FromVector2Array;
+ }
+
+ if (typeOfT == typeof(Vector3[]))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Vector3[], godot_variant>)
+ &FromVector3Array;
+ }
+
+ if (typeOfT == typeof(Color[]))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Color[], godot_variant>)
+ &FromColorArray;
+ }
+
+ if (typeOfT == typeof(StringName[]))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in StringName[], godot_variant>)
+ &FromStringNameArray;
+ }
+
+ if (typeOfT == typeof(NodePath[]))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in NodePath[], godot_variant>)
+ &FromNodePathArray;
+ }
+
+ if (typeOfT == typeof(RID[]))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in RID[], godot_variant>)
+ &FromRidArray;
+ }
+
+ if (typeof(Godot.Object).IsAssignableFrom(typeOfT))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Godot.Object, godot_variant>)
+ &FromGodotObject;
+ }
+
+ if (typeOfT == typeof(StringName))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in StringName, godot_variant>)
+ &FromStringName;
+ }
+
+ if (typeOfT == typeof(NodePath))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in NodePath, godot_variant>)
+ &FromNodePath;
+ }
+
+ if (typeOfT == typeof(RID))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in RID, godot_variant>)
+ &FromRid;
+ }
+
+ if (typeOfT == typeof(Godot.Collections.Dictionary))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Godot.Collections.Dictionary, godot_variant>)
+ &FromGodotDictionary;
+ }
+
+ if (typeOfT == typeof(Godot.Collections.Array))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Godot.Collections.Array, godot_variant>)
+ &FromGodotArray;
+ }
+
+ if (typeOfT == typeof(Variant))
+ {
+ return (delegate* <in T, godot_variant>)(delegate* <in Variant, godot_variant>)
+ &FromVariant;
+ }
+
+ return null;
+ }
+
+ [SuppressMessage("ReSharper", "RedundantNameQualifier")]
+ internal static delegate* <in godot_variant, T> GetToManagedCallback<T>()
+ {
+ static bool ToBool(in godot_variant variant) =>
+ VariantUtils.ConvertToBool(variant);
+
+ static char ToChar(in godot_variant variant) =>
+ VariantUtils.ConvertToChar(variant);
+
+ static sbyte ToInt8(in godot_variant variant) =>
+ VariantUtils.ConvertToInt8(variant);
+
+ static short ToInt16(in godot_variant variant) =>
+ VariantUtils.ConvertToInt16(variant);
+
+ static int ToInt32(in godot_variant variant) =>
+ VariantUtils.ConvertToInt32(variant);
+
+ static long ToInt64(in godot_variant variant) =>
+ VariantUtils.ConvertToInt64(variant);
+
+ static byte ToUInt8(in godot_variant variant) =>
+ VariantUtils.ConvertToUInt8(variant);
+
+ static ushort ToUInt16(in godot_variant variant) =>
+ VariantUtils.ConvertToUInt16(variant);
+
+ static uint ToUInt32(in godot_variant variant) =>
+ VariantUtils.ConvertToUInt32(variant);
+
+ static ulong ToUInt64(in godot_variant variant) =>
+ VariantUtils.ConvertToUInt64(variant);
+
+ static float ToFloat(in godot_variant variant) =>
+ VariantUtils.ConvertToFloat32(variant);
+
+ static double ToDouble(in godot_variant variant) =>
+ VariantUtils.ConvertToFloat64(variant);
+
+ static Vector2 ToVector2(in godot_variant variant) =>
+ VariantUtils.ConvertToVector2(variant);
+
+ static Vector2i ToVector2I(in godot_variant variant) =>
+ VariantUtils.ConvertToVector2i(variant);
+
+ static Rect2 ToRect2(in godot_variant variant) =>
+ VariantUtils.ConvertToRect2(variant);
+
+ static Rect2i ToRect2I(in godot_variant variant) =>
+ VariantUtils.ConvertToRect2i(variant);
+
+ static Transform2D ToTransform2D(in godot_variant variant) =>
+ VariantUtils.ConvertToTransform2D(variant);
+
+ static Vector3 ToVector3(in godot_variant variant) =>
+ VariantUtils.ConvertToVector3(variant);
+
+ static Vector3i ToVector3I(in godot_variant variant) =>
+ VariantUtils.ConvertToVector3i(variant);
+
+ static Basis ToBasis(in godot_variant variant) =>
+ VariantUtils.ConvertToBasis(variant);
+
+ static Quaternion ToQuaternion(in godot_variant variant) =>
+ VariantUtils.ConvertToQuaternion(variant);
+
+ static Transform3D ToTransform3D(in godot_variant variant) =>
+ VariantUtils.ConvertToTransform3D(variant);
+
+ static AABB ToAabb(in godot_variant variant) =>
+ VariantUtils.ConvertToAABB(variant);
+
+ static Color ToColor(in godot_variant variant) =>
+ VariantUtils.ConvertToColor(variant);
+
+ static Plane ToPlane(in godot_variant variant) =>
+ VariantUtils.ConvertToPlane(variant);
+
+ static Callable ToCallable(in godot_variant variant) =>
+ VariantUtils.ConvertToCallableManaged(variant);
+
+ static SignalInfo ToSignalInfo(in godot_variant variant) =>
+ VariantUtils.ConvertToSignalInfo(variant);
+
+ static string ToString(in godot_variant variant) =>
+ VariantUtils.ConvertToStringObject(variant);
+
+ static byte[] ToByteArray(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedByteArrayToSystemArray(variant);
+
+ static int[] ToInt32Array(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedInt32ArrayToSystemArray(variant);
+
+ static long[] ToInt64Array(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedInt64ArrayToSystemArray(variant);
+
+ static float[] ToFloatArray(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedFloat32ArrayToSystemArray(variant);
+
+ static double[] ToDoubleArray(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedFloat64ArrayToSystemArray(variant);
+
+ static string[] ToStringArray(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedStringArrayToSystemArray(variant);
+
+ static Vector2[] ToVector2Array(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedVector2ArrayToSystemArray(variant);
+
+ static Vector3[] ToVector3Array(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedVector3ArrayToSystemArray(variant);
+
+ static Color[] ToColorArray(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedColorArrayToSystemArray(variant);
+
+ static StringName[] ToStringNameArray(in godot_variant variant) =>
+ VariantUtils.ConvertToSystemArrayOfStringName(variant);
+
+ static NodePath[] ToNodePathArray(in godot_variant variant) =>
+ VariantUtils.ConvertToSystemArrayOfNodePath(variant);
+
+ static RID[] ToRidArray(in godot_variant variant) =>
+ VariantUtils.ConvertToSystemArrayOfRID(variant);
+
+ static Godot.Object ToGodotObject(in godot_variant variant) =>
+ VariantUtils.ConvertToGodotObject(variant);
+
+ static StringName ToStringName(in godot_variant variant) =>
+ VariantUtils.ConvertToStringNameObject(variant);
+
+ static NodePath ToNodePath(in godot_variant variant) =>
+ VariantUtils.ConvertToNodePathObject(variant);
+
+ static RID ToRid(in godot_variant variant) =>
+ VariantUtils.ConvertToRID(variant);
+
+ static Collections.Dictionary ToGodotDictionary(in godot_variant variant) =>
+ VariantUtils.ConvertToDictionaryObject(variant);
+
+ static Collections.Array ToGodotArray(in godot_variant variant) =>
+ VariantUtils.ConvertToArrayObject(variant);
+
+ static Variant ToVariant(in godot_variant variant) =>
+ Variant.CreateCopyingBorrowed(variant);
+
+ var typeOfT = typeof(T);
+
+ // ReSharper disable RedundantCast
+ // Rider is being stupid here. These casts are definitely needed. We get build errors without them.
+
+ if (typeOfT == typeof(bool))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, bool>)
+ &ToBool;
+ }
+
+ if (typeOfT == typeof(char))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, char>)
+ &ToChar;
+ }
+
+ if (typeOfT == typeof(sbyte))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, sbyte>)
+ &ToInt8;
+ }
+
+ if (typeOfT == typeof(short))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, short>)
+ &ToInt16;
+ }
+
+ if (typeOfT == typeof(int))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, int>)
+ &ToInt32;
+ }
+
+ if (typeOfT == typeof(long))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, long>)
+ &ToInt64;
+ }
+
+ if (typeOfT == typeof(byte))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, byte>)
+ &ToUInt8;
+ }
+
+ if (typeOfT == typeof(ushort))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, ushort>)
+ &ToUInt16;
+ }
+
+ if (typeOfT == typeof(uint))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, uint>)
+ &ToUInt32;
+ }
+
+ if (typeOfT == typeof(ulong))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, ulong>)
+ &ToUInt64;
+ }
+
+ if (typeOfT == typeof(float))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, float>)
+ &ToFloat;
+ }
+
+ if (typeOfT == typeof(double))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, double>)
+ &ToDouble;
+ }
+
+ if (typeOfT == typeof(Vector2))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Vector2>)
+ &ToVector2;
+ }
+
+ if (typeOfT == typeof(Vector2i))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Vector2i>)
+ &ToVector2I;
+ }
+
+ if (typeOfT == typeof(Rect2))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Rect2>)
+ &ToRect2;
+ }
+
+ if (typeOfT == typeof(Rect2i))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Rect2i>)
+ &ToRect2I;
+ }
+
+ if (typeOfT == typeof(Transform2D))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Transform2D>)
+ &ToTransform2D;
+ }
+
+ if (typeOfT == typeof(Vector3))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Vector3>)
+ &ToVector3;
+ }
+
+ if (typeOfT == typeof(Vector3i))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Vector3i>)
+ &ToVector3I;
+ }
+
+ if (typeOfT == typeof(Basis))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Basis>)
+ &ToBasis;
+ }
+
+ if (typeOfT == typeof(Quaternion))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Quaternion>)
+ &ToQuaternion;
+ }
+
+ if (typeOfT == typeof(Transform3D))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Transform3D>)
+ &ToTransform3D;
+ }
+
+ if (typeOfT == typeof(AABB))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, AABB>)
+ &ToAabb;
+ }
+
+ if (typeOfT == typeof(Color))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Color>)
+ &ToColor;
+ }
+
+ if (typeOfT == typeof(Plane))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Plane>)
+ &ToPlane;
+ }
+
+ if (typeOfT == typeof(Callable))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Callable>)
+ &ToCallable;
+ }
+
+ if (typeOfT == typeof(SignalInfo))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, SignalInfo>)
+ &ToSignalInfo;
+ }
+
+ if (typeOfT.IsEnum)
+ {
+ var enumUnderlyingType = typeOfT.GetEnumUnderlyingType();
+
+ switch (Type.GetTypeCode(enumUnderlyingType))
+ {
+ case TypeCode.SByte:
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, sbyte>)
+ &ToInt8;
+ }
+ case TypeCode.Int16:
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, short>)
+ &ToInt16;
+ }
+ case TypeCode.Int32:
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, int>)
+ &ToInt32;
+ }
+ case TypeCode.Int64:
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, long>)
+ &ToInt64;
+ }
+ case TypeCode.Byte:
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, byte>)
+ &ToUInt8;
+ }
+ case TypeCode.UInt16:
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, ushort>)
+ &ToUInt16;
+ }
+ case TypeCode.UInt32:
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, uint>)
+ &ToUInt32;
+ }
+ case TypeCode.UInt64:
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, ulong>)
+ &ToUInt64;
+ }
+ default:
+ return null;
+ }
+ }
+
+ if (typeOfT == typeof(string))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, string>)
+ &ToString;
+ }
+
+ if (typeOfT == typeof(byte[]))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, byte[]>)
+ &ToByteArray;
+ }
+
+ if (typeOfT == typeof(int[]))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, int[]>)
+ &ToInt32Array;
+ }
+
+ if (typeOfT == typeof(long[]))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, long[]>)
+ &ToInt64Array;
+ }
+
+ if (typeOfT == typeof(float[]))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, float[]>)
+ &ToFloatArray;
+ }
+
+ if (typeOfT == typeof(double[]))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, double[]>)
+ &ToDoubleArray;
+ }
+
+ if (typeOfT == typeof(string[]))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, string[]>)
+ &ToStringArray;
+ }
+
+ if (typeOfT == typeof(Vector2[]))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Vector2[]>)
+ &ToVector2Array;
+ }
+
+ if (typeOfT == typeof(Vector3[]))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Vector3[]>)
+ &ToVector3Array;
+ }
+
+ if (typeOfT == typeof(Color[]))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Color[]>)
+ &ToColorArray;
+ }
+
+ if (typeOfT == typeof(StringName[]))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, StringName[]>)
+ &ToStringNameArray;
+ }
+
+ if (typeOfT == typeof(NodePath[]))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, NodePath[]>)
+ &ToNodePathArray;
+ }
+
+ if (typeOfT == typeof(RID[]))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, RID[]>)
+ &ToRidArray;
+ }
+
+ if (typeof(Godot.Object).IsAssignableFrom(typeOfT))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Godot.Object>)
+ &ToGodotObject;
+ }
+
+ if (typeOfT == typeof(StringName))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, StringName>)
+ &ToStringName;
+ }
+
+ if (typeOfT == typeof(NodePath))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, NodePath>)
+ &ToNodePath;
+ }
+
+ if (typeOfT == typeof(RID))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, RID>)
+ &ToRid;
+ }
+
+ if (typeOfT == typeof(Godot.Collections.Dictionary))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Godot.Collections.Dictionary>)
+ &ToGodotDictionary;
+ }
+
+ if (typeOfT == typeof(Godot.Collections.Array))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Godot.Collections.Array>)
+ &ToGodotArray;
+ }
+
+ if (typeOfT == typeof(Variant))
+ {
+ return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, Variant>)
+ &ToVariant;
+ }
+
+ // ReSharper restore RedundantCast
+
+ return null;
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
index 1ce8965939..491ccf904e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
@@ -238,6 +238,10 @@ namespace Godot.NativeInterop
public static godot_variant CreateFromArray(Collections.Array? from)
=> from != null ? CreateFromArray((godot_array)from.NativeValue) : default;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromArray<T>(Array<T>? from)
+ => from != null ? CreateFromArray((godot_array)((Collections.Array)from).NativeValue) : default;
+
public static godot_variant CreateFromDictionary(godot_dictionary from)
{
NativeFuncs.godotsharp_variant_new_dictionary(out godot_variant ret, from);
@@ -248,6 +252,10 @@ namespace Godot.NativeInterop
public static godot_variant CreateFromDictionary(Dictionary? from)
=> from != null ? CreateFromDictionary((godot_dictionary)from.NativeValue) : default;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromDictionary<TKey, TValue>(Dictionary<TKey, TValue>? from)
+ => from != null ? CreateFromDictionary((godot_dictionary)((Dictionary)from).NativeValue) : default;
+
public static godot_variant CreateFromStringName(godot_string_name from)
{
NativeFuncs.godotsharp_variant_new_string_name(out godot_variant ret, from);
@@ -496,6 +504,10 @@ namespace Godot.NativeInterop
public static Collections.Array ConvertToArrayObject(in godot_variant p_var)
=> Collections.Array.CreateTakingOwnershipOfDisposableValue(ConvertToArray(p_var));
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Array<T> ConvertToArrayObject<T>(in godot_variant p_var)
+ => Array<T>.CreateTakingOwnershipOfDisposableValue(ConvertToArray(p_var));
+
public static godot_dictionary ConvertToDictionary(in godot_variant p_var)
=> p_var.Type == Variant.Type.Dictionary ?
NativeFuncs.godotsharp_dictionary_new_copy(p_var.Dictionary) :
@@ -505,6 +517,10 @@ namespace Godot.NativeInterop
public static Dictionary ConvertToDictionaryObject(in godot_variant p_var)
=> Dictionary.CreateTakingOwnershipOfDisposableValue(ConvertToDictionary(p_var));
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Dictionary<TKey, TValue> ConvertToDictionaryObject<TKey, TValue>(in godot_variant p_var)
+ => Dictionary<TKey, TValue>.CreateTakingOwnershipOfDisposableValue(ConvertToDictionary(p_var));
+
public static byte[] ConvertAsPackedByteArrayToSystemArray(in godot_variant p_var)
{
using var packedArray = NativeFuncs.godotsharp_variant_as_packed_byte_array(p_var);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index d1ff6ade8a..c7881c7404 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -94,6 +94,7 @@
<Compile Include="Core\NativeInterop\InteropUtils.cs" />
<Compile Include="Core\NativeInterop\NativeFuncs.extended.cs" />
<Compile Include="Core\NativeInterop\NativeVariantPtrArgs.cs" />
+ <Compile Include="Core\NativeInterop\VariantConversionCallbacks.cs" />
<Compile Include="Core\NativeInterop\VariantSpanHelpers.cs" />
<Compile Include="Core\NativeInterop\VariantUtils.cs" />
<Compile Include="Core\NodePath.cs" />
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs b/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs
index 7c4df291ac..eb8b061120 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs
@@ -284,6 +284,14 @@ public partial struct Variant : IDisposable
VariantUtils.ConvertToSystemArrayOfGodotObject<T>((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Collections.Dictionary<TKey, TValue> AsGodotDictionary<TKey, TValue>() =>
+ VariantUtils.ConvertToDictionaryObject<TKey, TValue>((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Collections.Array<T> AsGodotArray<T>() =>
+ VariantUtils.ConvertToArrayObject<T>((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public StringName[] AsSystemArrayOfStringName() =>
VariantUtils.ConvertToSystemArrayOfStringName((godot_variant)NativeVar);
@@ -595,6 +603,14 @@ public partial struct Variant : IDisposable
public static Variant CreateFrom(Godot.Object[] from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom<TKey, TValue>(Collections.Dictionary<TKey, TValue> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromDictionary(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom<T>(Collections.Array<T> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromArray(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Variant CreateFrom(Span<StringName> from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]