Allow reuse of composite nodes

This commit is contained in:
Shylie 2024-06-23 23:53:32 -04:00
parent d3e1c8e711
commit fa96a38a1d

View File

@ -1,11 +1,12 @@
local Tactree = {} local Tactree = {}
local Registry = {} Tactree.Nodes = {}
local function NodeStart(node, args) local function NodeStart(node, args)
-- abort if started -- abort if started
if node.data then return end if node.data then return end
node.data = node.parent and node.parent.data or args node.data = node.parent and node.parent.data or args
node.data[node] = {}
node:_start() node:_start()
end end
@ -24,16 +25,20 @@ local function NodeUpdate(node)
return result return result
end end
local function NodePrivateData(node)
return node.data[node]
end
local function default_impl(node) end local function default_impl(node) end
function Tactree.Node(name) function Tactree.Leaf(name)
return function(t) return function(t)
if Registry[name] then if Tactree.Nodes[name] then
error('node with name \'' .. name .. '\' already exists.', 2) error('node with name \'' .. name .. '\' already exists.', 2)
else else
Registry[name] = {} Tactree.Nodes[name] = {}
end end
local node_type = Registry[name] local node_type = Tactree.Nodes[name]
local tick = t.tick or t[1] local tick = t.tick or t[1]
if type(tick) ~= 'function' then error('no tick function supplied', 2) end if type(tick) ~= 'function' then error('no tick function supplied', 2) end
@ -44,40 +49,59 @@ function Tactree.Node(name)
end end
end end
function Tactree.Tree(name) function Tactree.Composite(name)
if not Registry[name] then error('no such node \'' .. name .. '\'', 2) end return function(parent_type_name)
return function(children)
if Tactree.Nodes[name] then
error('node with name \'' .. name .. '\' already exists.', 2)
else
if not Tactree.Nodes[parent_type_name] then error('no such node \'' .. name .. '\'', 2) end
Tactree.Nodes[name] = setmetatable({}, Tactree.Nodes[parent_type_name])
end
local node = setmetatable({}, { __index = Registry[name] }) local node_type = Tactree.Nodes[name]
node.children = {}
node.start = NodeStart node_type.children = {}
node.update = NodeUpdate
return function(children)
if type(children) == 'table' then
for _, child in ipairs(children) do for _, child in ipairs(children) do
if type(child) == 'string' then if type(child) ~= 'string' then error('invalid child node', 2) end
child = Tactree.Tree(child)
elseif type(child) ~= 'table' then
error('invalid child type: ' .. type(child), 2)
end
child.parent = node table.insert(node_type.children, child)
table.insert(node.children, child)
end end
end end
return node
end end
end end
function Tactree.Tree(name)
if not Tactree.Nodes[name] then error('no such node \'' .. name .. '\'', 2) end
local node = {}
node.children = {}
node.start = NodeStart
node.update = NodeUpdate
node.private = NodePrivateData
if Tactree.Nodes[name].children then
for _, child in ipairs(Tactree.Nodes[name].children) do
table.insert(node.children, Tactree.Tree(child))
end
end
return setmetatable(node, { __index = Tactree.Nodes[name] })
end
--[[ --[[
Tactree.Node 'Find nearest object' { function (node) ... end } Example usage
Tactree.Node 'Pick up object' { function (node) ... end} -------------
Tactree.Node 'Move' { function (node) return node.data.creature:move(node.data.tx, node.data.ty, dt) end }
local t = Tactree.Tree 'Sequence' { 'Find nearest object', 'Move', 'Pick up object' } Tactree.Leaf 'Find nearest object' { function (node) ... end }
Tactree.Leaf 'Pick up object' { function (node) ... end}
Tactree.Leaf 'Move' { function (node) return node.data.creature:move(node.data.tx, node.data.ty, dt) end }
Tactree.Composite 'Pick up nearest object' 'Sequence' { 'Find nearest object', 'Move', 'Pick up object' }
t:start(...) local tr = Tactree.Tree 'Pick up nearest object'
tr:start{ ... } ( or, if you already have a table, tr:start(existing_table) )
t:update() t:update()
]]-- ]]--