rokojori_action_library/Tools/mcp/ScenePathResolver.cs

88 lines
2.2 KiB
C#
Raw Normal View History

2026-10-03 12:15:58 +00:00
#if TOOLS
using Godot;
namespace Rokojori.Tools
{
// scenePath is a list of child names from the scene root, e.g. ["Player","CharacterBody3D"].
// SceneState has no parent/child API - nodes are a flat list, each with its own full relative
// path string (root is "."), so matching is by path-string comparison / prefix.
public static class ScenePathResolver
{
// SceneState.GetNodePath(idx, false) stringifies relative to the scene root as "./Name/Child",
// i.e. with an explicit "." leading segment - not a bare "Name/Child" as a naive join would produce.
public static string ToRelativePath( string[] scenePath )
{
if ( scenePath == null || scenePath.Length == 0 )
{
return ".";
}
return "./" + string.Join( "/", scenePath );
}
public static int FindNodeIndex( SceneState state, string relativePath )
{
var count = state.GetNodeCount();
for ( var i = 0; i < count; i++ )
{
if ( state.GetNodePath( i, false ).ToString() == relativePath )
{
return i;
}
}
return -1;
}
// 0 = same node, 1 = direct child, 2 = grandchild, etc. -1 = not a descendant.
public static int DepthOf( string rootRelativePath, string candidateRelativePath )
{
if ( rootRelativePath == candidateRelativePath )
{
return 0;
}
var prefix = rootRelativePath == "." ? "./" : rootRelativePath + "/";
if ( ! candidateRelativePath.StartsWith( prefix ) )
{
return -1;
}
var remainder = candidateRelativePath.Substring( prefix.Length );
return remainder.Split( '/' ).Length;
}
public static Node FindNode( Node root, string[] scenePath )
{
if ( scenePath == null || scenePath.Length == 0 )
{
return root;
}
return root.GetNodeOrNull( new NodePath( string.Join( "/", scenePath ) ) );
}
public static string[] ToStringArray( Rokojori.JSONArray array )
{
if ( array == null )
{
return new string[ 0 ];
}
var result = new string[ array.size ];
for ( var i = 0; i < array.size; i++ )
{
result[ i ] = array.Get( i ).stringValue;
}
return result;
}
}
}
#endif