using NativeEngine; namespace Sandbox; /// /// Anim param values contain any value for a limited set of types /// public struct AnimParam { public string Name; public T MinValue; public T MaxValue; public T DefaultValue; public string[] OptionNames; } public sealed partial class AnimationGraph : Resource { internal HAnimationGraph native; public override bool IsValid => native.IsValid; /// /// Whether the animation graph is invalid, or has not yet loaded. /// public bool IsError => native.IsNull || !native.IsStrongHandleValid(); /// /// Animation graph file name. /// public string Name { get; internal set; } /// /// Private constructor, use /// private AnimationGraph( HAnimationGraph native, string name ) { if ( native.IsNull ) throw new Exception( "Animation Graph pointer cannot be null!" ); this.native = native; Name = name; UpdateNameToIndexMapping(); SetIdFromResourcePath( Name ); } internal override void OnReloaded() { base.OnReloaded(); UpdateNameToIndexMapping(); } private void UpdateNameToIndexMapping() { _nameToIndex.Clear(); for ( var i = 0; i < ParamCount; i++ ) { _nameToIndex[GetParameterFromList( i ).GetName()] = i; } } ~AnimationGraph() { var n = native; native = default; MainThread.Queue( () => n.DestroyStrongHandle() ); } internal IAnimParameterList ParameterList => native.GetParameterList(); internal IAnimParameter GetParameterFromList( int index ) => ParameterList.GetParameter( index ); internal IAnimParameter GetParameterFromList( string name ) => ParameterList.GetParameter( name ); /// /// Number of parameters in this animgraph /// public int ParamCount => ParameterList.Count(); private Dictionary _nameToIndex = new(); private static readonly Type[] _types = [ null, typeof( bool ), typeof( byte ), typeof( int ), typeof( float ), typeof( Vector3 ), typeof( Rotation ), ]; /// /// Get value type of parameter at given index /// public Type GetParameterType( int index ) { return _types[(int)GetParameterFromList( index ).GetParameterType()]; } /// /// Get value type of parameter with the given , or if not found. /// public Type GetParameterType( string name ) { if ( GetParameterFromList( name ) is not { IsValid: true } param ) { return null; } var parameterType = param.GetParameterType(); return _types[(int)parameterType]; } /// /// Get name of parameter at given index /// public string GetParameterName( int index ) { return GetParameterFromList( index ).GetName(); } internal AnimParam GetParameterInternal( IAnimParameter param ) { if ( !param.IsValid ) { throw new ArgumentException( $"Invalid parameter" ); } var parameterType = param.GetParameterType(); var type = _types[(int)parameterType]; if ( type != typeof( T ) ) { throw new ArgumentException( $"Invalid parameter type {typeof( T )}, expected {type}" ); } return new() { Name = param.GetName(), MinValue = param.GetMinValue().GetValue(), MaxValue = param.GetMaxValue().GetValue(), DefaultValue = param.GetDefaultValue().GetValue(), OptionNames = parameterType == AnimParamType.Enum ? Enumerable.Range( 0, param.GetNumOptionNames() ) .Select( param.GetOptionName ) .ToArray() : null }; } /// /// Try to get parameter index at given name /// public bool TryGetParameterIndex( string name, out int index ) { return _nameToIndex.TryGetValue( name, out index ); } /// /// Get parameter at given name /// public AnimParam GetParameter( string name ) { return GetParameterInternal( GetParameterFromList( name ) ); } /// /// Get parameter at given index /// public AnimParam GetParameter( int index ) { return GetParameterInternal( GetParameterFromList( index ) ); } }