added base helpers and a simple test.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Godot.NET.Sdk/4.6.2">
|
<Project Sdk="Godot.NET.Sdk/4.6.2">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<ImplicitUsings>disable</ImplicitUsings>
|
<ImplicitUsings>disable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||||
|
|||||||
34
GodotHelper.Tests/test/src/MyNodeExtensionsTest.cs
Normal file
34
GodotHelper.Tests/test/src/MyNodeExtensionsTest.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
namespace GodotHelper.Tests;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Chickensoft.GoDotTest;
|
||||||
|
using Godot;
|
||||||
|
using GodotHelpers;
|
||||||
|
using Shouldly;
|
||||||
|
|
||||||
|
public class MyNodeExtensionsTest : TestClass
|
||||||
|
{
|
||||||
|
public MyNodeExtensionsTest(Node testScene) : base(testScene) { }
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task FreeDeferred()
|
||||||
|
{
|
||||||
|
var test = new Node();
|
||||||
|
var freeDeferred = new Node();
|
||||||
|
TestScene.AddChild(test);
|
||||||
|
test.AddChild(freeDeferred);
|
||||||
|
var tree = TestScene.GetTree();
|
||||||
|
await tree.ToSignal(tree, SceneTree.SignalName.ProcessFrame);
|
||||||
|
|
||||||
|
// Console.Write(test.GetChildCount());
|
||||||
|
freeDeferred.FreeDeferred();
|
||||||
|
|
||||||
|
test.GetChildCount().ShouldBe(1);
|
||||||
|
|
||||||
|
await tree.ToSignal(tree, SceneTree.SignalName.ProcessFrame);
|
||||||
|
test.GetChildCount().ShouldBe(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||||
<LangVersion>preview</LangVersion>
|
<LangVersion>preview</LangVersion>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
@@ -48,5 +48,6 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="GodotSharp" Version="4.6.2" />
|
<PackageReference Include="GodotSharp" Version="4.6.2" />
|
||||||
|
<PackageReference Include="SjkScripts" Version="1.0.15" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
24
GodotHelper/src/Math/LerpVectors.cs
Normal file
24
GodotHelper/src/Math/LerpVectors.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
namespace GodotHelpers;
|
||||||
|
|
||||||
|
using Godot;
|
||||||
|
public static partial class SJKMath
|
||||||
|
{
|
||||||
|
// public static Vector3I Lerp(Vector3I from, Vector3I to, float weight) => new Vector3I(
|
||||||
|
// Mathf.Lerp(from.X, to.X, weight),
|
||||||
|
// Mathf.Lerp(from.Y, to.Y, weight),
|
||||||
|
// Mathf.Lerp(from.Z, to.Z, weight)
|
||||||
|
// );
|
||||||
|
public static Vector3 Lerp(Vector3 from, Vector3 to, float weight) => new Vector3(
|
||||||
|
Mathf.Lerp(from.X, to.X, weight),
|
||||||
|
Mathf.Lerp(from.Y, to.Y, weight),
|
||||||
|
Mathf.Lerp(from.Z, to.Z, weight)
|
||||||
|
);
|
||||||
|
// public static Vector2I Lerp(Vector2I from, Vector2I to, float weight) => new Vector2I(
|
||||||
|
// Mathf.Lerp(from.X, to.X, weight),
|
||||||
|
// Mathf.Lerp(from.Y, to.Y, weight)
|
||||||
|
// );
|
||||||
|
public static Vector2 Lerp(Vector2 from, Vector2 to, float weight) => new Vector2(
|
||||||
|
Mathf.Lerp(from.X, to.X, weight),
|
||||||
|
Mathf.Lerp(from.Y, to.Y, weight)
|
||||||
|
);
|
||||||
|
}
|
||||||
46
GodotHelper/src/MyNodeExtensions.cs
Normal file
46
GodotHelper/src/MyNodeExtensions.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
namespace GodotHelpers;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
|
||||||
|
public static class MyNodeExtensions
|
||||||
|
{
|
||||||
|
public static void FreeDeferred(this Node node) => node.CallDeferred(GodotObject.MethodName.Free);
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if given Property exists on <c>Base</c>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Base">Current <c>GodotObject</c></param>
|
||||||
|
/// <param name="PropertyName">Property Name</param>
|
||||||
|
/// <returns><c>bool</c> true if given property exists on Base</returns>
|
||||||
|
public static bool HasProperty(this GodotObject Base, string PropertyName)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Returns the object's property list as an Godot.Collections.Array of dictionaries.
|
||||||
|
Each Godot.Collections.Dictionary contains the following entries:
|
||||||
|
- name is the property's name, as a string;
|
||||||
|
- class_name is an empty StringName, unless the property is Variant.Type.Object and it inherits from a class;
|
||||||
|
- type is the property's type, as an int (see Variant.Type);
|
||||||
|
- hint is how the property is meant to be edited (see PropertyHint);
|
||||||
|
- hint_string depends on the hint (see PropertyHint);
|
||||||
|
- usage is a combination of PropertyUsageFlags.
|
||||||
|
*/
|
||||||
|
foreach (var Property in Base.GetPropertyListEx())
|
||||||
|
{
|
||||||
|
if (Property.Name == PropertyName)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public static (Node node, Resource resource, NodePath remaining) GetNodeAndResourceEx(this Node self, NodePath path)
|
||||||
|
{
|
||||||
|
var result = self.GetNodeAndResource(path);
|
||||||
|
return ((Node)result[0], (Resource)result[1], (NodePath)result[2]);
|
||||||
|
}
|
||||||
|
public static void QueueFreeChildren(this Node node) => node.GetChildren().ToList().ForEach(item => item.QueueFree());
|
||||||
|
public static void QueueFreeChildren(this Node node, Func<Node, bool> predicate) => node.GetChildren().Where(predicate).ToList().ForEach(item => item.QueueFree());
|
||||||
|
}
|
||||||
10
GodotHelper/src/Raycasts/CollisionResultBase.cs
Normal file
10
GodotHelper/src/Raycasts/CollisionResultBase.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace GodotHelpers.Raycasts;
|
||||||
|
|
||||||
|
public record CollisionResultBase(
|
||||||
|
GodotObject Collider,
|
||||||
|
int ColliderId,
|
||||||
|
Rid Rid,
|
||||||
|
int Shape
|
||||||
|
);
|
||||||
10
GodotHelper/src/Raycasts/PointQueryResult2D.cs
Normal file
10
GodotHelper/src/Raycasts/PointQueryResult2D.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace GodotHelpers.Raycasts;
|
||||||
|
|
||||||
|
public record PointQueryResult2D(
|
||||||
|
GodotObject Collider,
|
||||||
|
int ColliderId,
|
||||||
|
Rid Rid,
|
||||||
|
int Shape
|
||||||
|
) : CollisionResultBase(Collider, ColliderId, Rid, Shape);
|
||||||
10
GodotHelper/src/Raycasts/PointQueryResult3D.cs
Normal file
10
GodotHelper/src/Raycasts/PointQueryResult3D.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace GodotHelpers.Raycasts;
|
||||||
|
|
||||||
|
public record PointQueryResult3D(
|
||||||
|
GodotObject Collider,
|
||||||
|
int ColliderId,
|
||||||
|
Rid Rid,
|
||||||
|
int Shape
|
||||||
|
) : CollisionResultBase(Collider, ColliderId, Rid, Shape);
|
||||||
119
GodotHelper/src/Raycasts/RaycastExtensions.cs
Normal file
119
GodotHelper/src/Raycasts/RaycastExtensions.cs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Godot;
|
||||||
|
using Godot.Collections;
|
||||||
|
using SJK.Functional;
|
||||||
|
|
||||||
|
namespace GodotHelpers.Raycasts;
|
||||||
|
|
||||||
|
|
||||||
|
public static class RaycastExtensions
|
||||||
|
{
|
||||||
|
// --- 3D ---
|
||||||
|
|
||||||
|
public static RaycastResult3D? RaycastEx(this PhysicsDirectSpaceState3D space, Vector3 from, Vector3 to, uint collisionMask = uint.MaxValue, Rid[]? exclude = null, bool hitFromInside = false)
|
||||||
|
{
|
||||||
|
var query = new PhysicsRayQueryParameters3D
|
||||||
|
{
|
||||||
|
From = from,
|
||||||
|
To = to,
|
||||||
|
CollisionMask = collisionMask,
|
||||||
|
HitFromInside = hitFromInside,
|
||||||
|
};
|
||||||
|
if (exclude != null)
|
||||||
|
query.Exclude = new Array<Rid>(exclude);
|
||||||
|
|
||||||
|
var result = space.IntersectRay(query);
|
||||||
|
if (result.Count == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new RaycastResult3D(
|
||||||
|
Collider: result["collider"].AsGodotObject(),
|
||||||
|
ColliderId: result["collider_id"].AsInt32(),
|
||||||
|
Rid: (Rid)result["rid"],
|
||||||
|
Shape: result["shape"].AsInt32(),
|
||||||
|
Position: result["position"].AsVector3(),
|
||||||
|
Normal: result["normal"].AsVector3()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool RaycastHitEx(this PhysicsDirectSpaceState3D space, Vector3 from, Vector3 to, [NotNullWhen(true)] out RaycastResult3D hit, uint collisionMask = uint.MaxValue, Rid[]? exclude = null, bool hitFromInside = false)
|
||||||
|
{
|
||||||
|
hit = space.RaycastEx(from, to, collisionMask, exclude, hitFromInside)!;
|
||||||
|
return hit is not null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 2D ---
|
||||||
|
|
||||||
|
public static RaycastResult2D? RaycastEx(this PhysicsDirectSpaceState2D space, Vector2 from, Vector2 to, uint collisionMask = uint.MaxValue, Rid[]? exclude = null, bool hitFromInside = false)
|
||||||
|
{
|
||||||
|
var query = new PhysicsRayQueryParameters2D
|
||||||
|
{
|
||||||
|
From = from,
|
||||||
|
To = to,
|
||||||
|
CollisionMask = collisionMask,
|
||||||
|
HitFromInside = hitFromInside,
|
||||||
|
};
|
||||||
|
if (exclude != null)
|
||||||
|
query.Exclude = new Array<Rid>(exclude);
|
||||||
|
|
||||||
|
var result = space.IntersectRay(query);
|
||||||
|
if (result.Count == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new RaycastResult2D(
|
||||||
|
Collider: result["collider"].AsGodotObject(),
|
||||||
|
ColliderId: result["collider_id"].AsInt32(),
|
||||||
|
Rid: (Rid)result["rid"],
|
||||||
|
Shape: result["shape"].AsInt32(),
|
||||||
|
Position: result["position"].AsVector2(),
|
||||||
|
Normal: result["normal"].AsVector2()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
public static IOption<RaycastResult2D> RaycastOptionEx(this PhysicsDirectSpaceState2D space, Vector2 from, Vector2 to, uint collisionMask = uint.MaxValue, Rid[]? exclude = null, bool hitFromInside = false)
|
||||||
|
=> RaycastEx(space, from, to, collisionMask, exclude, hitFromInside).ToOption();
|
||||||
|
|
||||||
|
|
||||||
|
public static bool RaycastHitEx(this PhysicsDirectSpaceState2D space, Vector2 from, Vector2 to, out RaycastResult2D hit, uint collisionMask = uint.MaxValue, Rid[]? exclude = null, bool hitFromInside = false)
|
||||||
|
{
|
||||||
|
hit = space.RaycastEx(from, to, collisionMask, exclude, hitFromInside)!;
|
||||||
|
return hit is not null;
|
||||||
|
}
|
||||||
|
// 3D Shape Cast
|
||||||
|
public static List<CollisionResultBase> IntersectShapeEx(this PhysicsDirectSpaceState3D space, PhysicsShapeQueryParameters3D query, int maxResults = 32)
|
||||||
|
{
|
||||||
|
var results = space.IntersectShape(query, maxResults);
|
||||||
|
var list = new List<CollisionResultBase>(results.Count);
|
||||||
|
|
||||||
|
foreach (var dict in results)
|
||||||
|
{
|
||||||
|
list.Add(new CollisionResultBase(
|
||||||
|
Collider: dict["collider"].AsGodotObject(),
|
||||||
|
ColliderId: dict["collider_id"].AsInt32(),
|
||||||
|
Rid: (Rid)dict["rid"],
|
||||||
|
Shape: dict["shape"].AsInt32()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2D Shape Cast
|
||||||
|
public static List<CollisionResultBase> IntersectShapeEx(this PhysicsDirectSpaceState2D space, PhysicsShapeQueryParameters2D query, int maxResults = 32)
|
||||||
|
{
|
||||||
|
var results = space.IntersectShape(query, maxResults);
|
||||||
|
var list = new List<CollisionResultBase>(results.Count);
|
||||||
|
|
||||||
|
foreach (var dict in results)
|
||||||
|
{
|
||||||
|
list.Add(new CollisionResultBase(
|
||||||
|
Collider: dict["collider"].AsGodotObject(),
|
||||||
|
ColliderId: dict["collider_id"].AsInt32(),
|
||||||
|
Rid: (Rid)dict["rid"],
|
||||||
|
Shape: dict["shape"].AsInt32()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
GodotHelper/src/Raycasts/RaycastResult2D.cs
Normal file
12
GodotHelper/src/Raycasts/RaycastResult2D.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace GodotHelpers.Raycasts;
|
||||||
|
|
||||||
|
public record RaycastResult2D(
|
||||||
|
GodotObject Collider,
|
||||||
|
int ColliderId,
|
||||||
|
Rid Rid,
|
||||||
|
int Shape,
|
||||||
|
Vector2 Position,
|
||||||
|
Vector2 Normal
|
||||||
|
) : CollisionResultBase(Collider, ColliderId, Rid, Shape);
|
||||||
12
GodotHelper/src/Raycasts/RaycastResult3D.cs
Normal file
12
GodotHelper/src/Raycasts/RaycastResult3D.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace GodotHelpers.Raycasts;
|
||||||
|
|
||||||
|
public record RaycastResult3D(
|
||||||
|
GodotObject Collider,
|
||||||
|
int ColliderId,
|
||||||
|
Rid Rid,
|
||||||
|
int Shape,
|
||||||
|
Vector3 Position,
|
||||||
|
Vector3 Normal
|
||||||
|
) : CollisionResultBase(Collider, ColliderId, Rid, Shape);
|
||||||
13
GodotHelper/src/Raycasts/ShapeCastResult2D.cs
Normal file
13
GodotHelper/src/Raycasts/ShapeCastResult2D.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace GodotHelpers.Raycasts;
|
||||||
|
|
||||||
|
public record ShapeCastResult2D(
|
||||||
|
GodotObject Collider,
|
||||||
|
int ColliderId,
|
||||||
|
Rid Rid,
|
||||||
|
int Shape,
|
||||||
|
Vector2 Point,
|
||||||
|
Vector2 Normal,
|
||||||
|
int CollisionCount
|
||||||
|
) : CollisionResultBase(Collider, ColliderId, Rid, Shape);
|
||||||
13
GodotHelper/src/Raycasts/ShapeCastResult3D.cs
Normal file
13
GodotHelper/src/Raycasts/ShapeCastResult3D.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace GodotHelpers.Raycasts;
|
||||||
|
|
||||||
|
public record ShapeCastResult3D(
|
||||||
|
GodotObject Collider,
|
||||||
|
int ColliderId,
|
||||||
|
Rid Rid,
|
||||||
|
int Shape,
|
||||||
|
Vector3 Point,
|
||||||
|
Vector3 Normal,
|
||||||
|
int CollisionCount
|
||||||
|
) : CollisionResultBase(Collider, ColliderId, Rid, Shape);
|
||||||
126
GodotHelper/src/Reflector.cs
Normal file
126
GodotHelper/src/Reflector.cs
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
namespace GodotHelpers;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Godot;
|
||||||
|
using Godot.Collections;
|
||||||
|
using Array = Godot.Collections.Array;
|
||||||
|
/// <summary>
|
||||||
|
/// Strong‑typed view of Godot's get_method_list / get_property_list output.
|
||||||
|
/// </summary>
|
||||||
|
public static class Reflector
|
||||||
|
{
|
||||||
|
/* ──────────── Typed records ──────────── */
|
||||||
|
|
||||||
|
public readonly record struct ArgInfo(
|
||||||
|
string Name,
|
||||||
|
Variant.Type Type,
|
||||||
|
PropertyHint Hint,
|
||||||
|
string HintString,
|
||||||
|
Variant DefaultValue);
|
||||||
|
|
||||||
|
public readonly record struct MethodInfoEx(
|
||||||
|
string Name,
|
||||||
|
IReadOnlyList<ArgInfo> Args,
|
||||||
|
IReadOnlyList<Variant> DefaultArgs,
|
||||||
|
MethodFlags Flags,
|
||||||
|
int Id,
|
||||||
|
ArgInfo? ReturnValue);
|
||||||
|
|
||||||
|
public readonly record struct PropertyInfoEx(
|
||||||
|
string Name,
|
||||||
|
string ClassName,
|
||||||
|
Variant.Type Type,
|
||||||
|
PropertyHint Hint,
|
||||||
|
string HintString,
|
||||||
|
PropertyUsageFlags Usage);
|
||||||
|
|
||||||
|
/* ──────────── Public helpers ──────────── */
|
||||||
|
|
||||||
|
public static List<MethodInfoEx> GetMethodsListEx(this GodotObject godotObject) => GetMethods(godotObject);
|
||||||
|
public static List<MethodInfoEx> GetMethods(GodotObject obj)
|
||||||
|
{
|
||||||
|
var raw = obj.GetMethodList();
|
||||||
|
var list = new List<MethodInfoEx>(raw.Count);
|
||||||
|
|
||||||
|
foreach (Dictionary dict in raw)
|
||||||
|
{
|
||||||
|
// — Parse args —
|
||||||
|
var argsRaw = (Array)dict["args"];
|
||||||
|
var args = new List<ArgInfo>(argsRaw.Count);
|
||||||
|
foreach (Dictionary a in argsRaw)
|
||||||
|
args.Add(ParseArg(a));
|
||||||
|
|
||||||
|
// — Parse return (may be empty) —
|
||||||
|
ArgInfo? ret = null;
|
||||||
|
if (dict.TryGetValue("return", out var retRaw) && retRaw.AsGodotDictionary() is Dictionary rd && rd.Count > 0)
|
||||||
|
ret = ParseArg(rd);
|
||||||
|
|
||||||
|
list.Add(new MethodInfoEx(
|
||||||
|
Name: (string)dict["name"],
|
||||||
|
Args: args,
|
||||||
|
DefaultArgs: (Array)dict["default_args"],
|
||||||
|
Flags: (MethodFlags)(int)dict["flags"],
|
||||||
|
Id: (int)dict["id"],
|
||||||
|
ReturnValue: ret
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
public static bool TryGetMethodInfo(this GodotObject godotObject, string property, out MethodInfoEx info)
|
||||||
|
{
|
||||||
|
foreach (var item in GetMethods(godotObject))
|
||||||
|
{
|
||||||
|
if (item.Name == property)
|
||||||
|
{
|
||||||
|
info = item;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public static List<PropertyInfoEx> GetPropertyListEx(this GodotObject godotObject) => GetProperties(godotObject);
|
||||||
|
public static List<PropertyInfoEx> GetProperties(GodotObject obj)
|
||||||
|
{
|
||||||
|
var raw = obj.GetPropertyList();
|
||||||
|
var list = new List<PropertyInfoEx>(raw.Count);
|
||||||
|
|
||||||
|
foreach (Dictionary dict in raw)
|
||||||
|
{
|
||||||
|
list.Add(new PropertyInfoEx(
|
||||||
|
Name: (string)dict["name"],
|
||||||
|
ClassName: (string)dict["class_name"],
|
||||||
|
Type: (Variant.Type)(int)dict["type"],
|
||||||
|
Hint: (PropertyHint)(int)dict["hint"],
|
||||||
|
HintString: (string)dict["hint_string"],
|
||||||
|
Usage: (PropertyUsageFlags)(int)dict["usage"]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
public static PropertyInfoEx GetProperty(this IEnumerable<PropertyInfoEx> properties, string name) => properties.FirstOrDefault(item => item.Name == name);
|
||||||
|
public static bool TryGetPropertyInfo(this GodotObject godotObject, string property, out PropertyInfoEx info)
|
||||||
|
{
|
||||||
|
foreach (var item in GetProperties(godotObject))
|
||||||
|
{
|
||||||
|
if (item.Name == property)
|
||||||
|
{
|
||||||
|
info = item;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* ──────────── Internals ──────────── */
|
||||||
|
|
||||||
|
private static ArgInfo ParseArg(Dictionary d) => new(
|
||||||
|
Name: (string)d["name"],
|
||||||
|
Type: (Variant.Type)(int)d["type"],
|
||||||
|
Hint: (PropertyHint)(int)d["hint"],
|
||||||
|
HintString: (string)d["hint_string"],
|
||||||
|
DefaultValue: d.TryGetValue("default_value", out var dv) ? dv : default);
|
||||||
|
|
||||||
|
}
|
||||||
78
GodotHelper/src/VariantUtils.cs
Normal file
78
GodotHelper/src/VariantUtils.cs
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Godot;
|
||||||
|
using Godot.Collections;
|
||||||
|
namespace SJK.GodotHelpers;
|
||||||
|
|
||||||
|
public static class VariantUtils
|
||||||
|
{
|
||||||
|
public static Variant SafeToVariant(object value)
|
||||||
|
{
|
||||||
|
return value switch
|
||||||
|
{
|
||||||
|
null => new Variant(),
|
||||||
|
bool b => Variant.From(b),
|
||||||
|
int i => Variant.From(i),
|
||||||
|
long l => Variant.From((int)l), // Godot Variant only supports 32-bit int
|
||||||
|
float f => Variant.From(f),
|
||||||
|
double d => Variant.From((float)d),
|
||||||
|
string s => Variant.From(s),
|
||||||
|
Vector2 v2 => Variant.From(v2),
|
||||||
|
Vector2I v2i => Variant.From(v2i),
|
||||||
|
Vector3 v3 => Variant.From(v3),
|
||||||
|
Vector3I v3i => Variant.From(v3i),
|
||||||
|
Vector4 v4 => Variant.From(v4),
|
||||||
|
Vector4I v4i => Variant.From(v4i),
|
||||||
|
Rect2 rect2 => Variant.From(rect2),
|
||||||
|
Rect2I rect2i => Variant.From(rect2i),
|
||||||
|
Quaternion q => Variant.From(q),
|
||||||
|
Basis basis => Variant.From(basis),
|
||||||
|
Transform2D t2d => Variant.From(t2d),
|
||||||
|
Transform3D t3d => Variant.From(t3d),
|
||||||
|
Color color => Variant.From(color),
|
||||||
|
Plane plane => Variant.From(plane),
|
||||||
|
Aabb aabb => Variant.From(aabb),
|
||||||
|
GodotObject go => Variant.From(go),
|
||||||
|
byte[] bytes => Variant.From(bytes),
|
||||||
|
StringName sn => Variant.From(sn),
|
||||||
|
NodePath np => Variant.From(np),
|
||||||
|
Callable call => Variant.From(call),
|
||||||
|
Signal sig => Variant.From(sig),
|
||||||
|
Dictionary dict => Variant.From(dict),
|
||||||
|
Godot.Collections.Array array => Variant.From(array),
|
||||||
|
_ => throw new InvalidCastException($"Unsupported type '{value?.GetType().FullName}' for Variant conversion.")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static Type GetSystemType(this Variant.Type type) => type switch
|
||||||
|
{
|
||||||
|
Variant.Type.Nil => typeof(object),
|
||||||
|
Variant.Type.Bool => typeof(bool),
|
||||||
|
Variant.Type.Int => typeof(int),
|
||||||
|
Variant.Type.Float => typeof(float),
|
||||||
|
Variant.Type.String => typeof(string),
|
||||||
|
Variant.Type.Vector2 => typeof(Vector2),
|
||||||
|
Variant.Type.Vector2I => typeof(Vector2I),
|
||||||
|
Variant.Type.Rect2 => typeof(Rect2),
|
||||||
|
Variant.Type.Rect2I => typeof(Rect2I),
|
||||||
|
Variant.Type.Vector3 => typeof(Vector3),
|
||||||
|
Variant.Type.Vector3I => typeof(Vector3I),
|
||||||
|
Variant.Type.Vector4 => typeof(Vector4),
|
||||||
|
Variant.Type.Vector4I => typeof(Vector4I),
|
||||||
|
Variant.Type.Transform2D => typeof(Transform2D),
|
||||||
|
Variant.Type.Transform3D => typeof(Transform3D),
|
||||||
|
Variant.Type.Basis => typeof(Basis),
|
||||||
|
Variant.Type.Quaternion => typeof(Quaternion),
|
||||||
|
Variant.Type.Aabb => typeof(Aabb),
|
||||||
|
Variant.Type.Color => typeof(Color),
|
||||||
|
Variant.Type.Plane => typeof(Plane),
|
||||||
|
Variant.Type.StringName => typeof(StringName),
|
||||||
|
Variant.Type.NodePath => typeof(NodePath),
|
||||||
|
Variant.Type.Rid => typeof(Rid),
|
||||||
|
Variant.Type.Object => typeof(GodotObject),
|
||||||
|
Variant.Type.Callable => typeof(Callable),
|
||||||
|
Variant.Type.Signal => typeof(Signal),
|
||||||
|
Variant.Type.Dictionary => typeof(Dictionary),
|
||||||
|
Variant.Type.Array => typeof(Godot.Collections.Array),
|
||||||
|
_ => typeof(object)
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "8.0.125",
|
"version": "10.0.104",
|
||||||
"rollForward": "latestMinor"
|
"rollForward": "latestMinor"
|
||||||
},
|
},
|
||||||
"msbuild-sdks": {
|
"msbuild-sdks": {
|
||||||
|
|||||||
Reference in New Issue
Block a user