#if TOOLS using Godot; namespace Rokojori.Tools { using Rokojori; public static class ReadSceneFragmentRoute { public static JSONObject ToolDefinition() { var filePathSchema = new JSONObject(); filePathSchema.Set( "type", "string" ); filePathSchema.Set( "description", "res:// path to the scene (.tscn)" ); var scenePathSchema = new JSONObject(); scenePathSchema.Set( "type", "array" ); scenePathSchema.Set( "description", "Child names from the scene root to the target node. Empty array = scene root." ); var levelSchema = new JSONObject(); levelSchema.Set( "type", "integer" ); levelSchema.Set( "description", "Descendant depth to include: 0 = all, 1 = direct children only, 2 = two levels, etc. Defaults to 0." ); var properties = new JSONObject(); properties.Set( "filePath", filePathSchema ); properties.Set( "scenePath", scenePathSchema ); properties.Set( "levelOfChildren", levelSchema ); var required = new JSONArray(); required.Push( "filePath" ); required.Push( "scenePath" ); var schema = new JSONObject(); schema.Set( "type", "object" ); schema.Set( "properties", properties ); schema.Set( "required", required ); var tool = new JSONObject(); tool.Set( "name", "read_scene_fragment" ); tool.Set( "description", "Read a node subtree out of a scene file without instantiating it." ); tool.Set( "inputSchema", schema ); return tool; } public static ToolCallOutcome Execute( JSONObject arguments ) { var filePath = JsonUtil.GetStringOrNull( arguments, "filePath" ); var scenePathArray = arguments != null ? arguments.GetArray( "scenePath" ) : null; var levelData = arguments != null ? arguments.Get( "levelOfChildren" ) : null; var levelOfChildren = levelData != null && levelData.isNumber ? levelData.intValue : 0; if ( string.IsNullOrEmpty( filePath ) ) { return ToolCallOutcome.Error( "Missing required argument: filePath" ); } if ( ! ResourceLoader.Exists( filePath, "PackedScene" ) ) { return ToolCallOutcome.Error( "Scene not found: " + filePath ); } var packedScene = ResourceLoader.Load( filePath ); if ( packedScene == null ) { return ToolCallOutcome.Error( "Failed to load scene: " + filePath ); } var state = packedScene.GetState(); var scenePath = ScenePathResolver.ToStringArray( scenePathArray ); var targetRelativePath = ScenePathResolver.ToRelativePath( scenePath ); var targetIndex = ScenePathResolver.FindNodeIndex( state, targetRelativePath ); if ( targetIndex == -1 ) { return ToolCallOutcome.Error( "Node not found at scenePath: " + targetRelativePath ); } var startingLevels = levelOfChildren == 0 ? -1 : levelOfChildren; var fragment = SerializeNode( state, targetIndex, targetRelativePath, startingLevels ); return ToolCallOutcome.Ok( JSON.Stringify( fragment ) ); } static JSONObject SerializeNode( SceneState state, int index, string relativePath, int remainingLevels ) { var obj = new JSONObject(); obj.Set( "name", state.GetNodeName( index ).ToString() ); obj.Set( "type", state.GetNodeType( index ).ToString() ); var properties = new JSONObject(); var propertyCount = state.GetNodePropertyCount( index ); for ( var i = 0; i < propertyCount; i++ ) { var propName = state.GetNodePropertyName( index, i ).ToString(); var propValue = state.GetNodePropertyValue( index, i ); properties.Set( propName, VariantJson.ToJson( propValue ) ); } obj.Set( "properties", properties ); if ( remainingLevels == 0 ) { return obj; } var children = new JSONObject(); var nodeCount = state.GetNodeCount(); var nextLevels = remainingLevels == -1 ? -1 : remainingLevels - 1; for ( var i = 0; i < nodeCount; i++ ) { var candidatePath = state.GetNodePath( i, false ).ToString(); if ( ScenePathResolver.DepthOf( relativePath, candidatePath ) != 1 ) { continue; } var childName = state.GetNodeName( i ).ToString(); children.Set( childName, SerializeNode( state, i, candidatePath, nextLevels ) ); } obj.Set( "children", children ); return obj; } } } #endif