namespace GodotHelpers;
using System;
using System.Collections.Generic;
using System.Linq;
using Godot;
using Godot.Collections;
using Array = Godot.Collections.Array;
///
/// Strong‑typed view of Godot's get_method_list / get_property_list output.
///
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 Args,
IReadOnlyList 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 GetMethodsListEx(this GodotObject godotObject) => GetMethods(godotObject);
public static List GetMethods(GodotObject obj)
{
var raw = obj.GetMethodList();
var list = new List(raw.Count);
foreach (Dictionary dict in raw)
{
// — Parse args —
var argsRaw = (Array)dict["args"];
var args = new List(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 GetPropertyListEx(this GodotObject godotObject) => GetProperties(godotObject);
public static List GetProperties(GodotObject obj)
{
var raw = obj.GetPropertyList();
var list = new List(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 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);
}