tactree/init.lua

226 lines
5.0 KiB
Lua
Raw Normal View History

2024-06-23 13:13:16 +00:00
local Tactree = {}
2024-06-24 18:02:39 +00:00
local Nodes = {}
2024-06-23 13:13:16 +00:00
local function NodeReset(node)
node:_finish()
node._started = false
end
2024-06-23 13:13:16 +00:00
local function NodeStart(node, args)
2024-06-30 22:23:36 +00:00
-- don't start again if started
2024-07-12 12:19:42 +00:00
if node._started then return end
2024-06-23 13:13:16 +00:00
2024-07-12 12:19:42 +00:00
node.data = node.parent and node.parent.data or args or node.data
node.data[node] = node.data[node] or {}
2024-06-23 13:13:16 +00:00
node:_start()
2024-07-12 12:19:42 +00:00
node._started = true
2024-06-23 13:13:16 +00:00
end
2024-07-12 12:19:42 +00:00
local function NodeUpdate(node, ...)
-- automatically start if not started
if not node._started then
NodeStart(node)
end
-- mark node as run and unmark children
node._ran = true
for _, child in ipairs(node.children) do
child._ran = false
end
2024-06-23 13:13:16 +00:00
2024-07-12 12:19:42 +00:00
local result = node:_tick(...)
2024-06-23 13:13:16 +00:00
if result ~= nil then
NodeReset(node)
end
2024-06-23 13:13:16 +00:00
-- reset unrun children
for _, child in ipairs(node.children) do
if not child._ran and child._started then
NodeReset(child)
end
2024-06-23 13:13:16 +00:00
end
return result
end
2024-06-24 03:53:32 +00:00
local function NodePrivateData(node)
return node.data[node]
end
2024-06-23 13:13:16 +00:00
local function default_impl(node) end
2024-06-24 03:53:32 +00:00
function Tactree.Leaf(name)
2024-06-23 13:13:16 +00:00
return function(t)
2024-06-24 18:02:39 +00:00
if Nodes[name] then
2024-06-23 13:13:16 +00:00
error('node with name \'' .. name .. '\' already exists.', 2)
else
2024-06-24 18:02:39 +00:00
Nodes[name] = {}
2024-06-23 13:13:16 +00:00
end
2024-06-24 18:02:39 +00:00
local node_type = Nodes[name]
2024-06-23 13:13:16 +00:00
local tick = t.tick or t[1]
if type(tick) ~= 'function' then error('no tick function supplied', 2) end
node_type._tick = tick
node_type._start = type(t.start) == 'function' and t.start or default_impl
node_type._finish = type(t.finish) == 'function' and t.finish or default_impl
end
end
2024-06-24 03:53:32 +00:00
function Tactree.Composite(name)
return function(parent_type_name)
return function(children)
2024-06-24 18:02:39 +00:00
if Nodes[name] then
2024-06-24 03:53:32 +00:00
error('node with name \'' .. name .. '\' already exists.', 2)
else
if not Nodes[parent_type_name] then error('no such node \'' .. parent_type_name .. '\'', 2) end
2024-06-24 18:02:39 +00:00
Nodes[name] = setmetatable({}, { __index = Nodes[parent_type_name] })
2024-06-24 03:53:32 +00:00
end
2024-06-24 18:02:39 +00:00
local node_type = Nodes[name]
2024-06-24 03:53:32 +00:00
node_type.children = {}
for _, child in ipairs(children) do
if type(child) ~= 'string' then error('invalid child node', 2) end
table.insert(node_type.children, child)
end
end
end
end
2024-07-12 12:19:42 +00:00
local function tree_by_name(name, depth)
depth = depth or 2
if not Nodes[name] then error('no such node \'' .. name .. '\'', depth) end
2024-06-23 13:13:16 +00:00
2024-06-24 03:53:32 +00:00
local node = {}
2024-06-23 13:13:16 +00:00
node.children = {}
node.start = NodeStart
node.update = NodeUpdate
2024-06-24 03:53:32 +00:00
node.private = NodePrivateData
2024-06-23 13:13:16 +00:00
-- this will crash if there is a recursive structure; find a way to prevent this?
-- does my API even allow declaring recursive structures?
2024-06-24 18:02:39 +00:00
if Nodes[name].children then
for _, child in ipairs(Nodes[name].children) do
2024-07-12 12:19:42 +00:00
local cn = tree_by_name(child, depth + 1)
2024-06-24 18:02:39 +00:00
cn.parent = node
table.insert(node.children, cn)
2024-06-23 13:13:16 +00:00
end
end
2024-06-24 03:53:32 +00:00
2024-06-30 22:23:36 +00:00
return setmetatable(node, { __index = Nodes[name], __tostring = function() return name end })
2024-06-23 13:13:16 +00:00
end
2024-07-12 12:19:42 +00:00
function Tactree.Tree(name)
if not Nodes[name] then error('no such node \'' .. name .. '\'', 2) end
2024-06-24 18:02:39 +00:00
2024-07-12 12:19:42 +00:00
return function(children)
local node = {}
node.children = {}
node.start = NodeStart
node.update = NodeUpdate
node.private = NodePrivateData
-- add pre-defined children
if Nodes[name].children then
for _, child in ipairs(Nodes[name].children) do
local cn = tree_by_name(child, 3)
cn.parent = node
table.insert(node.children, cn)
2024-06-24 18:02:39 +00:00
end
end
2024-07-12 12:19:42 +00:00
-- add extra children from call
for _, child in ipairs(children) do
local cn
if type(child) == 'string' then
cn = tree_by_name(child, 3)
elseif type(child) == 'table' then
cn = child
2024-06-27 19:31:21 +00:00
else
2024-07-12 12:19:42 +00:00
error('invalid child type: \'' .. type(child) '\'', 3)
2024-06-27 19:31:21 +00:00
end
2024-07-12 12:19:42 +00:00
cn.parent = node
table.insert(node.children, cn)
end
2024-06-30 22:23:36 +00:00
2024-07-12 12:19:42 +00:00
return setmetatable(node, { __index = Nodes[name], __tostring = function() return name end })
2024-06-30 22:23:36 +00:00
end
2024-07-12 12:19:42 +00:00
end
2024-06-30 22:23:36 +00:00
2024-07-12 12:19:42 +00:00
Tactree.Leaf 'Sequence'
{
function(node, ...)
local child = 1
local result
repeat
result = node.children[child]:update(...)
child = child + 1
until (not result) or (child > #node.children)
return result
end
}
Tactree.Leaf 'StepSequence'
2024-06-24 18:02:39 +00:00
{
start = function(node)
2024-07-12 12:19:42 +00:00
node:private().current_child = 1
2024-06-24 18:02:39 +00:00
end,
2024-07-12 12:19:42 +00:00
tick = function(node, ...)
local result
repeat
result = node.children[node:private().current_child]:update(...)
if result ~= nil then node:private().current_child = node:private().current_child + 1 end
2024-07-12 12:19:42 +00:00
until (not result) or (node:private().current_child > #node.children)
return result
2024-06-27 19:31:21 +00:00
end
}
2024-07-12 12:19:42 +00:00
Tactree.Leaf 'Selector'
{
function(node, ...)
local child = 1
local result
repeat
result = node.children[child]:update(...)
child = child + 1
until (result ~= false) or (child > #node.children)
return result
end
}
Tactree.Leaf 'StepSelector'
2024-06-27 19:31:21 +00:00
{
start = function(node)
2024-07-12 12:19:42 +00:00
node:private().current_child = 1
2024-06-27 19:31:21 +00:00
end,
2024-07-12 12:19:42 +00:00
tick = function(node, ...)
local result
repeat
result = node.children[node:private().current_child]:update(...)
if result ~= nil then node:private().current_child = node:private().current_child + 1 end
2024-07-12 12:19:42 +00:00
until (result ~= false) or (node:private().current_child > #node.children)
return result
2024-06-24 18:02:39 +00:00
end
}
2024-07-12 12:19:42 +00:00
Tactree.Leaf 'Inverter'
2024-06-27 19:31:21 +00:00
{
function(node, ...)
2024-07-12 12:19:42 +00:00
local result = node.children[1]:update(...)
2024-06-27 19:31:21 +00:00
if result ~= nil then return not result end
2024-06-27 19:31:21 +00:00
end
}
2024-06-23 13:13:16 +00:00
return Tactree