#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(); 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