diff --git a/CHANGES.md b/CHANGES.md index e484c19..a56cb79 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,12 +5,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +### Fixed +- The state chart now issues a better error message when being called while not yet ready ([#81](https://github.com/derkork/godot-statecharts/issues/81)). ### Improved - The history in the state chart debugger now uses little icons to show the type history entry. This makes it easier to see what happened at a glance. A big thanks goes out to [Alireza Zamani](https://github.com/alitnk) for suggesting this improvement. ## [0.13.0] - 2024-01-30 ### Breaking Change -- You can now have fully automatic transitions ([#71]((https://github.com/derkork/godot-statecharts/issues/71))). An automatic transition has no event and will be executed when the state is entered, any event is sent or any expression property is modified. Note that a state must be active for its automatic transitions to be considered. +- You can now have fully automatic transitions ([#71](https://github.com/derkork/godot-statecharts/issues/71)). An automatic transition has no event and will be executed when the state is entered, any event is sent or any expression property is modified. Note that a state must be active for its automatic transitions to be considered. This change can potentially break existing state charts which have transitions with no event. Before this change, these transitions were only executed when the state was entered. After this change, there are more situations in which these transitions can be executed, so you might have to add additional guards to your transitions or use the `state_entered` signal to trigger your logic. diff --git a/addons/godot_state_charts/state_chart.gd b/addons/godot_state_charts/state_chart.gd index d5853e8..5a01225 100644 --- a/addons/godot_state_charts/state_chart.gd +++ b/addons/godot_state_charts/state_chart.gd @@ -82,8 +82,12 @@ func _ready() -> void: ## will process the event as soon as possible but there is no guarantee that the ## event will be fully processed when this method returns. func send_event(event:StringName) -> void: + if not is_node_ready(): + push_error("State chart is not yet ready. If you call `send_event` in _ready, please call it deferred, e.g. `state_chart.send_event.call_deferred(\"my_event\").") + return + if not is_instance_valid(_state): - push_error("StateMachine is not initialized") + push_error("State chart has no root state. Ignoring call to `send_event`.") return if _event_processing_active: @@ -146,6 +150,14 @@ func _warn_not_active(transition:Transition, source:State): ## with the same name. E.g. if you set the property "foo" to 42, you can use the expression "foo == 42" in ## an expression guard. func set_expression_property(name:StringName, value) -> void: + if not is_node_ready(): + push_error("State chart is not yet ready. If you call `set_expression_property` in `_ready`, please call it deferred, e.g. `state_chart.set_expression_property.call_deferred(\"my_property\", 5).") + return + + if not is_instance_valid(_state): + push_error("State chart has no root state. Ignoring call to `set_expression_property`.") + return + _expression_properties[name] = value # run a property change event through the state chart to run automatic transitions _state._process_transitions(&"", true) @@ -154,6 +166,13 @@ func set_expression_property(name:StringName, value) -> void: ## Calls the `step` function in all active states. Used for situations where `state_processing` and ## `state_physics_processing` don't make sense (e.g. turn-based games, or games with a fixed timestep). func step(): + if not is_node_ready(): + push_error("State chart is not yet ready. If you call `step` in `_ready`, please call it deferred, e.g. `state_chart.step.call_deferred()`.") + return + + if not is_instance_valid(_state): + push_error("State chart has no root state. Ignoring call to `step`.") + return _state._state_step() func _get_configuration_warnings() -> PackedStringArray: diff --git a/manual/manual.md b/manual/manual.md index 254117a..668651a 100644 --- a/manual/manual.md +++ b/manual/manual.md @@ -267,7 +267,7 @@ In deeper state charts, events will be passed to the active states going all the > ⚠️ **Note:** The initial state of a state chart will only be entered one frame after the state chart's `_ready` function ran. It is done this way to give nodes above the state chart time to run their `_ready` functions before any state chart logic is triggered. > -> This means that if you call `send_event` in a `_ready` function it will most likely not work as expected. If you must send an event in a `_ready` function, you can use `call_deferred` to delay the event sending by one frame, e.g. `state_chart.send_event.call_deferred("some_event")`. +> This means that if you call `send_event`, `set_expression_property` or `step` in a `_ready` function things will most likely not work as expected. If you must call any of these functions in a `_ready` function, you can use `call_deferred` to delay the event sending by one frame, e.g. `state_chart.send_event.call_deferred("some_event")`. ##### Multiple transitions on the same state A single state can have multiple transitions. If this is the case, all transitions will be checked from top to bottom and the first transition that reacts to the event will be executed. If you want to have multiple transitions that react to the same event, you can use [guards](#transition-guards) to determine which transition should be taken.