]> git.tdb.fi Git - libs/game.git/blob - source/game/owned.h
Enforce no creation or destruction of objects during tick
[libs/game.git] / source / game / owned.h
1 #ifndef MSP_GAME_OWNED_H_
2 #define MSP_GAME_OWNED_H_
3
4 #include <stdexcept>
5 #include "accessguard.h"
6 #include "events.h"
7 #include "handle.h"
8 #include "stage.h"
9
10 namespace Msp::Game {
11
12 class Component;
13 class Entity;
14
15 template<typename T>
16 class Owned: public Handle<T>
17 {
18 public:
19         Owned() = default;
20
21         template<typename P, typename... Args>
22         Owned(Handle<P>, Args &&...);
23
24         template<typename P, typename... Args>
25         Owned(Owned<P> &p, Args &&... a): Owned(static_cast<Handle<P> &>(p), std::forward<Args>(a)...) { }
26
27         template<typename P, typename... Args>
28                 requires(!std::is_const_v<P>)
29         Owned(P &parent, Args &&... args): Owned(Handle<P>::from_object(&parent), std::forward<Args>(args)...) { }
30
31         Owned(Owned &&other): Handle<T>(other) { other.ptr = nullptr; }
32         Owned &operator=(Owned &&other);
33         ~Owned() { destroy(); }
34
35 private:
36         template<typename O>
37         static Stage &get_stage(O &);
38
39         void destroy();
40 };
41
42
43 template<typename T>
44 template<typename P, typename... Args>
45 Owned<T>::Owned(Handle<P> parent, Args &&... args)
46 {
47 #ifdef DEBUG
48         AccessGuard::get_instance().check<AccessGuard::Create>();
49 #endif
50
51         if(!parent)
52                 throw std::invalid_argument("Owned::Owned");
53
54         Stage &stage = get_stage(*parent);
55         Pool<T> &pool = stage.get_pools().get_pool<T>();
56         this->ptr = pool.create(parent, std::forward<Args>(args)...);
57         if constexpr(std::is_base_of_v<Component, T>)
58         {
59                 parent->add_component(*this);
60                 stage.get_event_source().emit<Events::ComponentCreated>(*this);
61         }
62         else
63         {
64                 parent->add_child(*this);
65                 stage.get_event_source().emit<Events::EntityCreated>(*this);
66         }
67 }
68
69 template<typename T>
70 Owned<T> &Owned<T>::operator=(Owned &&other)
71 {
72         destroy();
73
74         this->ptr = other.ptr;
75         other.ptr = nullptr;
76
77         return *this;
78 }
79
80 template<typename T>
81 template<typename O>
82 Stage &Owned<T>::get_stage(O &obj)
83 {
84         if constexpr(std::is_base_of_v<Component, O>)
85                 return get_stage(*obj.get_entity());
86         else
87                 return obj.get_stage();
88 }
89
90 template<typename T>
91 void Owned<T>::destroy()
92 {
93         T *obj = this->get();
94         if(!obj)
95                 return;
96
97 #ifdef DEBUG
98         AccessGuard::get_instance().check<AccessGuard::Destroy>();
99 #endif
100
101         Stage &stage = get_stage(*obj);
102
103         if constexpr(std::is_base_of_v<Component, T>)
104         {
105                 stage.get_event_source().emit<Events::ComponentDestroyed>(*this);
106                 obj->get_entity()->remove_component(*this);
107         }
108         else if(auto parent = obj->get_parent().get())
109         {
110                 stage.get_event_source().emit<Events::EntityDestroyed>(*this);
111                 parent->remove_child(*this);
112         }
113
114         Pool<T> &pool = stage.get_pools().get_pool<T>();
115         pool.destroy(this->ptr);
116 }
117
118 } // namespace Msp::Game
119
120 #endif