using System.Collections.Generic;
using System.Linq;
using Facepunch.ActionGraphs;
using Sandbox;
namespace Editor.ActionGraphs;
public static class ActionGraphExtensions
{
public static Sandbox.DisplayInfo GetDisplayInfo( this Node node )
{
var displayInfo = new Sandbox.DisplayInfo
{
Name = node.DisplayInfo.Title,
Description = node.DisplayInfo.Description,
Icon = node.DisplayInfo.Icon,
Tags = node.DisplayInfo.Tags
};
if ( node.Definition.Identifier == "resource.ref" && node.Properties["value"].Value is Resource resource )
{
var dispInfo = Sandbox.DisplayInfo.For( resource );
displayInfo.Name = resource.ResourceName;
displayInfo.Icon = dispInfo.Icon ?? displayInfo.Icon;
displayInfo.Description = $"References a {dispInfo.Name}.
{resource.ResourcePath}";
}
if ( node.Definition == EditorNodeLibrary.Input && node.ActionGraph.Title is { } title )
{
displayInfo.Name = title;
}
else if ( node.Definition == EditorNodeLibrary.InputValue
&& node.Properties.Name.Value is string name
&& node.ActionGraph.Inputs.TryGetValue( name, out var input )
&& input.IsTarget )
{
displayInfo.Name = "This";
displayInfo.Description = "Object this graph is currently running on.";
}
else if ( displayInfo.Name.LastIndexOf( '→' ) is var index and not -1
&& node.Inputs.Values.FirstOrDefault( x => x.IsTarget )?.Link is { Source: { } output } )
{
if ( node.ActionGraph.TargetOutput is { } targetSource && output == targetSource )
{
displayInfo.Name = $"This → {displayInfo.Name[(index + 1)..].TrimStart()}";
}
else if ( output.Node is { Parent: { } parent } && parent == node )
{
displayInfo.Name = $"{output.Node.DisplayInfo.Title} → {displayInfo.Name[(index + 1)..].TrimStart()}";
}
}
if ( node.Kind == NodeKind.Action && node.Binding.IsAsync )
{
displayInfo.Name += " \u29d7";
}
return displayInfo;
}
public static bool GetVisible( this Node node )
{
return node.UserData["Visible"]?.GetValue() ?? true;
}
public static bool IsUsed( this Node.Output output )
{
return output.Links.Any( x => x.Target.Node.Parent != output.Node );
}
public static bool IsAnyExpandedOutputVisible( this Node.Output output )
{
return output.GetExpandedOutputs( true ).Any( x => x != output );
}
public static IEnumerable GetExpandedOutputs( this Node.Output output, bool visibleOnly )
{
if ( !visibleOnly || output.Node.GetVisible() || output.IsUsed() )
{
yield return output;
}
foreach ( var child in output.Links.Select( x => x.Target.Node ).Where( x => x.Parent == output.Node ) )
{
if ( child.Kind != NodeKind.Expression ) continue;
foreach ( var childOutput in child.Outputs.Values )
{
foreach ( var expandedChildOutput in GetExpandedOutputs( childOutput, visibleOnly ) )
{
yield return expandedChildOutput;
}
}
}
}
public static void SetVisible( this Node node, bool value )
{
if ( !value )
{
node.UserData["Visible"] = false;
}
else
{
node.UserData.Remove( "Visible" );
}
}
public static bool IsOperator( this NodeDefinition nodeDef )
{
return nodeDef.GetType().Name == "ExpressionNodeDefinition"
|| nodeDef.Attributes.OfType().Any();
}
public static string GetNextInputName( this ActionGraph graph )
{
const string prefix = "_in";
for ( var i = 0; ; ++i )
{
if ( graph.Inputs.ContainsKey( $"{prefix}{i}" ) )
{
continue;
}
return $"{prefix}{i}";
}
}
public static string GetNextOutputName( this ActionGraph graph )
{
const string prefix = "_out";
for ( var i = 0; ; ++i )
{
if ( graph.Outputs.ContainsKey( $"{prefix}{i}" ) )
{
continue;
}
return $"{prefix}{i}";
}
}
}