You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 2e63a35
Browse filesBrowse the repository at this point in the historyBrowse files
authored
Add _onlyIf and _onStart preconditions (#820, #895) (#1261)
* Add _onlyIf and _onStart preconditions (#820, #895)
- `_onlyIf="<script>"`: if false when the node is IDLE, return SKIPPED
(the opposite of `_skipIf`, more readable in most cases).
- `_onStart="<script>"`: execute a script right before the first tick() of
the node, i.e. only if no other precondition returned a status. Useful
to initialize or reset blackboard entries.
Both are evaluated only when the node is IDLE/SKIPPED, like `_skipIf`.
ONLY_IF and ON_START are appended at the end of PreCond, so the values of
the existing ones don't change. Appending ONLY_IF after WHILE_TRUE keeps
the semantics: SKIP_IF, WHILE_TRUE and ONLY_IF all return SKIPPED.
Behavior change: the attribute names `_onlyIf` and `_onStart` are now
reserved. Before, they were stored silently as non-port attributes and
did nothing.
Supersedes #821 and #932.
Co-Authored-By: Darko Lukic <2135826+lukicdarkoo@users.noreply.github.com>
Co-Authored-By: Aglargil <34728006+Aglargil@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Preconditions: static_assert on name arrays, fix _onStart comment, document _onStart/_onlyIf caveats
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: cover _onlyIf/_onStart edge cases (while-interrupt, SubTree, ReactiveSequence, WriteTreeToXML)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Darko Lukic <2135826+lukicdarkoo@users.noreply.github.com>
Co-authored-by: Aglargil <34728006+Aglargil@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/pre_postconditions.md
+24-3Lines changed: 24 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -14,6 +14,8 @@ Pre-conditions are evaluated **before** a node's `tick()` method is called. They
14
14
|`_successIf`| IDLE only | If true, return SUCCESS without calling tick() |
15
15
|`_skipIf`| IDLE only | If true, return SKIPPED without calling tick() |
16
16
|`_while`| IDLE and RUNNING | If false when IDLE, return SKIPPED. If false when RUNNING, halt node and return SKIPPED |
17
+
|`_onlyIf`| IDLE only | If false, return SKIPPED without calling tick() (the opposite of `_skipIf`) |
18
+
|`_onStart`| IDLE only | Not a condition: execute the script right before the first tick() |
17
19
18
20
### Evaluation Order
19
21
@@ -22,12 +24,16 @@ When a node has multiple pre-conditions, they are evaluated in this order:
22
24
2.`_successIf`
23
25
3.`_skipIf`
24
26
4.`_while`
27
+
5.`_onlyIf`
28
+
6.`_onStart`
25
29
26
-
The first condition that triggers will determine the result.
30
+
The first condition that triggers will determine the result. `_onStart` comes last,
31
+
so its script is executed only if no other pre-condition has short-circuited the node.
32
+
If both `_skipIf` and `_onlyIf` are present, either one can skip the node.
27
33
28
34
### Important: One-time Evaluation
29
35
30
-
**`_failureIf`, `_successIf`, and `_skipIf` are evaluated only once** when the node transitions from IDLE (or SKIPPED) to another state. They are **NOT re-evaluated** while the node is RUNNING.
36
+
**`_failureIf`, `_successIf`, `_skipIf`, `_onlyIf`and `_onStart` are evaluated only once** when the node transitions from IDLE (or SKIPPED) to another state. They are **NOT re-evaluated** while the node is RUNNING.
31
37
32
38
This means if you have:
33
39
```xml
@@ -48,10 +54,25 @@ If `battery_ok` becomes false while `MyAction` is running, the action is interru
48
54
49
55
### When to Use Each Pre-condition
50
56
51
-
-**`_skipIf`**: Skip a node without failing the parent (useful in Sequences)
57
+
-**`_skipIf`** / **`_onlyIf`**: Skip a node without failing the parent (useful in Sequences)
52
58
-**`_failureIf`**: Fail early based on a condition (useful in Fallbacks)
53
59
-**`_successIf`**: Succeed early based on a condition
54
60
-**`_while`**: Guard that must remain true for the entire execution
61
+
-**`_onStart`**: Initialize or reset blackboard entries when the node starts,
62
+
e.g. `<MyAction _onStart="attempts := 0"/>`
63
+
64
+
### Notes on `_onStart`
65
+
66
+
- It runs **every time the node starts from IDLE**, not once per tree execution. Inside a
67
+
`Retry` or `Repeat`, the child goes back to IDLE after each iteration, so
68
+
`_onStart="attempts := 0"` is re-executed on every iteration.
69
+
Likewise, a node placed before a RUNNING sibling in a `ReactiveSequence` is halted and
70
+
re-ticked from IDLE on every tick, so its `_onStart` runs on every tick.
71
+
- It runs just before `tick()`, but a pre-tick callback (see `setPreTickFunction()`, used for
72
+
instance by Groot2 breakpoints and status injection) may still substitute the result after
73
+
`_onStart` has run, in which case `tick()` is not called.
74
+
-`ThreadedAction` does not evaluate any pre-condition, `_onlyIf` and `_onStart` included:
75
+
it runs `tick()` in its own thread, bypassing the pre/post-condition checks.
0 commit comments