-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
behaviortree.go
99 lines (88 loc) · 2.15 KB
/
behaviortree.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package behaviortree
import (
"errors"
"fmt"
)
const (
_Status = iota
// Running indicates that the Tick for a given Node is currently running
Running
// Success indicates that the Tick for a given Node completed successfully
Success
// Failure indicates that the Tick for a given Node failed to complete successfully
Failure
)
type (
// Node represents an node in a tree, that can be ticked
Node func() (Tick, []Node)
// Tick represents the logic for a node, which may or may not be stateful
Tick func(children []Node) (Status, error)
// Status is a type with three valid values, Running, Success, and Failure, the three possible states for BTs
Status int
)
// New constructs a new behavior tree and is equivalent to NewNode with vararg support for less indentation
func New(tick Tick, children ...Node) Node {
return factory(tick, children)
}
func NewNode(tick Tick, children []Node) Node { return factory(tick, children) }
var factory = func(tick Tick, children []Node) (node Node) {
var (
frame *Frame
)
if v := make([]uintptr, 1); runtimeCallers(3, v[:]) >= 1 {
if v, _ := runtimeCallersFrames(v).Next(); v.PC != 0 {
frame = &Frame{
PC: v.PC,
Function: v.Function,
File: v.File,
Line: v.Line,
Entry: v.Entry,
}
}
}
node = func() (Tick, []Node) {
if frame != nil {
node.valueHandle(func(key interface{}) (interface{}, bool) {
if key != (vkFrame{}) {
return nil, false
}
frame := *frame
return &frame, true
})
}
return tick, children
}
return
}
func (n Node) Tick() (Status, error) {
if n == nil {
return Failure, errors.New("behaviortree.Node cannot tick a nil node")
}
tick, children := n()
if tick == nil {
return Failure, errors.New("behaviortree.Node cannot tick a node with a nil tick")
}
return tick(children)
}
func (s Status) Status() Status {
switch s {
case Running:
return Running
case Success:
return Success
default:
return Failure
}
}
func (s Status) String() string {
switch s {
case Running:
return `running`
case Success:
return `success`
case Failure:
return `failure`
default:
return fmt.Sprintf("unknown status (%d)", s)
}
}