diff --git a/Forge.Tests/Statescript/ExpressionResolverTests.cs b/Forge.Tests/Statescript/ExpressionResolverTests.cs index 2b29780..ae1c2f3 100644 --- a/Forge.Tests/Statescript/ExpressionResolverTests.cs +++ b/Forge.Tests/Statescript/ExpressionResolverTests.cs @@ -34,7 +34,7 @@ public void Comparison_resolver_greater_than_returns_true_when_left_exceeds_righ ComparisonOperation.GreaterThan, new VariantResolver(new Variant128(10.0), typeof(double)))); - var condition = new ExpressionConditionNode("isAboveThreshold"); + var condition = new ExpressionNode("isAboveThreshold"); var trueAction = new TrackingActionNode(); var falseAction = new TrackingActionNode(); @@ -71,7 +71,7 @@ public void Comparison_resolver_greater_than_returns_false_when_left_is_less() ComparisonOperation.GreaterThan, new VariantResolver(new Variant128(10.0), typeof(double)))); - var condition = new ExpressionConditionNode("isAboveThreshold"); + var condition = new ExpressionNode("isAboveThreshold"); var trueAction = new TrackingActionNode(); var falseAction = new TrackingActionNode(); @@ -108,7 +108,7 @@ public void Comparison_resolver_equal_returns_true_for_matching_values() ComparisonOperation.Equal, new VariantResolver(new Variant128(42.0), typeof(double)))); - var condition = new ExpressionConditionNode("isEqual"); + var condition = new ExpressionNode("isEqual"); var trueAction = new TrackingActionNode(); var falseAction = new TrackingActionNode(); @@ -148,7 +148,7 @@ public void Comparison_resolver_compares_two_graph_variables() ComparisonOperation.GreaterThan, new VariableResolver("threshold", typeof(double)))); - var condition = new ExpressionConditionNode("isHealthAboveThreshold"); + var condition = new ExpressionNode("isHealthAboveThreshold"); var trueAction = new TrackingActionNode(); var falseAction = new TrackingActionNode(); @@ -185,7 +185,7 @@ public void Comparison_resolver_less_than_or_equal_at_boundary() ComparisonOperation.LessThanOrEqual, new VariantResolver(new Variant128(10.0), typeof(double)))); - var condition = new ExpressionConditionNode("atBoundary"); + var condition = new ExpressionNode("atBoundary"); var trueAction = new TrackingActionNode(); var falseAction = new TrackingActionNode(); @@ -222,7 +222,7 @@ public void Comparison_resolver_not_equal_returns_true_for_different_values() ComparisonOperation.NotEqual, new VariantResolver(new Variant128(2.0), typeof(double)))); - var condition = new ExpressionConditionNode("isDifferent"); + var condition = new ExpressionNode("isDifferent"); var trueAction = new TrackingActionNode(); var falseAction = new TrackingActionNode(); @@ -253,7 +253,7 @@ public void Expression_condition_node_returns_false_for_missing_property() { var graph = new Graph(); - var condition = new ExpressionConditionNode("nonexistent"); + var condition = new ExpressionNode("nonexistent"); var trueAction = new TrackingActionNode(); var falseAction = new TrackingActionNode(); @@ -293,7 +293,7 @@ public void Comparison_resolver_works_with_int_operands() ComparisonOperation.GreaterThanOrEqual, new VariableResolver("requiredScore", typeof(int)))); - var condition = new ExpressionConditionNode("hasEnoughScore"); + var condition = new ExpressionNode("hasEnoughScore"); var trueAction = new TrackingActionNode(); var falseAction = new TrackingActionNode(); @@ -334,7 +334,7 @@ public void Comparison_resolver_works_with_attribute_resolver() ComparisonOperation.GreaterThanOrEqual, new VariableResolver("required", typeof(int)))); - var condition = new ExpressionConditionNode("hasEnoughAttribute"); + var condition = new ExpressionNode("hasEnoughAttribute"); var trueAction = new TrackingActionNode(); var falseAction = new TrackingActionNode(); diff --git a/Forge/Statescript/Node.cs b/Forge/Statescript/Node.cs index ce43882..fc52fd9 100644 --- a/Forge/Statescript/Node.cs +++ b/Forge/Statescript/Node.cs @@ -19,6 +19,11 @@ public abstract class Node /// The list to add output ports to. protected abstract void DefinePorts(List inputPorts, List outputPorts); + /// + /// Gets a description of the node type, which is used in editor tooltips and documentation. + /// + public virtual string Description => $"{GetType().Name.Replace("Node", string.Empty)} node."; + /// /// Gets or sets the unique identifier for this node. /// diff --git a/Forge/Statescript/Nodes/Action/SetVariableNode.cs b/Forge/Statescript/Nodes/Action/SetVariableNode.cs index 1969a4f..1c7e9e2 100644 --- a/Forge/Statescript/Nodes/Action/SetVariableNode.cs +++ b/Forge/Statescript/Nodes/Action/SetVariableNode.cs @@ -23,6 +23,9 @@ public class SetVariableNode(StringKey sourcePropertyName, StringKey targetVaria private readonly StringKey _targetVariableName = targetVariableName; + /// + public override string Description => "Sets a graph variable to the value of a property."; + /// protected override void Execute(GraphContext graphContext) { diff --git a/Forge/Statescript/Nodes/ActionNode.cs b/Forge/Statescript/Nodes/ActionNode.cs index 12b045e..fd44ee4 100644 --- a/Forge/Statescript/Nodes/ActionNode.cs +++ b/Forge/Statescript/Nodes/ActionNode.cs @@ -26,6 +26,9 @@ public abstract class ActionNode : Node /// The current graph context. protected abstract void Execute(GraphContext graphContext); + /// + public override string Description => $"A {GetType().Name.Replace("Node", string.Empty)} action node."; + /// #pragma warning disable SA1202 // Elements should be ordered by access internal override IEnumerable GetReachableOutputPorts(byte inputPortIndex) diff --git a/Forge/Statescript/Nodes/Condition/ExpressionConditionNode.cs b/Forge/Statescript/Nodes/Condition/ExpressionNode.cs similarity index 86% rename from Forge/Statescript/Nodes/Condition/ExpressionConditionNode.cs rename to Forge/Statescript/Nodes/Condition/ExpressionNode.cs index 1fecf55..cf57b3e 100644 --- a/Forge/Statescript/Nodes/Condition/ExpressionConditionNode.cs +++ b/Forge/Statescript/Nodes/Condition/ExpressionNode.cs @@ -17,10 +17,13 @@ namespace Gamesmiths.Forge.Statescript.Nodes.Condition; /// /// The name of the graph property that provides the condition result. Must resolve /// to a value. -public class ExpressionConditionNode(StringKey conditionPropertyName) : ConditionNode +public class ExpressionNode(StringKey conditionPropertyName) : ConditionNode { private readonly StringKey _conditionPropertyName = conditionPropertyName; + /// + public override string Description => "Evaluates the given property to determine which port to activate."; + /// protected override bool Test(GraphContext graphContext) { diff --git a/Forge/Statescript/Nodes/ConditionNode.cs b/Forge/Statescript/Nodes/ConditionNode.cs index 4dabde9..7f0544e 100644 --- a/Forge/Statescript/Nodes/ConditionNode.cs +++ b/Forge/Statescript/Nodes/ConditionNode.cs @@ -32,6 +32,9 @@ public abstract class ConditionNode : Node /// if the condition is met; otherwise, . protected abstract bool Test(GraphContext graphContext); + /// + public override string Description => $"A {GetType().Name.Replace("Node", string.Empty)} condition node."; + /// #pragma warning disable SA1202 // Elements should be ordered by access internal override IEnumerable GetReachableOutputPorts(byte inputPortIndex) diff --git a/Forge/Statescript/Nodes/EntryNode.cs b/Forge/Statescript/Nodes/EntryNode.cs index f25a834..c8cf871 100644 --- a/Forge/Statescript/Nodes/EntryNode.cs +++ b/Forge/Statescript/Nodes/EntryNode.cs @@ -15,6 +15,9 @@ public class EntryNode : Node /// public const byte OutputPort = 0; + /// + public override string Description => "Entry point of the graph. Emits a message to start execution."; + /// /// Starts the graph execution by emitting a message through the output port. /// diff --git a/Forge/Statescript/Nodes/ExitNode.cs b/Forge/Statescript/Nodes/ExitNode.cs index 7eefa8a..72cbce0 100644 --- a/Forge/Statescript/Nodes/ExitNode.cs +++ b/Forge/Statescript/Nodes/ExitNode.cs @@ -19,6 +19,9 @@ public class ExitNode : Node /// public const byte InputPort = 0; + /// + public override string Description => "Exit point of the graph. Stops execution when a message is received."; + /// internal override IEnumerable GetReachableOutputPorts(byte inputPortIndex) { diff --git a/Forge/Statescript/Nodes/State/TimerNode.cs b/Forge/Statescript/Nodes/State/TimerNode.cs index 315f317..f345c9e 100644 --- a/Forge/Statescript/Nodes/State/TimerNode.cs +++ b/Forge/Statescript/Nodes/State/TimerNode.cs @@ -21,6 +21,9 @@ public class TimerNode(StringKey durationPropertyName) : StateNode + public override string Description => "Remains active for a configured duration, then deactivates."; + /// protected override void OnActivate(GraphContext graphContext) { diff --git a/Forge/Statescript/Nodes/StateNode.cs b/Forge/Statescript/Nodes/StateNode.cs index 07cdf19..ba6c654 100644 --- a/Forge/Statescript/Nodes/StateNode.cs +++ b/Forge/Statescript/Nodes/StateNode.cs @@ -57,6 +57,9 @@ public abstract class StateNode : Node /// The graph's context. protected abstract void OnDeactivate(GraphContext graphContext); + /// + public override string Description => $"A {GetType().Name.Replace("Node", string.Empty)} state node."; + /// /// Updates this state node with the given delta time. Only processes the update if the node is currently active. ///