using Godot; using System.Collections.Generic; using System.Reflection; using Rokojori.Extensions; namespace Rokojori { [GlobalClass, Tool ] public partial class SelectNode3D : Action { [Export] public Selector selector; bool _enteredTree = false; public override void _EnterTree() { base._EnterTree(); _enteredTree = true; } Node _target; [Export] public Node target { get => _target; set { if ( _target == value ) { return; } _target = value; // Deserialization sets exported properties before _EnterTree fires, so this // only triggers for genuine interactive edits in the editor, never for a scene // being loaded (regardless of property order) or for runtime reassignment. if ( _enteredTree && Engine.IsEditorHint() ) { targetMember = ""; #if TOOLS NotifyPropertyListChanged(); #endif } } } [Export] public string targetMember; protected override void _OnTrigger() { if ( target == null ) { return; } Node3D node3D = null; if ( selector == null ) { ReflectionHelper.SetValue( target, targetMember, node3D ); this.LogInfo( "Set Null:", HierarchyName.Of( target ), targetMember ); return; } var selectedNode = Unique.Get().Select( selector ); if ( selectedNode is Selectable ) { var go = selectedNode.GetParent(); if ( go != null ) { node3D = go.body; } } ReflectionHelper.SetValue( target, targetMember, node3D ); } #if TOOLS public override void _ValidateProperty( Godot.Collections.Dictionary property ) { if ( property[ "name" ].AsString() != nameof( targetMember ) ) { return; } var members = GetTargetNode3DMemberNames(); property[ "hint" ] = (long) PropertyHint.Enum; property[ "hint_string" ] = members.Count == 0 ? "(Invalid Target)" : "None," + string.Join( ",", members ); } List GetTargetNode3DMemberNames() { var names = new List(); if ( target == null ) { return names; } var infos = ReflectionHelper.GetDataMemberInfos( target, BindingFlags.Public | BindingFlags.Instance ); foreach ( var info in infos ) { if ( ! info.IsDefined( typeof( ExportAttribute ) ) ) { continue; } var memberType = info.GetMemberType(); if ( memberType == null || ! memberType.IsAssignableFrom( typeof( Node3D ) ) ) { continue; } names.Add( info.Name ); } return names; } #endif } }