diff --git a/addons/behaviour_toolkit/behaviour_tree/bt_composite.gd b/addons/behaviour_toolkit/behaviour_tree/bt_composite.gd index 7d9cb40..e598abf 100644 --- a/addons/behaviour_toolkit/behaviour_tree/bt_composite.gd +++ b/addons/behaviour_toolkit/behaviour_tree/bt_composite.gd @@ -1,6 +1,25 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTComposite.svg") class_name BTComposite extends BTBehaviour ## The leaves under the composite node. @onready var leaves: Array = get_children() + + +func _get_configuration_warnings() -> PackedStringArray: + var warnings: Array = [] + + var parent = get_parent() + var children = get_children() + + if not parent is BTComposite and not parent is BTRoot and not parent is BTDecorator: + warnings.append("BTComposite node must be a child of BTComposite or BTRoot node.") + + if children.size() == 0: + warnings.append("BTComposite node must have at least one child.") + + if children.size() == 1: + warnings.append("BTComposite node should have more than one child.") + + return warnings diff --git a/addons/behaviour_toolkit/behaviour_tree/bt_decorator.gd b/addons/behaviour_toolkit/behaviour_tree/bt_decorator.gd index e2a0d69..7e8f109 100644 --- a/addons/behaviour_toolkit/behaviour_tree/bt_decorator.gd +++ b/addons/behaviour_toolkit/behaviour_tree/bt_decorator.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTDecorator.svg") class_name BTDecorator extends BTBehaviour @@ -7,7 +8,26 @@ class_name BTDecorator extends BTBehaviour func _get_leaf() -> BTBehaviour: - if get_child_count() == 0: - return null - - return get_child(0) + if get_child_count() == 0: + return null + + return get_child(0) + + +func _get_configuration_warnings() -> PackedStringArray: + var warnings: Array = [] + + var parent = get_parent() + var children = get_children() + + if not parent is BTComposite and not parent is BTRoot: + warnings.append("Decorator node should be a child of a composite node or the root node.") + + if children.size() == 0: + warnings.append("Decorator node should have a child.") + elif children.size() > 1: + warnings.append("Decorator node should have only one child.") + elif not children[0] is BTBehaviour: + warnings.append("Decorator node should have a BTBehaviour node as a child.") + + return warnings diff --git a/addons/behaviour_toolkit/behaviour_tree/bt_leaf.gd b/addons/behaviour_toolkit/behaviour_tree/bt_leaf.gd index cc36a73..e2414e5 100644 --- a/addons/behaviour_toolkit/behaviour_tree/bt_leaf.gd +++ b/addons/behaviour_toolkit/behaviour_tree/bt_leaf.gd @@ -1,6 +1,22 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTLeaf.svg") class_name BTLeaf extends BTBehaviour func tick(_delta: float, _actor: Node, _blackboard: Blackboard) -> BTStatus: return BTStatus.SUCCESS + + +func _get_configuration_warnings() -> PackedStringArray: + var warnings: Array = [] + + var parent = get_parent() + var children = get_children() + + if not parent is BTBehaviour and not parent is BTRoot: + warnings.append("BTLeaf node must be a child of BTBehaviour or BTRoot node.") + + if children.size() > 0: + warnings.append("BTLeaf node must not have any children.") + + return warnings diff --git a/addons/behaviour_toolkit/behaviour_tree/bt_leaf_integration.gd b/addons/behaviour_toolkit/behaviour_tree/bt_leaf_integration.gd index 5deaff3..4268b4c 100644 --- a/addons/behaviour_toolkit/behaviour_tree/bt_leaf_integration.gd +++ b/addons/behaviour_toolkit/behaviour_tree/bt_leaf_integration.gd @@ -1,5 +1,20 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTLeafIntegration.svg") class_name BTLeafIntegration extends BTLeaf -@export var state_machine: FiniteStateMachine +@export var state_machine: FiniteStateMachine: + set(value): + state_machine = value + update_configuration_warnings() + + +func _get_configuration_warnings(): + var warnings: Array = [] + + warnings.append_array(super._get_configuration_warnings()) + + if state_machine == null: + warnings.append("No state machine set.") + + return warnings diff --git a/addons/behaviour_toolkit/behaviour_tree/bt_root.gd b/addons/behaviour_toolkit/behaviour_tree/bt_root.gd index 8f0bc75..8d13551 100644 --- a/addons/behaviour_toolkit/behaviour_tree/bt_root.gd +++ b/addons/behaviour_toolkit/behaviour_tree/bt_root.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTRoot.svg") class_name BTRoot extends BehaviourToolkit ## Node used as a base parent (root) of a Behaviour Tree @@ -32,6 +33,12 @@ var current_status: BTBehaviour.BTStatus func _ready() -> void: + # Don't run in editor + if Engine.is_editor_hint(): + set_physics_process(false) + set_process(false) + return + if blackboard == null: blackboard = _create_local_blackboard() @@ -68,3 +75,19 @@ func _create_local_blackboard() -> Blackboard: func _setup_processing() -> void: set_physics_process(process_type == ProcessType.PHYSICS) set_process(process_type == ProcessType.IDLE) + + +func _get_configuration_warnings() -> PackedStringArray: + var warnings: Array = [] + + var children = get_children() + + if children.size() == 0: + warnings.append("Behaviour Tree needs to have one Behaviour child.") + elif children.size() == 1: + if not children[0] is BTBehaviour: + warnings.append("The child of Behaviour Tree needs to be a Behaviour.") + elif children.size() > 1: + warnings.append("Behaviour Tree can have only one Behaviour child.") + + return warnings diff --git a/addons/behaviour_toolkit/behaviour_tree/composites/bt_integrated_fsm.gd b/addons/behaviour_toolkit/behaviour_tree/composites/bt_integrated_fsm.gd index 0ebe8b8..99a5004 100644 --- a/addons/behaviour_toolkit/behaviour_tree/composites/bt_integrated_fsm.gd +++ b/addons/behaviour_toolkit/behaviour_tree/composites/bt_integrated_fsm.gd @@ -1,9 +1,14 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTCompositeIntegration.svg") class_name BTIntegratedFSM extends BTComposite -@onready var state_machine: FiniteStateMachine = _get_machine() +var state_machine: FiniteStateMachine = null +func _ready(): + if not Engine.is_editor_hint(): + state_machine = _get_machine() + func tick(_delta: float, _actor: Node, _blackboard: Blackboard) -> BTStatus: if state_machine.active == false: @@ -20,3 +25,20 @@ func _get_machine() -> FiniteStateMachine: return null else: return get_child(0) + + +func _get_configuration_warnings(): + var warnings: Array = [] + var children = get_children() + + if children.size() == 0: + warnings.append("BTIntegratedFSM must have a child node. The first child will be used as the state machine.") + + if children.size() > 1: + warnings.append("BTIntegratedFSM can only have one child node. The first child will be used as the state machine.") + + if children.size() == 1: + if not children[0] is FiniteStateMachine: + warnings.append("BTIntegratedFSM's child node must be a FiniteStateMachine. The first child will be used as the state machine.") + + return warnings diff --git a/addons/behaviour_toolkit/behaviour_tree/composites/bt_random_selector.gd b/addons/behaviour_toolkit/behaviour_tree/composites/bt_random_selector.gd index 3bb75ad..ebb596f 100644 --- a/addons/behaviour_toolkit/behaviour_tree/composites/bt_random_selector.gd +++ b/addons/behaviour_toolkit/behaviour_tree/composites/bt_random_selector.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTCompositeRandomSelector.svg") class_name BTRandomSelector extends BTComposite ## The selector composite but with a random order of the leaves. diff --git a/addons/behaviour_toolkit/behaviour_tree/composites/bt_random_sequence.gd b/addons/behaviour_toolkit/behaviour_tree/composites/bt_random_sequence.gd index 6532eca..f219032 100644 --- a/addons/behaviour_toolkit/behaviour_tree/composites/bt_random_sequence.gd +++ b/addons/behaviour_toolkit/behaviour_tree/composites/bt_random_sequence.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTCompositeRandomSequence.svg") class_name BTRandomSequence extends BTComposite ## The squence composite but with a random order of the leaves. diff --git a/addons/behaviour_toolkit/behaviour_tree/composites/bt_selector.gd b/addons/behaviour_toolkit/behaviour_tree/composites/bt_selector.gd index ecc4876..9fdfaaa 100644 --- a/addons/behaviour_toolkit/behaviour_tree/composites/bt_selector.gd +++ b/addons/behaviour_toolkit/behaviour_tree/composites/bt_selector.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTCompositeSelector.svg") class_name BTSelector extends BTComposite ## Selects the first child that succeeds, or fails if none do. diff --git a/addons/behaviour_toolkit/behaviour_tree/composites/bt_sequence.gd b/addons/behaviour_toolkit/behaviour_tree/composites/bt_sequence.gd index 594bad2..9a0954c 100644 --- a/addons/behaviour_toolkit/behaviour_tree/composites/bt_sequence.gd +++ b/addons/behaviour_toolkit/behaviour_tree/composites/bt_sequence.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTCompositeSequence.svg") class_name BTSequence extends BTComposite ## A sequence node will return success if all of its children return success. diff --git a/addons/behaviour_toolkit/behaviour_tree/composites/bt_simple_parallel.gd b/addons/behaviour_toolkit/behaviour_tree/composites/bt_simple_parallel.gd index 95563d9..5e4b62b 100644 --- a/addons/behaviour_toolkit/behaviour_tree/composites/bt_simple_parallel.gd +++ b/addons/behaviour_toolkit/behaviour_tree/composites/bt_simple_parallel.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTSimpleParallel.svg") class_name BTSimpleParallel extends BTComposite ## Executes all children in parallel, and returns SUCCESS depending on the policy. It returns FAILURE if any child returns FAILURE. diff --git a/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_always_fail.gd b/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_always_fail.gd index 795131b..9ddaf1c 100644 --- a/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_always_fail.gd +++ b/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_always_fail.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTDecoratorFail.svg") class_name BTAlwaysFail extends BTDecorator ## The leaf will always fail after running. diff --git a/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_always_succeed.gd b/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_always_succeed.gd index 28ad106..5bbbf60 100644 --- a/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_always_succeed.gd +++ b/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_always_succeed.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTDecoratorSucceed.svg") class_name BTAlwaysSucceed extends BTDecorator ## The leaf will always succeed after running. diff --git a/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_inverter.gd b/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_inverter.gd index 0ba9264..5acc12f 100644 --- a/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_inverter.gd +++ b/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_inverter.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTDecoratorNot.svg") class_name BTInverter extends BTDecorator ## The result of the leaf is inverted. diff --git a/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_limiter.gd b/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_limiter.gd index 2cd16e1..a696c39 100644 --- a/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_limiter.gd +++ b/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_limiter.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTDecoratorLimiter.svg") class_name BTLimiter extends BTDecorator ## Limits the number of times a leaf can be run. (The leaf will fully run, before triggering the limit.) diff --git a/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_repeat.gd b/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_repeat.gd index c9d5976..c13a873 100644 --- a/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_repeat.gd +++ b/addons/behaviour_toolkit/behaviour_tree/decorators/decorator_repeat.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTDecoratorRepeat.svg") class_name BTRepeat extends BTDecorator ## Repeats the leaf a number of times. diff --git a/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_call.gd b/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_call.gd index c3951a4..f5fbb98 100644 --- a/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_call.gd +++ b/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_call.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTLeafCall.svg") class_name LeafCall extends BTLeaf ## Leaf that calls a method on a target node. The target can be the actor, the blackboard or a custom node. @@ -6,39 +7,62 @@ class_name LeafCall extends BTLeaf ## The target type of the call. Can be the actor, the blackboard or a custom node. enum CallTarget { - ACTOR, ## The actor node set on the BTRoot node. - BLACKBOARD, ## The blackboard node set on the BTRoot node. - CUSTOM ## A custom node set on the custom_target variable. + ACTOR, ## The actor node set on the BTRoot node. + BLACKBOARD, ## The blackboard node set on the BTRoot node. + CUSTOM ## A custom node set on the custom_target variable. } ## The method to call on the target node. -@export var method: StringName +@export var method: StringName: + set(value): + method = value + update_configuration_warnings() ## The arguments to pass to the method. @export var arguments: Array = [] @export_category("Target") ## The target type of the call. Can be the actor, the blackboard or a custom node. -@export var target_type: CallTarget = CallTarget.ACTOR +@export var target_type: CallTarget = CallTarget.ACTOR: + set(value): + target_type = value + update_configuration_warnings() ## The custom node to call the method on. Only used if target_type is set to CallTarget.CUSTOM. -@export var custom_target: Node +@export var custom_target: Node: + set(value): + custom_target = value + update_configuration_warnings() func tick(delta: float, actor: Node, blackboard: Blackboard): - var target - - match target_type: - CallTarget.ACTOR: - target = actor - CallTarget.BLACKBOARD: - target = blackboard - CallTarget.CUSTOM: - target = custom_target - - if target.has_method(method): - target.callv(method, arguments) - else: - print("Method " + method + " not found on target " + target.to_string()) - return BTStatus.FAILURE - - return BTStatus.SUCCESS + var target + + match target_type: + CallTarget.ACTOR: + target = actor + CallTarget.BLACKBOARD: + target = blackboard + CallTarget.CUSTOM: + target = custom_target + + if target.has_method(method): + target.callv(method, arguments) + else: + print("Method " + method + " not found on target " + target.to_string()) + return BTStatus.FAILURE + + return BTStatus.SUCCESS + + +func _get_configuration_warnings(): + var warnings: Array = [] + + warnings.append_array(super._get_configuration_warnings()) + + if method == "": + warnings.append("Method is not set.") + + if target_type == CallTarget.CUSTOM and custom_target == null: + warnings.append("Target type is set to CUSTOM but no custom target is set.") + + return warnings diff --git a/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_condition.gd b/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_condition.gd index b768a1e..c03f513 100644 --- a/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_condition.gd +++ b/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_condition.gd @@ -6,38 +6,41 @@ class_name LeafCondition extends BTLeaf enum ConditionTarget { - ACTOR, - CUSTOM + ACTOR, + CUSTOM } enum ConditionValue { - STRING, - INT, - FLOAT, - BOOL + STRING, + INT, + FLOAT, + BOOL } enum ConditionType { - EQUAL, - NOT_EQUAL, - GREATER, - GREATER_EQUAL, - LESS, - LESS_EQUAL + EQUAL, + NOT_EQUAL, + GREATER, + GREATER_EQUAL, + LESS, + LESS_EQUAL } ## The property of the target node to query. -@export var condition_property: StringName +@export var condition_property: StringName: + set(value): + condition_property = value + update_configuration_warnings() ## The type of comparison to perform. @export var condition_type: ConditionType = ConditionType.EQUAL ## The type of the value to compare to. @export var value_type: ConditionValue = ConditionValue.STRING: - set(value): - value_type = value - notify_property_list_changed() + set(value): + value_type = value + notify_property_list_changed() ## The string value to compare to. @export var condition_value_string: String ## The int value to compare to. @@ -49,51 +52,71 @@ enum ConditionType { @export_category("Target") ## The target node to query. If set to ACTOR, the actor will be queried. -@export var target_type: ConditionTarget = ConditionTarget.ACTOR +@export var target_type: ConditionTarget = ConditionTarget.ACTOR: + set(value): + target_type = value + update_configuration_warnings() ## The custom node to query. Only used if target_type is set to CUSTOM. -@export var custom_target: Node +@export var custom_target: Node: + set(value): + custom_target = value + update_configuration_warnings() func tick(delta: float, actor: Node, _blackboard: Blackboard): - var target: Node - match target_type: - ConditionTarget.ACTOR: - target = actor - ConditionTarget.CUSTOM: - target = custom_target - - var value: Variant - match value_type: - ConditionValue.STRING: - value = condition_value_string - ConditionValue.INT: - value = condition_value_int - ConditionValue.FLOAT: - value = condition_value_float - ConditionValue.BOOL: - value = condition_value_bool - - var property_value = target.get(condition_property) - - if property_value == null: - return BTStatus.FAILURE - - var result: bool - match condition_type: - ConditionType.EQUAL: - result = property_value == value - ConditionType.NOT_EQUAL: - result = property_value != value - ConditionType.GREATER: - result = property_value > value - ConditionType.GREATER_EQUAL: - result = property_value >= value - ConditionType.LESS: - result = property_value < value - ConditionType.LESS_EQUAL: - result = property_value <= value - - if not result: - return BTStatus.FAILURE - - return BTStatus.SUCCESS + var target: Node + match target_type: + ConditionTarget.ACTOR: + target = actor + ConditionTarget.CUSTOM: + target = custom_target + + var value: Variant + match value_type: + ConditionValue.STRING: + value = condition_value_string + ConditionValue.INT: + value = condition_value_int + ConditionValue.FLOAT: + value = condition_value_float + ConditionValue.BOOL: + value = condition_value_bool + + var property_value = target.get(condition_property) + + if property_value == null: + return BTStatus.FAILURE + + var result: bool + match condition_type: + ConditionType.EQUAL: + result = property_value == value + ConditionType.NOT_EQUAL: + result = property_value != value + ConditionType.GREATER: + result = property_value > value + ConditionType.GREATER_EQUAL: + result = property_value >= value + ConditionType.LESS: + result = property_value < value + ConditionType.LESS_EQUAL: + result = property_value <= value + + if not result: + return BTStatus.FAILURE + + return BTStatus.SUCCESS + + +func _get_configuration_warnings(): + var warnings: Array = [] + + warnings.append_array(super._get_configuration_warnings()) + + if condition_property == "": + warnings.append("Condition property is empty.") + + if target_type == ConditionTarget.CUSTOM and custom_target == null: + warnings.append("Custom target is not assigned.") + + return warnings diff --git a/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_event.gd b/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_event.gd index 055e9c2..9ab2c74 100644 --- a/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_event.gd +++ b/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_event.gd @@ -1,11 +1,26 @@ +@tool class_name LeafFSMEvent extends BTLeafIntegration ## This node fires an event on a state machine. -@export var event: String +@export var event: StringName: + set(value): + event = value + update_configuration_warnings() @export var return_status: BTStatus = BTStatus.SUCCESS func tick(_delta: float, _actor: Node, _blackboard: Blackboard) -> BTStatus: state_machine.fire_event(event) return return_status + + +func _get_configuration_warnings(): + var warnings: Array = [] + + warnings.append_array(super._get_configuration_warnings()) + + if event == "": + warnings.append("Event is empty.") + + return warnings diff --git a/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_print.gd b/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_print.gd index 987d5d5..cd5bdcb 100644 --- a/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_print.gd +++ b/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_print.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTLeafPrint.svg") class_name LeafPrint extends BTLeaf diff --git a/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_signal.gd b/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_signal.gd index c8ed02c..969a4bc 100644 --- a/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_signal.gd +++ b/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_signal.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTLeafSignal.svg") class_name LeafSignal extends BTLeaf ## Leaf that emits a signal with optional array of arguments. @@ -22,17 +23,26 @@ signal leaf_emitted(arguments_array: Array) ## The signal name to call on the target node. -@export var signal_name: StringName +@export var signal_name: StringName: + set(value): + signal_name = value + update_configuration_warnings() ## Array of arguments emitted with the [code]leaf_emitted/code] signal. @export var arguments: Array = [] @export_category("Target") ## The target type to emit signal. Can be the actor, a custom node ## or [LeafSignal] own signal `leaf_emitted` (When target type is `Self`). -@export var target_type: EmitTarget = EmitTarget.SELF +@export var target_type: EmitTarget = EmitTarget.SELF: + set(value): + target_type = value + update_configuration_warnings() ## The custom node to call the method on. Only used if target_type ## is set toCallTarget.CUSTOM. -@export var custom_target: Node +@export var custom_target: Node: + set(value): + custom_target = value + update_configuration_warnings() @@ -57,3 +67,16 @@ func tick(_delta: float, _actor: Node, _blackboard: Blackboard) -> BTStatus: return BTStatus.SUCCESS + +func _get_configuration_warnings(): + var warnings: Array = [] + + warnings.append_array(super._get_configuration_warnings()) + + if signal_name == "": + warnings.append("Signal is not set.") + + if target_type == EmitTarget.CUSTOM and custom_target == null: + warnings.append("Target type is set to Custom but no custom target is set.") + + return warnings diff --git a/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_tween.gd b/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_tween.gd index 15533d7..2f67890 100644 --- a/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_tween.gd +++ b/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_tween.gd @@ -27,7 +27,10 @@ const DEFAULT_CUSTOM_SCRIPT = "# Custom Tween Value\nstatic func get_tween_value @export var duration: float = 2.0 ## The property to tween. ## For example: "rotation:y" or "scale" -@export var tween_property: String +@export var tween_property: String: + set(value): + tween_property = value + update_configuration_warnings() ## The value type of the tween. @export var tween_value_type: TweenValueType: set = set_tween_value_type ## The integer value to tween to. @@ -123,3 +126,14 @@ func _init_tween(actor: Node, blackboard: Blackboard): tween.tween_property(actor, tween_property, tween_value, duration).as_relative() else: tween.tween_property(actor, tween_property, tween_value, duration) + + +func _get_configuration_warnings(): + var warnings: Array = [] + + warnings.append_array(super._get_configuration_warnings()) + + if tween_property == "": + warnings.append("Tween property is empty.") + + return warnings diff --git a/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_wait.gd b/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_wait.gd index fae3108..2c07b48 100644 --- a/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_wait.gd +++ b/addons/behaviour_toolkit/behaviour_tree/leaves/leaf_wait.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/BTLeafWait.svg") class_name LeafWait extends BTLeaf diff --git a/addons/behaviour_toolkit/finite_state_machine/fsm.gd b/addons/behaviour_toolkit/finite_state_machine/fsm.gd index 3c70461..ed254ef 100644 --- a/addons/behaviour_toolkit/finite_state_machine/fsm.gd +++ b/addons/behaviour_toolkit/finite_state_machine/fsm.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/FiniteStateMachine.svg") class_name FiniteStateMachine extends BehaviourToolkit ## An implementation of a simple finite state machine. @@ -33,8 +34,10 @@ signal state_changed(state: FSMState) ## Whether the FSM is active or not. @export var active: bool = true ## The initial state of the FSM. -@export var initial_state: FSMState - +@export var initial_state: FSMState: + set(value): + initial_state = value + update_configuration_warnings() ## The actor of the FSM. @export var actor: Node ## The blackboard of the FSM. @@ -52,6 +55,12 @@ var current_bt_status: BTBehaviour.BTStatus func _ready() -> void: + # Don't run in editor + if Engine.is_editor_hint(): + set_physics_process(false) + set_process(false) + return + connect("state_changed", _on_state_changed) if blackboard == null: @@ -163,3 +172,21 @@ func _setup_processing() -> void: func _on_state_changed(state: FSMState) -> void: pass + + +func _get_configuration_warnings() -> PackedStringArray: + var warnings: Array = [] + + if not initial_state: + warnings.append("Initial state is not set.") + + var children: Array = get_children() + + if children.size() == 0: + warnings.append("No states found.") + + for child in children: + if not child is FSMState: + warnings.append("Node '" + child.get_name() + "' is not a FSMState.") + + return warnings diff --git a/addons/behaviour_toolkit/finite_state_machine/fsm_state.gd b/addons/behaviour_toolkit/finite_state_machine/fsm_state.gd index 9128f33..c95eb95 100644 --- a/addons/behaviour_toolkit/finite_state_machine/fsm_state.gd +++ b/addons/behaviour_toolkit/finite_state_machine/fsm_state.gd @@ -1,3 +1,4 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/FSMState.svg") class_name FSMState extends BehaviourToolkit ## A state in a [FiniteStateMachine]. @@ -8,6 +9,10 @@ var transitions: Array[FSMTransition] = [] func _ready() -> void: + # Don't run in editor + if Engine.is_editor_hint(): + return + for transition in get_children(): if transition is FSMTransition: transitions.append(transition) @@ -26,3 +31,13 @@ func _on_update(_delta: float, _actor: Node, _blackboard: Blackboard) -> void: ## Executes before the state is exited. func _on_exit(_actor: Node, _blackboard: Blackboard) -> void: pass + + +func _get_configuration_warnings(): + var warnings = [] + + var parent: Node = get_parent() + if not parent is FiniteStateMachine: + warnings.append("FSMState should be a child of a FiniteStateMachine node.") + + return warnings diff --git a/addons/behaviour_toolkit/finite_state_machine/fsm_state_integrated_bt.gd b/addons/behaviour_toolkit/finite_state_machine/fsm_state_integrated_bt.gd index 0dfe27d..c2add34 100644 --- a/addons/behaviour_toolkit/finite_state_machine/fsm_state_integrated_bt.gd +++ b/addons/behaviour_toolkit/finite_state_machine/fsm_state_integrated_bt.gd @@ -1,14 +1,20 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/FSMStateIntegration.svg") class_name FSMStateIntegratedBT extends FSMState - @onready var behaviour_tree: BTRoot = _get_behaviour_tree() -@export var fire_event_on_status: bool = false +@export var fire_event_on_status: bool = false: + set(value): + fire_event_on_status = value + update_configuration_warnings() @export var on_status: BTBehaviour.BTStatus = BTBehaviour.BTStatus.SUCCESS -@export var event: String +@export var event: String: + set(value): + event = value + update_configuration_warnings() ## Executes after the state is entered. @@ -29,6 +35,10 @@ func _on_exit(_actor: Node, _blackboard: Blackboard) -> void: func _get_behaviour_tree() -> BTRoot: + # Don't run in editor + if Engine.is_editor_hint(): + return null + if get_child_count() == 0: return null @@ -37,3 +47,25 @@ func _get_behaviour_tree() -> BTRoot: return child return null + +func _get_configuration_warnings(): + var warnings: Array = [] + + warnings.append_array(super._get_configuration_warnings()) + + var children: Array = get_children() + + var has_root: bool = false + for child in children: + if child is BTRoot: + has_root = true + elif not child is FSMTransition: + warnings.append("FSMStateIntegratedBT can only have BTRoot and FSMTransition children.") + + if not has_root: + warnings.append("FSMStateIntegratedBT must have a BTRoot child node.") + + if fire_event_on_status and event == "": + warnings.append("FSMStateIntegratedBT has fire_event_on_status enabled, but no event is set.") + + return warnings diff --git a/addons/behaviour_toolkit/finite_state_machine/fsm_state_integration_return.gd b/addons/behaviour_toolkit/finite_state_machine/fsm_state_integration_return.gd index ff0011b..f16066e 100644 --- a/addons/behaviour_toolkit/finite_state_machine/fsm_state_integration_return.gd +++ b/addons/behaviour_toolkit/finite_state_machine/fsm_state_integration_return.gd @@ -22,3 +22,16 @@ func _on_update(_delta: float, _actor: Node, _blackboard: Blackboard) -> void: ## Executes before the state is exited. func _on_exit(_actor: Node, _blackboard: Blackboard) -> void: pass + + +func _get_configuration_warnings(): + var warnings: Array = [] + + warnings.append_array(super._get_configuration_warnings()) + + var fsm_parent: Node = get_parent().get_parent() + + if not fsm_parent is BTIntegratedFSM: + warnings.append("Can only return from a BTIntegratedFSM.") + + return warnings diff --git a/addons/behaviour_toolkit/finite_state_machine/fsm_transition.gd b/addons/behaviour_toolkit/finite_state_machine/fsm_transition.gd index 7971efe..97995f8 100644 --- a/addons/behaviour_toolkit/finite_state_machine/fsm_transition.gd +++ b/addons/behaviour_toolkit/finite_state_machine/fsm_transition.gd @@ -1,16 +1,26 @@ +@tool @icon("res://addons/behaviour_toolkit/icons/FSMTransition.svg") class_name FSMTransition extends BehaviourToolkit ## A transition between two [FSMState]s in a [FiniteStateMachine]. ## The state to transition to. -@export var next_state: FSMState +@export var next_state: FSMState: + set(value): + next_state = value + update_configuration_warnings() @export_category("Transition Logic") ## If true, the FSM will check for the event to trigger the transition. -@export var use_event: bool = false +@export var use_event: bool = false: + set(value): + use_event = value + update_configuration_warnings() ## The event that triggers the transition. -@export var event: String = "" +@export var event: String = "": + set(value): + event = value + update_configuration_warnings() ## Executed when the transition is taken. @@ -33,3 +43,19 @@ func is_valid_event(current_event: String) -> bool: ## Returns which state to transition to, when valid. func get_next_state() -> FSMState: return next_state + + +func _get_configuration_warnings(): + var warnings = [] + + var parent: Node = get_parent() + if not parent is FSMState: + warnings.append("FSMTransition should be a child of FSMState.") + + if not next_state: + warnings.append("FSMTransition has no next state.") + + if use_event and event == "": + warnings.append("FSMTransition has no event set.") + + return warnings diff --git a/script_templates/BTComposite/new_composite.gd b/script_templates/BTComposite/new_composite.gd index 0765848..7fbb7df 100644 --- a/script_templates/BTComposite/new_composite.gd +++ b/script_templates/BTComposite/new_composite.gd @@ -1,3 +1,4 @@ +@tool extends BTComposite @@ -8,3 +9,15 @@ func tick(_delta: float, _actor: Node, _blackboard: Blackboard) -> BTStatus: # Return BTStatus depending on the result of the leaves # Return BTStatus.RUNNING, if there are still leaves to tick return BTStatus.SUCCESS + + +# Add custom configuration warnings +# Note: Can be deleted if you don't want to define your own warnings. +func _get_configuration_warnings(): + var warnings: Array = [] + + warnings.append_array(super._get_configuration_warnings()) + + # Add your own warnings to the array here + + return warnings diff --git a/script_templates/BTDecorator/new_decorator.gd b/script_templates/BTDecorator/new_decorator.gd index 91cc4e8..6315d99 100644 --- a/script_templates/BTDecorator/new_decorator.gd +++ b/script_templates/BTDecorator/new_decorator.gd @@ -1,3 +1,4 @@ +@tool extends BTDecorator @@ -9,3 +10,15 @@ func tick(_delta: float, _actor: Node, _blackboard: Blackboard) -> BTStatus: # Augment the response of the leaf return response + + +# Add custom configuration warnings +# Note: Can be deleted if you don't want to define your own warnings. +func _get_configuration_warnings(): + var warnings: Array = [] + + warnings.append_array(super._get_configuration_warnings()) + + # Add your own warnings to the array here + + return warnings diff --git a/script_templates/BTLeaf/new_leaf.gd b/script_templates/BTLeaf/new_leaf.gd index fe8c488..7d0d4be 100644 --- a/script_templates/BTLeaf/new_leaf.gd +++ b/script_templates/BTLeaf/new_leaf.gd @@ -1,3 +1,4 @@ +@tool extends BTLeaf @@ -6,3 +7,15 @@ func tick(_delta: float, _actor: Node, _blackboard: Blackboard) -> BTStatus: # Handle leaf logic # Return SUCCESS, FAILURE, or RUNNING return BTStatus.SUCCESS + + +# Add custom configuration warnings +# Note: Can be deleted if you don't want to define your own warnings. +func _get_configuration_warnings(): + var warnings: Array = [] + + warnings.append_array(super._get_configuration_warnings()) + + # Add your own warnings to the array here + + return warnings diff --git a/script_templates/FSMState/new_state.gd b/script_templates/FSMState/new_state.gd index 0d00ace..4e52802 100644 --- a/script_templates/FSMState/new_state.gd +++ b/script_templates/FSMState/new_state.gd @@ -1,3 +1,4 @@ +@tool extends FSMState @@ -14,3 +15,15 @@ func _on_update(_delta: float, _actor: Node, _blackboard: Blackboard) -> void: # Executes before the state is exited. func _on_exit(_actor: Node, _blackboard: Blackboard) -> void: pass + + +# Add custom configuration warnings +# Note: Can be deleted if you don't want to define your own warnings. +func _get_configuration_warnings(): + var warnings: Array = [] + + warnings.append_array(super._get_configuration_warnings()) + + # Add your own warnings to the array here + + return warnings diff --git a/script_templates/FSMTransition/new_transition.gd b/script_templates/FSMTransition/new_transition.gd index 2061de0..de5fe45 100644 --- a/script_templates/FSMTransition/new_transition.gd +++ b/script_templates/FSMTransition/new_transition.gd @@ -1,3 +1,4 @@ +@tool extends FSMTransition # Executed when the transition is taken. @@ -8,3 +9,15 @@ func _on_transition(_delta: float, _actor: Node, _blackboard: Blackboard) -> voi # Evaluates true, if the transition conditions are met. func is_valid(_actor: Node, _blackboard: Blackboard) -> bool: return false + + +# Add custom configuration warnings +# Note: Can be deleted if you don't want to define your own warnings. +func _get_configuration_warnings(): + var warnings: Array = [] + + warnings.append_array(super._get_configuration_warnings()) + + # Add your own warnings to the array here + + return warnings