Toast Engine
Loading...
Searching...
No Matches
node.hpp
Go to the documentation of this file.
1
13
14#pragma once
15#define NODEFILE
16#include "box.hpp"
17#include "control_box.hpp"
18
19#include <list>
20#include <memory>
21#include <optional>
22#include <string>
23#include <string_view>
24#include <toast/assets/prefab.hpp>
25#include <toast/engine_defs.hpp>
26#include <toast/events/listener.hpp>
28#include <toast/export.hpp>
29#include <toast/log.hpp>
31#include <toast/uid.hpp>
32#include <toast/world/node_owner.hpp>
33
34namespace physics {
35class Collider;
36}
37
38namespace assets {
39class Script;
40}
41
42namespace scripting {
43class ScriptRuntime;
44}
45
46namespace toast {
47class INodeOwner;
48
49namespace _detail {
50struct NodeCluster;
51}
52
53enum class NodeState : uint8_t {
54 null,
59 destroy,
60};
61
62enum class NodeType : uint8_t {
63 null,
67};
68
70 enum Severity : uint8_t {
71 warning,
72 error
73 } severity;
74
75 uint8_t id;
76 std::string text;
77
78 auto operator==(const NodeMessage& rhs) const noexcept -> bool { return id == rhs.id; }
79};
80
81class [[ToastNode, Icon("Circle")]] TOAST_API Node {
82 friend class INodeOwner;
83 friend class World;
84 friend class Workspace;
85 friend class PlayWorkspace;
86 friend class TickScheduler;
87 friend class Node3D;
88 friend class assets::Prefab;
89 friend struct _detail::ControlBox;
90 friend struct _detail::NodeCluster;
92 friend class physics::Collider;
93
94public:
95 Node();
96 virtual ~Node();
97
99 [[nodiscard]]
100 auto uid() const noexcept -> const UID&;
101
103 [[nodiscard]]
104 auto rid() const noexcept -> std::uintptr_t;
105
107 [[nodiscard]]
108 auto name() const noexcept -> std::string_view;
109
114 void name(std::string_view name) noexcept;
115
121 [[nodiscard]]
122 auto enabled() const noexcept -> bool;
123
124 [[nodiscard]]
125 auto participatesIn(NodeOwnerParticipation use) const noexcept -> bool {
126 return m_owner != nullptr && m_owner->participatesIn(use);
127 }
128
135 [[nodiscard]]
136 auto owner() const noexcept -> INodeOwner* {
137 return m_owner;
138 }
139
144 void enabled(bool value) noexcept;
145
150 [[nodiscard]]
151 auto box() const noexcept -> Box<Node>;
152
159 [[nodiscard]]
160 auto info() const -> const NodeInfo*;
161
166 [[nodiscard]]
167 auto sourcePrefab() const noexcept -> const assets::Handle<assets::Prefab>&;
168
174 [[nodiscard]]
175 auto isInstanceRoot() const noexcept -> bool;
176
181 [[nodiscard]]
182 auto root() const noexcept -> Box<Node>;
183
185 [[nodiscard]]
186 auto state() const noexcept -> NodeState {
187 return m_state;
188 }
189
191 [[nodiscard]]
192 auto type() const noexcept -> NodeType {
193 return m_type;
194 }
195
197 [[nodiscard]]
198 auto listener() noexcept -> event::Listener&;
199
204 [[nodiscard]]
205 auto parent() noexcept -> Box<Node>;
206
213 [[nodiscard]]
214 auto children() const noexcept -> const std::vector<Box<Node>>& {
215 return m_children;
216 }
217
218 [[nodiscard]]
219 auto childrenSnapshot() const -> std::vector<Box<Node>>;
220
227 auto create(std::string_view type = "toast::Node") noexcept -> Box<Node> {
228 if (m_state == NodeState::root or m_state == NodeState::global) {
229 return m_owner->requestRuntimeCreate(*this, type);
230 }
231
232 // TODO: implement
233 TOAST_NOT_IMPLEMENTED;
234 return {};
235 }
236
243 auto spawn(UID uid) noexcept -> Box<Node> {
244 if (m_state == NodeState::root or m_state == NodeState::global) {
245 return m_owner->requestRuntimeSpawn(*this, uid);
246 }
247
248 // TODO: implement
249 TOAST_NOT_IMPLEMENTED;
250 return {};
251 }
252
259 auto spawn(std::string_view uri) noexcept -> Box<Node> {
260 if (m_state == NodeState::root or m_state == NodeState::global) {
261 return m_owner->requestRuntimeSpawn(*this, uri);
262 }
263
264 // TODO: implement
265 TOAST_NOT_IMPLEMENTED;
266 return {};
267 }
268
277 [[nodiscard]]
278 auto find(std::string_view query) -> Box<Node>;
279
286 [[nodiscard]]
287 auto find(const UID& uid) -> Box<Node>;
288
296 [[nodiscard]]
297 auto search(std::string_view query) -> std::vector<Box<Node>>;
298
299 [[nodiscard]]
300 auto childrenOfType(const NodeInfo* type) const -> std::vector<Box<Node>>;
301
302 [[nodiscard]]
303 auto searchType(const NodeInfo* type) const -> std::vector<Box<Node>>;
304
305 void addDependsOn(Node& other);
306 void removeDependsOn(Node& other);
307
311 void interactsWith(Node& other);
312
313 [[nodiscard]]
314 auto scriptRuntime() noexcept -> scripting::ScriptRuntime* {
315 return m_script_runtime.get();
316 }
317
321 [[nodiscard]]
322 auto hasTickFunction(TickFunctionList mask) const noexcept -> bool;
323
332 [[nodiscard]]
333 auto scriptVm(TickFunctionList func) const noexcept -> std::optional<size_t>;
334
336 [[nodiscard]]
337 auto scriptVmAny() const noexcept -> std::optional<size_t>;
338
340 [[nodiscard]]
341 auto hasCallable(std::string_view name) const noexcept -> bool;
342
346 void reloadScripts() noexcept;
347
349 [[nodiscard]]
350 auto scripts() const noexcept -> const std::vector<assets::Handle<assets::Script>>& {
351 return m_scripts;
352 }
353
356 m_scripts = std::move(scripts);
357 loadScripts();
358 onScriptsReloaded();
359 }
360
362 void addScript(const assets::Handle<assets::Script>& script) noexcept {
363 m_scripts.push_back(script);
364 loadScripts();
365 }
366
372 template<typename R = void, typename... Args>
373 auto call(std::string_view name, Args&&... args) -> R {
374 std::array<std::any, sizeof...(Args)> any_args {std::any(std::decay_t<Args>(args))...};
375 if constexpr (std::is_void_v<R>) {
376 if (m_info && m_info->getMethod(name)) {
377 _detail::callMethodChain(m_info, this, name, args...);
378 }
379 _detail::callNodeScripts(this, name, any_args);
380 } else {
381 R result {};
382 if (m_info && m_info->getMethod(name)) {
383 result = _detail::callMethodChain<R>(m_info, this, name, args...);
384 }
385 _detail::callNodeScripts(this, name, any_args);
386 return result;
387 }
388 }
389
395 template<typename T>
396 [[nodiscard]]
397 auto get(std::string_view name) const -> T {
398 if (m_info) {
399 if (const auto* f = m_info->getField(name)) {
400 std::any v = f->get(const_cast<Node*>(this));
401 if (auto* p = std::any_cast<T>(&v)) {
402 return *p;
403 }
404 }
405 }
406 std::any v = _detail::getNodeScriptVar(this, name);
407 if (auto* p = std::any_cast<T>(&v)) {
408 return *p;
409 }
410 return T {};
411 }
412
417 template<typename T>
418 void set(std::string_view name, const T& value) {
419 if (m_info) {
420 if (const auto* f = m_info->getField(name)) {
421 f->set(this, std::any(value));
422 onReflectedFieldChanged(f->name);
423 }
424 }
425 _detail::setNodeScriptVar(this, name, std::any(value));
426 }
427
428 signals::Signal<Box<Node>> on_enable;
429 signals::Signal<Box<Node>> on_disable;
430 signals::Signal<Box<Node>> on_begin;
431 signals::Signal<Box<Node>> on_end;
432
433protected:
434 INodeOwner* m_owner = nullptr;
435
436 virtual void onReflectedFieldChanged(std::string_view /*field_name*/) { }
437
438 virtual void onScriptsReloaded() { }
439
441 virtual void onScriptsReloading() { }
442
443 [[nodiscard]]
444 virtual auto luaAffinity() const noexcept -> std::optional<size_t> {
445 return std::nullopt;
446 }
447
449 virtual void onScriptVarChanged(std::string_view path) { }
450
451 virtual void updateInspectorMessages() { }
452
453 void addInspectorMessage(const NodeMessage& message) {
454 for (auto& existing : m_messages) {
455 if (existing == message) {
456 existing = message;
457 return;
458 }
459 }
460 m_messages.emplace_back(message);
461 }
462
463 void removeInspectorMessage(const NodeMessage& message) { m_messages.remove(message); }
464
465private:
466 bool m_recursive_prefab = false;
467
468public:
469 [[nodiscard]]
470 auto isRecursivePrefab() const noexcept -> bool {
471 return m_recursive_prefab;
472 }
473
474private:
475 [[Reflect, Hidden]]
476 UID m_uid; // serialized unique id
477 std::string m_name;
478
479 [[Reflect, Hidden]]
480 bool m_local_enabled = false; // is this object enabled?
481 bool m_inherited_enabled = false; // is any parent of this object enabled?
482
483 [[Reflect, Name("Parent"), InspectorNoModify]]
484 Box<Node> m_parent;
485
486 [[Reflect, Name("Prefab"), InspectorNoModify]]
487 assets::Handle<assets::Prefab> m_source_prefab;
488
489 NodeState m_state = NodeState::null;
490 NodeType m_type = NodeType::null;
491 std::array<uint8_t, 5> m_wave = {
492 255, 255, 255, 255, 255
493 };
494
495 Box<Node> m_box;
496 const NodeInfo* m_info = nullptr;
497 std::string m_reflect_type_name;
498 bool m_prefab_interior =
499 false;
500 std::vector<Box<Node>> m_children;
501 std::shared_ptr<const assets::Prefab::BasicNode>
502 m_unresolved_chunk;
503
504 std::unique_ptr<event::Listener> m_listener = nullptr;
505
506 [[Reflect]]
507 std::vector<assets::Handle<assets::Script>> m_scripts;
508
510 std::unique_ptr<scripting::ScriptRuntime> m_script_runtime;
511
512 uint64_t m_script_group = 0;
513 std::optional<size_t> m_script_vm;
514
515 enum LifecycleBits : uint8_t {
516 lifecycle_loaded = 1 << 0,
517 lifecycle_initialized = 1 << 1,
518 lifecycle_begun = 1 << 2,
519 lifecycle_enabled = 1 << 3,
520 };
521
522 uint8_t m_lifecycle = 0;
523
524 [[nodiscard]]
525 auto parentInternal() const noexcept -> Box<Node> {
526 return m_parent;
527 }
528
529 [[nodiscard]]
530 auto rootUnlocked() const noexcept -> Box<Node>;
531
532 void inheritedEnabled(bool value) noexcept;
533 void changeNodeState(NodeState state) noexcept;
534
536 void callTick(const NodeInfo* info, TickFunctionList func_type) noexcept;
537
539 void callTickNative(const NodeInfo* info, TickFunctionList func_type) noexcept;
540
541 void callTickScripts(TickFunctionList func_type) noexcept;
542
544 void propagateCallTick(const NodeInfo* info, TickFunctionList func_type) noexcept;
545
547 void propagateEnable() noexcept;
548
550 void refreshInfo();
551
553 void loadScripts() noexcept;
554
555 std::list<NodeMessage> m_messages;
556};
557
558}
559
561template<typename T>
562auto reflect_cast(toast::Node* n) -> T* { // NOLINT
563 if (n && n->info() && n->info()->isA(toast::nodeTypeInfo<T>())) {
564 return static_cast<T*>(n);
565 }
566 return nullptr;
567}
568
569#undef NODEFILE
570#include <toast/events/signals.inl>
pseudo shared pointer for Nodes
Type-safe smart pointer for assets.
Definition core_types.hpp:149
Definition prefab.hpp:54
Definition script.hpp:14
Definition collider.hpp:18
Definition script_runtime.hpp:165
Intrusive reference-counted handle to a Node.
Definition box.hpp:35
Definition node_owner.hpp:38
Definition node.hpp:81
auto type() const noexcept -> NodeType
Definition node.hpp:192
virtual void onScriptsReloading()
Definition node.hpp:441
auto spawn(UID uid) noexcept -> Box< Node >
Asynchronously instantiates a prefab as a child of this node.
Definition node.hpp:243
void set(std::string_view name, const T &value)
Writes a named value: reflected C++ field if present and every Lua instance variable of that name tha...
Definition node.hpp:418
auto children() const noexcept -> const std::vector< Box< Node > > &
The ordered list of direct children.
Definition node.hpp:214
auto state() const noexcept -> NodeState
Definition node.hpp:186
auto scripts() const noexcept -> const std::vector< assets::Handle< assets::Script > > &
Definition node.hpp:350
auto call(std::string_view name, Args &&... args) -> R
Invokes all C++ reflected implementations of name (base→derived) and all same-named Lua functions acr...
Definition node.hpp:373
auto spawn(std::string_view uri) noexcept -> Box< Node >
Asynchronously instantiates a prefab as a child of this node.
Definition node.hpp:259
auto owner() const noexcept -> INodeOwner *
The World or Workspace this node belongs to.
Definition node.hpp:136
auto rid() const noexcept -> std::uintptr_t
Runtime identifier for this node, guaranteed to be unique but changes every time.
Definition node.cpp:41
void addScript(const assets::Handle< assets::Script > &script) noexcept
Definition node.hpp:362
auto name() const noexcept -> std::string_view
Display name. Siblings may share one - this is not an identifier.
Definition node.cpp:45
auto create(std::string_view type="toast::Node") noexcept -> Box< Node >
Creates a new child node of the given type and attaches it to this node.
Definition node.hpp:227
auto uid() const noexcept -> const UID &
Stable unique identifier, assigned at construction or deserialization. Never changes.
Definition node.cpp:37
auto enabled() const noexcept -> bool
Whether this node is currently active.
Definition node.cpp:53
void setScripts(std::vector< assets::Handle< assets::Script > > scripts) noexcept
Definition node.hpp:355
virtual void onScriptVarChanged(std::string_view path)
Definition node.hpp:449
auto get(std::string_view name) const -> T
Reads a named value: reflected C++ field first, then the first matching Lua instance variable.
Definition node.hpp:397
Control block for the pseudo shared pointer Box<Node>.
Engine-wide definitions and helper macros for cross-platform compatibility.
Public logging interface for the engine.
Member-robber pattern used by the generated reflection code.
Definition defer.hpp:16
auto reflect_cast(toast::Node *n) -> T *
null-safe RTTI replacement; walks the NodeInfo chain instead of dynamic_cast
Definition node.hpp:562
NodeState
Definition node.hpp:53
@ cached
The node is loaded in memory but not in use.
Definition node.hpp:56
@ root
The node is currently in use within world::root_node.
Definition node.hpp:55
@ global
The node is currently in use within world::global[].
Definition node.hpp:57
@ loading
The node is in the load queue.
Definition node.hpp:58
NodeType
Definition node.hpp:62
@ world_root
This node is the root that resides in the world.
Definition node.hpp:66
@ child
This node is a regular node.
Definition node.hpp:64
Complete reflection record for a registered Node type.
Definition reflect_node.hpp:210
Definition node.hpp:69
Definition uid.hpp:20
Reference-count control block embedded inside the Node allocation.
Definition control_box.hpp:33
Definition tick_scheduler.hpp:33
Definition world_test_access.hpp:14
Unique identifier for everything that exists in our engine.