Repository navigation
Expand file tree
/
Copy pathbehavior_node.lua
More file actions
143 lines (124 loc) · 3.58 KB
/
Copy pathbehavior_node.lua
File metadata and controls
143 lines (124 loc) · 3.58 KB
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
local bret = require 'behavior3.behavior_ret'
local process = require 'behavior3.sample_process'
local debugger
local sformat = string.format
local table = table
local print = print
---@class BehaviorNode
local mt = {}
mt.__index = mt
local function new_node(...)
local obj = setmetatable({}, mt)
obj:init(...)
return obj
end
function mt:init(node_data, tree)
self.tree = tree
self.name = node_data.name
self.id = node_data.id
self.info = sformat('node %s.%s %s', tree.name, self.id, self.name)
self.data = node_data
self.args = self.data.args or {}
---@type BehaviorNode[]
self.children = {}
for _, child_data in ipairs(node_data.children or {}) do
if not child_data.disabled then
local child = new_node(child_data, tree)
table.insert(self.children, child)
end
end
end
--- BehaviorNode:run()
---@param env BehaviorEnv
---@return BehaviorRet
function mt:run(env)
if env.abort then
return bret.RUNNING
end
--print("start", self.name, self.node_id)
if env:get_inner_var(self, "YIELD") == nil then
env:push_stack(self)
end
local vars = {}
for i, var_name in ipairs(self.data.input or {}) do
vars[i] = env:get_var(var_name)
end
assert(process[self.name], self.name)
local func = assert(process[self.name].run, self.name)
local ok, errmsg = xpcall(function()
if self.data.input then
vars = table.pack(func(self, env, table.unpack(vars, 1, #self.data.input)))
else
vars = table.pack(func(self, env, table.unpack(vars)))
end
end, debug.traceback)
if not ok then
error(sformat("node %s run error:%s", self.info, errmsg))
end
local ret = vars[1]
assert(ret, self.info)
if ret == bret.ABORT then
env.abort = true
return bret.RUNNING -- 为了安全退栈
end
if ret ~= bret.RUNNING then
for i, var_name in ipairs(self.data.output or {}) do
env:set_var(var_name, vars[i + 1])
end
env:set_inner_var(self, "YIELD", nil)
env:pop_stack()
elseif env:get_inner_var(self, "YIELD") == nil then
env:set_inner_var(self, "YIELD", true)
end
env.last_ret = ret
--print("fini", self.name, self.node_id, table.unpack(vars, 1, #self.data.input))
if self.data.debug then
debugger(self, env, ret)
end
return ret
end
function mt:yield(env, arg)
env:set_inner_var(self, "YIELD", arg or true)
return bret.RUNNING
end
function mt:resume(env)
return env:get_inner_var(self, "YIELD"), env.last_ret
end
function mt:get_debug_info(env, ret)
local var_str = ''
for k, v in pairs(env.vars) do
var_str = var_str .. sformat("[%s]=%s,", k, v)
end
return sformat("[DEBUG] btree:%s, ret:%s vars:{%s}", self.info, ret, var_str)
end
local btree_funcs = {}
local function btree_func(code, env)
local func = btree_funcs[code]
if not func then
code = code:gsub("!=", "~=")
func = load("return function(vars, math) _ENV = vars return " .. code .. " end")()
btree_funcs[code] = func
end
return func(env.vars, math)
end
function mt:get_env_args(key, env)
local a
if not self.data.args or not self.data.args[key] then
return
end
return btree_func(assert(self.data.args[key], key), env)
end
local M = {}
function M.new(...)
return new_node(...)
end
function M.process(custom)
process = custom
end
debugger = function(node, env, ret)
print(node:get_debug_info(env, ret))
end
function M.set_debugger(func)
debugger = func
end
return M