rokojori_action_library/Tools/mcp/PropertyReflection.cs

87 lines
2.1 KiB
C#

#if TOOLS
using Godot;
using Godot.Collections;
namespace Rokojori.Tools
{
using Rokojori;
// Walks GetPropertyList() filtered to PropertyUsageFlags.Storage, matching what
// Godot's own .tscn/.tres serializer persists - so round-trips don't add/lose properties.
public static class PropertyReflection
{
public static JSONObject ToJson( GodotObject target )
{
var result = new JSONObject();
var properties = target.GetPropertyList();
foreach ( var propertyDictionary in properties )
{
var dict = (Dictionary) propertyDictionary;
if ( ! IsStored( dict ) )
{
continue;
}
var name = dict[ "name" ].AsString();
if ( string.IsNullOrEmpty( name ) )
{
continue;
}
var value = target.Get( name );
result.Set( name, VariantJson.ToJson( value ) );
}
return result;
}
public static void ApplyFromJson( GodotObject target, JSONObject data )
{
var properties = target.GetPropertyList();
var typesByName = new System.Collections.Generic.Dictionary<string, Variant.Type>();
foreach ( var propertyDictionary in properties )
{
var dict = (Dictionary) propertyDictionary;
var name = dict[ "name" ].AsString();
if ( ! string.IsNullOrEmpty( name ) )
{
typesByName[ name ] = (Variant.Type) dict[ "type" ].AsInt32();
}
}
for ( var i = 0; i < data.keys.Count; i++ )
{
var name = data.keys[ i ];
if ( ! typesByName.ContainsKey( name ) )
{
RJLog.Error( "MCP PropertyReflection: unknown property", name, "on", target.GetClass() );
continue;
}
var variant = VariantJson.FromJson( data.values[ i ], typesByName[ name ] );
target.Set( name, variant );
}
}
static bool IsStored( Dictionary propertyInfo )
{
if ( ! propertyInfo.ContainsKey( "usage" ) )
{
return false;
}
var usage = propertyInfo[ "usage" ].AsInt64();
return ( usage & (long) PropertyUsageFlags.Storage ) != 0;
}
}
}
#endif