]> git.tdb.fi Git - libs/game.git/blob - source/game/owned.h
df3cd94f2fde19079742f1a317be059b576e672d
[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 "handle.h"
6
7 namespace Msp::Game {
8
9 class Component;
10 class Entity;
11 class Root;
12 class Stage;
13
14 template<typename T>
15 class Owned: public Handle<T>
16 {
17 public:
18         Owned() = default;
19
20         template<typename... Args>
21         Owned(Handle<Entity>, Args &&...);
22
23         template<typename... Args>
24         Owned(Entity &parent, Args &&... args): Owned(Handle<Entity>::from_object(&parent), std::forward<Args>(args)...) { }
25
26         Owned(Owned &&other): Handle<T>(other) { other.ptr = nullptr; }
27         Owned &operator=(Owned &&other);
28         ~Owned() { destroy(); }
29
30 private:
31         template<typename O>
32         static Stage &get_stage(O &);
33
34         void destroy();
35 };
36
37
38 template<typename T>
39 template<typename... Args>
40 Owned<T>::Owned(Handle<Entity> parent, Args &&... args)
41 {
42         if(!parent)
43                 throw std::invalid_argument("Owned::Owned");
44
45         using DependentEntity = std::conditional_t<sizeof(T), Entity, Entity>;
46         Handle<DependentEntity> dparent = parent;
47
48         Pool<T> &pool = get_stage(*dparent).get_pools().template get_pool<T>();
49         this->ptr = pool.create(parent, std::forward<Args>(args)...);
50         if constexpr(std::is_base_of_v<Component, T>)
51                 dparent->add_component(*this);
52         else
53                 dparent->add_child(*this);
54 }
55
56 template<typename T>
57 Owned<T> &Owned<T>::operator=(Owned &&other)
58 {
59         destroy();
60
61         this->ptr = other.ptr;
62         other.ptr = nullptr;
63
64         return *this;
65 }
66
67 template<typename T>
68 template<typename O>
69 Stage &Owned<T>::get_stage(O &obj)
70 {
71         using DependentRoot = std::conditional_t<sizeof(T), Root, Root>;
72         if constexpr(std::is_base_of_v<Component, O>)
73                 return get_stage(*obj.get_entity());
74         else if constexpr(std::is_base_of_v<Entity, O>)
75                 return dynamic_cast<DependentRoot &>(*obj.get_root()).get_stage();
76         else
77                 return obj;
78 }
79
80 template<typename T>
81 void Owned<T>::destroy()
82 {
83         T *obj = this->get();
84         if(!obj)
85                 return;
86
87         Pool<T> &pool = get_stage(*obj).get_pools().template get_pool<T>();
88
89         if constexpr(std::is_base_of_v<Component, T>)
90                 obj->get_entity()->remove_component(*this);
91         else if(auto parent = obj->get_parent().get())
92                 parent->remove_child(*this);
93
94         pool.destroy(this->ptr);
95 }
96
97 } // namespace Msp::Game
98
99 #endif