10#include <toast/reflect/reflect.hpp>
12#include <unordered_map>
22void TOAST_API callNodeScripts(Node* node, std::string_view name, std::span<const std::any> args)
noexcept;
23void TOAST_API setNodeScriptVar(Node* node, std::string_view name,
const std::any& value)
noexcept;
24auto TOAST_API getNodeScriptVar(
const Node* node, std::string_view name)
noexcept -> std::any;
26template<
typename R = void,
typename... Args>
27auto callMethodChain(
const NodeInfo* info,
void* obj, std::string_view method_name,
const Args&... args) -> R;
47 post_physics = 1 << 10,
51 physics_tick = 1 << 14,
52 tick_mask = early_tick | tick | physics_tick | post_physics | late_tick | editor_tick,
57constexpr auto operator&(TickFunctionList lhs, TickFunctionList rhs) -> TickFunctionList {
58 return static_cast<TickFunctionList
>(
static_cast<uint16_t
>(lhs) &
static_cast<uint16_t
>(rhs));
62 return static_cast<TickFunctionList>(
static_cast<uint16_t
>(lhs) |
static_cast<uint16_t
>(rhs));
77 return (flags & flag) == flag;
82 case TickFunctionList::load:
return "load";
83 case TickFunctionList::save:
return "save";
84 case TickFunctionList::editor_tick:
return "editor_tick";
85 case TickFunctionList::init:
return "init";
86 case TickFunctionList::destroy:
return "destroy";
87 case TickFunctionList::begin:
return "begin";
88 case TickFunctionList::end:
return "end";
89 case TickFunctionList::on_enable:
return "on_enable";
90 case TickFunctionList::on_disable:
return "on_disable";
91 case TickFunctionList::early_tick:
return "early_tick";
92 case TickFunctionList::tick:
return "tick";
93 case TickFunctionList::physics_tick:
return "physics_tick";
94 case TickFunctionList::post_physics:
return "post_physics";
95 case TickFunctionList::late_tick:
return "late_tick";
96 default:
return "none";
126 Invoker physics_tick =
nullptr;
127 Invoker post_physics =
nullptr;
138 std::string_view name;
139 std::span<const FieldInfo* const> fields;
148 for (
const auto& f : fields) {
149 if (field_name == f->name) {
164 std::string_view name;
165 std::span<const FieldInfo* const> fields;
166 std::span<const SubgroupInfo> subgroups;
175 for (
const auto& g : subgroups) {
176 if (group_name == g.name) {
191 for (
const auto& f : fields) {
192 if (field_name == f->name) {
211 using Factory =
Node* (*)();
212 using Deleter = void (*)(
Node*);
214 std::string_view type;
216 std::span<const SignalInfo> signals;
217 std::span<const FieldInfo> all_fields;
218 std::span<const FieldInfo* const> fields;
219 std::span<const GroupInfo> groups;
220 std::span<const FunctionInfo> methods;
224 Factory construct =
nullptr;
225 Deleter destroy =
nullptr;
234 for (
const auto& f : signals) {
235 if (field_name == f.name) {
240 return base_type->getSignal(field_name);
246 auto getSignal(std::string_view declaring_type, std::string_view signal_name)
const ->
const SignalInfo* {
247 for (
const auto* info =
this; info !=
nullptr; info = info->base_type) {
248 if (info->type != declaring_type) {
251 for (
const auto& signal : info->signals) {
252 if (signal.name == signal_name) {
262 void forEachSignal(F&& callback)
const {
263 for (
const auto* info =
this; info !=
nullptr; info = info->base_type) {
264 for (
const auto& signal : info->signals) {
265 callback(*info, signal);
277 for (
const auto& f : all_fields) {
278 if (field_name == f.name) {
283 return base_type->getField(field_name);
295 for (
const auto& m : methods) {
296 if (method_name == m.name) {
301 return base_type->getMethod(method_name);
311 template<
typename R = void,
typename... Args>
312 auto call(
void* obj, std::string_view method_name, Args&&... args)
const -> R {
314 TOAST_WARN(
"Reflect",
"call(): reflected function '{}' not found on '{}'", method_name, type);
315 assert(
false &&
"NodeInfo::call(): reflected function not found");
316 if constexpr (std::is_void_v<R>) {
323 std::array<std::any,
sizeof...(Args)> any_args {std::any(std::decay_t<Args>(args))...};
324 if constexpr (std::is_void_v<R>) {
325 _detail::callMethodChain(
this, obj, method_name, std::forward<Args>(args)...);
326 _detail::callNodeScripts(
static_cast<Node*
>(obj), method_name, any_args);
328 R result = _detail::callMethodChain<R>(
this, obj, method_name, std::forward<Args>(args)...);
329 _detail::callNodeScripts(
static_cast<Node*
>(obj), method_name, any_args);
339 auto callAllDynamic(
void* obj, std::string_view method_name, std::span<const std::any> args)
const -> std::any {
342 result = base_type->callAllDynamic(obj, method_name, args);
344 for (
const auto& m : methods) {
345 if (m.name == method_name) {
346 result = m.callDynamic(obj, args);
360 for (
const NodeInfo* cur =
this; cur; cur = cur->base_type) {
375 for (
const NodeInfo* cur =
this; cur; cur = cur->base_type) {
376 if ((cur->functions.list & mask) != TickFunctionList::none) {
385 constexpr auto id() const -> uint32_t {
386 uint32_t hash = 2166136261u;
387 for (
char c : type) {
388 hash ^=
static_cast<uint8_t
>(c);
401 for (
const auto& g : groups) {
402 if (group_name == g.name) {
407 return base_type->getGroup(group_name);
420 for (
const auto& f : all_fields) {
421 if (field_name == f.name) {
426 return base_type->search(field_name);
439 base_type->forEachBaseType(fn);
448 static auto get()
noexcept ->
const NodeInfo*;
454template<
typename R,
typename... Args>
455auto callMethodChain(
const NodeInfo* info,
void* obj, std::string_view method_name,
const Args&... args) -> R {
456 if constexpr (std::is_void_v<R>) {
457 if (info->base_type) {
458 callMethodChain(info->base_type, obj, method_name, args...);
460 for (
const auto& m : info->methods) {
461 if (m.name == method_name) {
462 m.call(obj, args...);
468 if (info->base_type) {
469 result = callMethodChain<R>(info->base_type, obj, method_name, args...);
471 for (
const auto& m : info->methods) {
472 if (m.name == method_name) {
473 result = m.call<R>(obj, args...);
492class TOAST_API NodeRegistry {
507 if (name.starts_with(
"::")) {
508 name.remove_prefix(2);
510 auto types = (*instance).types;
511 auto it = (*instance).types.find(name);
512 return it != (*instance).types.end() ? it->second :
nullptr;
519 for (
const auto& [key, info] : instance->types) {
526 std::unordered_map<std::string_view, const NodeInfo*> types;
530TOAST_API
void registerEngineTypes();
533auto nodeTypeInfo() noexcept -> const NodeInfo*;
Global registry mapping fully-qualified type names to NodeInfo pointers.
Definition reflect_node.hpp:492
static void forEachType(F &&fn)
Calls fn(info) for every registered node type.
Definition reflect_node.hpp:517
static void registerNode(const NodeInfo *info)
Called by the generated registration function; inserts a type into the registry.
Definition engine.cpp:111
static auto reflect(std::string_view name) -> const NodeInfo *
Looks up a Node type by its fully-qualified C++ name.
Definition reflect_node.hpp:505
#define TOAST_WARN(sink,...)
Indicates possible code missuse.
Definition log.hpp:94
Member-robber pattern used by the generated reflection code.
Definition defer.hpp:16
TickFunctionList
Bit-flag set describing which lifecycle phases a Node type implements.
Definition reflect_node.hpp:36
Runtime descriptor for one reflected field.
Definition reflect.hpp:79
Runtime descriptor for one reflected member function.
Definition reflect.hpp:157
Top-level category grouping fields and optional SubgroupInfo children.
Definition reflect_node.hpp:163
auto getField(std::string_view field_name) const -> const FieldInfo *
Finds a field by name within this group's flat field list.
Definition reflect_node.hpp:190
auto getSubgroup(std::string_view group_name) const -> const SubgroupInfo *
Finds a subgroup by name.
Definition reflect_node.hpp:174
Complete reflection record for a registered Node type.
Definition reflect_node.hpp:210
auto getMethod(std::string_view method_name) const -> const FunctionInfo *
Finds a reflected function by name in this type, then walks base_type if not found.
Definition reflect_node.hpp:294
auto getGroup(std::string_view group_name) const -> const GroupInfo *
Finds a group by name, walking base_type if not found.
Definition reflect_node.hpp:400
auto getField(std::string_view field_name) const -> const FieldInfo *
Finds a field by name in this type's all_fields, then walks base_type if not found.
Definition reflect_node.hpp:276
auto call(void *obj, std::string_view method_name, Args &&... args) const -> R
Walks base->derived calling every inheritance level that defines method_name, then fires Lua scripts.
Definition reflect_node.hpp:312
void forEachBaseType(F &&fn) const
Calls fn for each NodeInfo in the inheritance chain, from the root base down to this type.
Definition reflect_node.hpp:437
auto callAllDynamic(void *obj, std::string_view method_name, std::span< const std::any > args) const -> std::any
Walks base->derived via dynamic invokers, calling every level that defines method_name.
Definition reflect_node.hpp:339
constexpr auto id() const -> uint32_t
FNV-1a hash of the type string; not the same as a Node's runtime UID.
Definition reflect_node.hpp:385
auto hasFunction(TickFunctionList mask) const -> bool
Checks whether this type or any base type implements the given lifecycle phase(s).
Definition reflect_node.hpp:374
auto search(std::string_view field_name) const -> const FieldInfo *
Finds a field by name, walking the full inheritance chain.
Definition reflect_node.hpp:419
auto isA(const NodeInfo *other) const -> bool
Checks whether this type is the same as or a subtype of another.
Definition reflect_node.hpp:359
auto getSignal(std::string_view field_name) const -> const SignalInfo *
Finds a signal by name in this type's signals, then walks base_type if not found.
Definition reflect_node.hpp:233
Definition reflect_node.hpp:446
Definition reflect.hpp:52
A named sub-section of fields inside a GroupInfo.
Definition reflect_node.hpp:137
auto getField(std::string_view field_name) const -> const FieldInfo *
Linear scan for a field by name within this subgroup.
Definition reflect_node.hpp:147
Set of lifecycle function pointers for one Node type.
Definition reflect_node.hpp:109
void(*)(void *) Invoker
void* erases the Node* to avoid a vtable; generated code casts it back before calling
Definition reflect_node.hpp:111