]> git.tdb.fi Git - libs/game.git/blob - source/game/owned.h
d6f9f17a9ce170d7456dbafe08b3e53fe1a29418
[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         bool first_created = !pool.get_capacity();
57         this->ptr = pool.create(parent, std::forward<Args>(args)...);
58         if constexpr(std::is_base_of_v<Component, T>)
59         {
60                 if(first_created)
61                         stage.get_reflector().get_or_create_class<T>().template set_polymorphic_base<Component>(**this);
62                 parent->add_component(*this);
63                 stage.get_event_source().emit<Events::ComponentCreated>(*this);
64         }
65         else
66         {
67                 if(first_created)
68                         stage.get_reflector().get_or_create_class<T>().template set_polymorphic_base<Entity>(**this);
69                 parent->add_child(*this);
70                 stage.get_event_source().emit<Events::EntityCreated>(*this);
71         }
72 }
73
74 template<typename T>
75 Owned<T> &Owned<T>::operator=(Owned &&other)
76 {
77         destroy();
78
79         this->ptr = other.ptr;
80         other.ptr = nullptr;
81
82         return *this;
83 }
84
85 template<typename T>
86 template<typename O>
87 Stage &Owned<T>::get_stage(O &obj)
88 {
89         if constexpr(std::is_base_of_v<Component, O>)
90                 return get_stage(*obj.get_entity());
91         else
92                 return obj.get_stage();
93 }
94
95 template<typename T>
96 void Owned<T>::destroy()
97 {
98         T *obj = this->get();
99         if(!obj)
100                 return;
101
102 #ifdef DEBUG
103         AccessGuard::get_instance().check<AccessGuard::Destroy>();
104 #endif
105
106         Stage &stage = get_stage(*obj);
107
108         if constexpr(std::is_base_of_v<Component, T>)
109         {
110                 stage.get_event_source().emit<Events::ComponentDestroyed>(*this);
111                 obj->get_entity()->remove_component(*this);
112         }
113         else if(auto parent = obj->get_parent().get())
114         {
115                 stage.get_event_source().emit<Events::EntityDestroyed>(*this);
116                 parent->remove_child(*this);
117         }
118
119         Pool<T> &pool = stage.get_pools().get_pool<T>();
120         pool.destroy(this->ptr);
121 }
122
123 } // namespace Msp::Game
124
125 #endif