gd_core/addons/core/misc/PODNode.cs

145 lines
4.4 KiB
C#

using Godot;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
[Tool]
public partial class PODNode<T> : Node where T : class, new()
{
private T _data = new T();
// We can't export a generic type 'T', but we can still access it.
public T Data
{
get => _data;
set
{
_data = value ?? new T();
// If the data object is replaced, tell the editor to refresh the inspector.
if( Engine.IsEditorHint() )
{
NotifyPropertyListChanged();
}
}
}
public override Godot.Collections.Array<Godot.Collections.Dictionary> _GetPropertyList()
{
var properties = new Godot.Collections.Array<Godot.Collections.Dictionary>();
//if (Data == null) return properties;
// Use reflection to find all writable properties in our POD.
PropertyInfo[] podProperties = typeof( T ).GetProperties( BindingFlags.Public | BindingFlags.Instance )
.Where( p => p.CanRead && p.CanWrite ).ToArray();
foreach( var prop in podProperties )
{
// Try to map the C# type to a Godot Variant type.
var (variantType, hint, hintString) = CSharpTypeToVariant( prop.PropertyType );
if( variantType == Variant.Type.Nil )
continue; // Skip unsupported types.
// Create the dictionary that Godot's Inspector understands.
properties.Add( new Godot.Collections.Dictionary
{
{ "name", $"{prop.Name}" }, // Use a category for organization.
{ "type", (int)variantType },
{ "usage", (int)PropertyUsageFlags.Default },
{ "hint", (int)hint },
{ "hint_string", hintString }
} );
}
return properties;
}
public override Variant _Get( StringName property )
{
string propName = property.ToString();
if( !propName.StartsWith( "Data/" ) )
return base._Get( property );
string podPropName = propName.Remove( 0, 5 ); // Remove "Data/" prefix.
PropertyInfo propInfo = typeof( T ).GetProperty( podPropName );
if( propInfo != null )
{
try
{
// Ensure the property can be read.
if( !propInfo.CanRead )
{
GD.PrintErr( $"Property '{podPropName}' is not readable." );
return Variant.From<GodotObject>( null );
}
var value = Variant.From( propInfo.GetValue( Data ) );
return value;
}
catch( Exception ex )
{
GD.PrintErr( $"Failed to access property '{podPropName}': {ex.Message}" );
return Variant.From<GodotObject>( null );
}
}
return base._Get( property );
}
public override bool _Set( StringName property, Variant value )
{
string propName = property.ToString();
//if (!propName.StartsWith("Data/")) return base._Set(property, value);
string podPropName = propName.Remove( 0, 5 ); // Remove "Data/" prefix.
PropertyInfo propInfo = typeof( T ).GetProperty( podPropName );
if( propInfo != null )
{
try
{
// Convert Godot's Variant back to the correct C# type.
object convertedValue = value.AsType( propInfo.PropertyType );
propInfo.SetValue( Data, convertedValue );
return true;
}
catch( Exception ex )
{
GD.PrintErr( $"Failed to set property '{podPropName}': {ex.Message}" );
return false;
}
}
return base._Set( property, value );
}
// Helper to map C# types to Godot's Variant types and property hints.
private (Variant.Type, PropertyHint, string) CSharpTypeToVariant( Type type )
{
if( type == typeof( int ) || type == typeof( long ) )
return (Variant.Type.Int, PropertyHint.None, "");
if( type == typeof( uint ) || type == typeof( ulong ) )
return (Variant.Type.Int, PropertyHint.None, "");
if( type == typeof( float ) || type == typeof( double ) )
return (Variant.Type.Float, PropertyHint.None, "");
if( type == typeof( string ) )
return (Variant.Type.String, PropertyHint.None, "");
if( type == typeof( bool ) )
return (Variant.Type.Bool, PropertyHint.None, "");
if( type == typeof( Vector2 ) )
return (Variant.Type.Vector2, PropertyHint.None, "");
if( type == typeof( Vector3 ) )
return (Variant.Type.Vector3, PropertyHint.None, "");
if( type == typeof( Color ) )
return (Variant.Type.Color, PropertyHint.None, "");
if( type.IsEnum )
{
// Create a comma-separated string of enum names for a dropdown list.
string hintString = string.Join( ",", Enum.GetNames( type ) );
return (Variant.Type.Int, PropertyHint.Enum, hintString);
}
// Add more type mappings as needed.
return (Variant.Type.Nil, PropertyHint.None, ""); // Unsupported type.
}
}