Add bt_assert macro for non-crashing assertions in behavior trees
This commit is contained in:
parent
95492efea7
commit
44672ac1fd
12 changed files with 148 additions and 24 deletions
|
|
@ -3,4 +3,4 @@ file(GLOB_RECURSE PSEMEK_BT_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "sour
|
||||||
|
|
||||||
psemek_add_library(psemek-bt ${PSEMEK_BT_HEADERS} ${PSEMEK_BT_SOURCES})
|
psemek_add_library(psemek-bt ${PSEMEK_BT_HEADERS} ${PSEMEK_BT_SOURCES})
|
||||||
target_include_directories(psemek-bt PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
target_include_directories(psemek-bt PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||||
target_link_libraries(psemek-bt PUBLIC psemek-util)
|
target_link_libraries(psemek-bt PUBLIC psemek-util psemek-log)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/bt/node.hpp>
|
#include <psemek/bt/node.hpp>
|
||||||
|
#include <psemek/bt/assert.hpp>
|
||||||
|
|
||||||
namespace psemek::bt
|
namespace psemek::bt
|
||||||
{
|
{
|
||||||
|
|
@ -25,7 +26,15 @@ namespace psemek::bt
|
||||||
|
|
||||||
status update(Time dt, Args ... args) override
|
status update(Time dt, Args ... args) override
|
||||||
{
|
{
|
||||||
action_fn_(dt, args...);
|
try
|
||||||
|
{
|
||||||
|
action_fn_(dt, args...);
|
||||||
|
}
|
||||||
|
catch (assertion_failed_exception const &)
|
||||||
|
{
|
||||||
|
return finished{false};
|
||||||
|
}
|
||||||
|
|
||||||
return finished{true};
|
return finished{true};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
28
libs/bt/include/psemek/bt/assert.hpp
Normal file
28
libs/bt/include/psemek/bt/assert.hpp
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <psemek/bt/status.hpp>
|
||||||
|
#include <psemek/log/log.hpp>
|
||||||
|
#include <psemek/util/exception.hpp>
|
||||||
|
#include <psemek/util/to_string.hpp>
|
||||||
|
|
||||||
|
namespace psemek::bt
|
||||||
|
{
|
||||||
|
|
||||||
|
struct assertion_failed_exception
|
||||||
|
: util::exception
|
||||||
|
{
|
||||||
|
assertion_failed_exception(std::string message, boost::stacktrace::stacktrace stacktrace = {})
|
||||||
|
: util::exception(std::move(message), std::move(stacktrace))
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ... Args>
|
||||||
|
inline bool assertion_failed(Args const & ... args)
|
||||||
|
{
|
||||||
|
(::psemek::log::error() << ... << args);
|
||||||
|
throw assertion_failed_exception(util::to_string(args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#define bt_assert(cond, ...) (void)(!(cond) && ::psemek::bt::assertion_failed("BT assertion failed: ", #cond, " ", ##__VA_ARGS__, " (", __FILE__, ":", __LINE__, ")"))
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/bt/node.hpp>
|
#include <psemek/bt/node.hpp>
|
||||||
|
#include <psemek/bt/assert.hpp>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -26,13 +27,27 @@ namespace psemek::bt
|
||||||
|
|
||||||
void start(Args ... args) override
|
void start(Args ... args) override
|
||||||
{
|
{
|
||||||
current_index_ = index_fn_(args...);
|
failed_start_ = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
current_index_ = index_fn_(args...);
|
||||||
|
}
|
||||||
|
catch (assertion_failed_exception const &)
|
||||||
|
{
|
||||||
|
failed_start_ = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (current_index_ < children_.size())
|
if (current_index_ < children_.size())
|
||||||
children_[current_index_]->start(args...);
|
children_[current_index_]->start(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
status update(Time dt, Args ... args) override
|
status update(Time dt, Args ... args) override
|
||||||
{
|
{
|
||||||
|
if (failed_start_)
|
||||||
|
return finished{false};
|
||||||
|
|
||||||
if (current_index_ >= children_.size())
|
if (current_index_ >= children_.size())
|
||||||
return finished{false};
|
return finished{false};
|
||||||
|
|
||||||
|
|
@ -49,6 +64,7 @@ namespace psemek::bt
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IndexFn index_fn_;
|
IndexFn index_fn_;
|
||||||
|
bool failed_start_ = false;
|
||||||
std::vector<node_ptr<tree_type>> children_;
|
std::vector<node_ptr<tree_type>> children_;
|
||||||
std::size_t current_index_ = 0;
|
std::size_t current_index_ = 0;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/bt/node.hpp>
|
#include <psemek/bt/node.hpp>
|
||||||
|
#include <psemek/bt/assert.hpp>
|
||||||
|
|
||||||
namespace psemek::bt
|
namespace psemek::bt
|
||||||
{
|
{
|
||||||
|
|
@ -23,7 +24,14 @@ namespace psemek::bt
|
||||||
|
|
||||||
status update(Time, Args ... args) override
|
status update(Time, Args ... args) override
|
||||||
{
|
{
|
||||||
return finished{condition_fn_(args...)};
|
try
|
||||||
|
{
|
||||||
|
return finished{condition_fn_(args...)};
|
||||||
|
}
|
||||||
|
catch (assertion_failed_exception const &)
|
||||||
|
{
|
||||||
|
return finished{false};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/bt/node.hpp>
|
#include <psemek/bt/node.hpp>
|
||||||
|
#include <psemek/bt/assert.hpp>
|
||||||
|
|
||||||
namespace psemek::bt
|
namespace psemek::bt
|
||||||
{
|
{
|
||||||
|
|
@ -23,12 +24,22 @@ namespace psemek::bt
|
||||||
|
|
||||||
void start(Args ... args) override
|
void start(Args ... args) override
|
||||||
{
|
{
|
||||||
child_ = node_factory_(args...);
|
try
|
||||||
child_->start(args...);
|
{
|
||||||
|
child_ = node_factory_(args...);
|
||||||
|
child_->start(args...);
|
||||||
|
}
|
||||||
|
catch (assertion_failed_exception const &)
|
||||||
|
{
|
||||||
|
child_ = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status update(Time dt, Args ... args) override
|
status update(Time dt, Args ... args) override
|
||||||
{
|
{
|
||||||
|
if (!child_)
|
||||||
|
return finished{false};
|
||||||
|
|
||||||
auto result = child_->update(dt, args...);
|
auto result = child_->update(dt, args...);
|
||||||
if (std::holds_alternative<finished>(result))
|
if (std::holds_alternative<finished>(result))
|
||||||
child_ = nullptr;
|
child_ = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/bt/tree.hpp>
|
#include <psemek/bt/tree.hpp>
|
||||||
|
#include <psemek/bt/status.hpp>
|
||||||
|
|
||||||
#include <variant>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace psemek::bt
|
namespace psemek::bt
|
||||||
|
|
@ -16,20 +16,11 @@ namespace psemek::bt
|
||||||
{
|
{
|
||||||
using tree_type = tree<Time, Event, Args...>;
|
using tree_type = tree<Time, Event, Args...>;
|
||||||
|
|
||||||
struct running
|
using running = detail::running;
|
||||||
{};
|
using finished = detail::finished;
|
||||||
|
using suspended = detail::suspended<Time>;
|
||||||
|
|
||||||
struct finished
|
using status = detail::status<Time>;
|
||||||
{
|
|
||||||
bool result;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct suspended
|
|
||||||
{
|
|
||||||
Time duration;
|
|
||||||
};
|
|
||||||
|
|
||||||
using status = std::variant<running, finished, suspended>;
|
|
||||||
|
|
||||||
virtual void start(Args ...) {}
|
virtual void start(Args ...) {}
|
||||||
virtual status update(Time dt, Args ... args) = 0;
|
virtual status update(Time dt, Args ... args) = 0;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/bt/node.hpp>
|
#include <psemek/bt/node.hpp>
|
||||||
|
#include <psemek/bt/assert.hpp>
|
||||||
|
|
||||||
namespace psemek::bt
|
namespace psemek::bt
|
||||||
{
|
{
|
||||||
|
|
@ -26,7 +27,14 @@ namespace psemek::bt
|
||||||
|
|
||||||
status update(Time dt, Args ... args) override
|
status update(Time dt, Args ... args) override
|
||||||
{
|
{
|
||||||
return process_fn_(dt, args...);
|
try
|
||||||
|
{
|
||||||
|
return process_fn_(dt, args...);
|
||||||
|
}
|
||||||
|
catch (assertion_failed_exception const &)
|
||||||
|
{
|
||||||
|
return finished{false};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool event(Event const &, Args ...) override
|
bool event(Event const &, Args ...) override
|
||||||
|
|
|
||||||
25
libs/bt/include/psemek/bt/status.hpp
Normal file
25
libs/bt/include/psemek/bt/status.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
namespace psemek::bt::detail
|
||||||
|
{
|
||||||
|
|
||||||
|
struct running
|
||||||
|
{};
|
||||||
|
|
||||||
|
struct finished
|
||||||
|
{
|
||||||
|
bool result;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Time>
|
||||||
|
struct suspended
|
||||||
|
{
|
||||||
|
Time duration;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Time>
|
||||||
|
using status = std::variant<running, finished, suspended<Time>>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/bt/node.hpp>
|
#include <psemek/bt/node.hpp>
|
||||||
|
#include <psemek/bt/assert.hpp>
|
||||||
|
|
||||||
namespace psemek::bt
|
namespace psemek::bt
|
||||||
{
|
{
|
||||||
|
|
@ -24,12 +25,24 @@ namespace psemek::bt
|
||||||
|
|
||||||
void start(Args ... args) override
|
void start(Args ... args) override
|
||||||
{
|
{
|
||||||
timer_ = duration_fn_(args...);
|
failed_start_ = false;
|
||||||
child_->start(args...);
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
timer_ = duration_fn_(args...);
|
||||||
|
child_->start(args...);
|
||||||
|
}
|
||||||
|
catch (assertion_failed_exception const &)
|
||||||
|
{
|
||||||
|
failed_start_ = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status update(Time dt, Args ... args) override
|
status update(Time dt, Args ... args) override
|
||||||
{
|
{
|
||||||
|
if (failed_start_)
|
||||||
|
return finished{false};
|
||||||
|
|
||||||
timer_ -= dt;
|
timer_ -= dt;
|
||||||
if (timer_ <= Time{0})
|
if (timer_ <= Time{0})
|
||||||
return finished{false};
|
return finished{false};
|
||||||
|
|
@ -46,6 +59,7 @@ namespace psemek::bt
|
||||||
node_ptr<tree<Time, Event, Args...>> child_;
|
node_ptr<tree<Time, Event, Args...>> child_;
|
||||||
DurationFn duration_fn_;
|
DurationFn duration_fn_;
|
||||||
Time timer_ = Time{};
|
Time timer_ = Time{};
|
||||||
|
bool failed_start_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/bt/node.hpp>
|
#include <psemek/bt/node.hpp>
|
||||||
|
#include <psemek/bt/assert.hpp>
|
||||||
|
|
||||||
namespace psemek::bt
|
namespace psemek::bt
|
||||||
{
|
{
|
||||||
|
|
@ -24,11 +25,23 @@ namespace psemek::bt
|
||||||
|
|
||||||
void start(Args ... args) override
|
void start(Args ... args) override
|
||||||
{
|
{
|
||||||
remaining_time_ = duration_fn_(args...);
|
failed_start_ = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
remaining_time_ = duration_fn_(args...);
|
||||||
|
}
|
||||||
|
catch (assertion_failed_exception const &)
|
||||||
|
{
|
||||||
|
failed_start_ = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status update(Time dt, Args ...) override
|
status update(Time dt, Args ...) override
|
||||||
{
|
{
|
||||||
|
if (failed_start_)
|
||||||
|
return finished{false};
|
||||||
|
|
||||||
remaining_time_ -= dt;
|
remaining_time_ -= dt;
|
||||||
if (remaining_time_ <= 0)
|
if (remaining_time_ <= 0)
|
||||||
return finished{true};
|
return finished{true};
|
||||||
|
|
@ -38,6 +51,7 @@ namespace psemek::bt
|
||||||
private:
|
private:
|
||||||
DurationFn duration_fn_;
|
DurationFn duration_fn_;
|
||||||
Time remaining_time_ = Time{};
|
Time remaining_time_ = Time{};
|
||||||
|
bool failed_start_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue