]> git.tdb.fi Git - libs/game.git/blobdiff - source/game/owned.h
Add move constructor and assignment from Owned of derived type
[libs/game.git] / source / game / owned.h
index 19daa7efe12afbbffeb3676d635088daca4889ff..a30f040d58269019cd3634159100e7d2f8a976c3 100644 (file)
@@ -2,6 +2,8 @@
 #define MSP_GAME_OWNED_H_
 
 #include <stdexcept>
+#include "accessguard.h"
+#include "events.h"
 #include "handle.h"
 #include "stage.h"
 
@@ -16,17 +18,30 @@ class Owned: public Handle<T>
 public:
        Owned() = default;
 
-       template<typename... Args>
-       Owned(Handle<Entity>, Args &&...);
+       template<typename P, typename... Args>
+       Owned(Handle<P>, Args &&...);
 
-       template<typename... Args>
-       Owned(Entity &parent, Args &&... args): Owned(Handle<Entity>::from_object(&parent), std::forward<Args>(args)...) { }
+       template<typename P, typename... Args>
+       Owned(P *parent, Args &&... args): Owned(Handle<P>::from_object(parent), std::forward<Args>(args)...) { }
 
        Owned(Owned &&other): Handle<T>(other) { other.ptr = nullptr; }
-       Owned &operator=(Owned &&other);
+
+       template<typename U>
+               requires std::is_base_of_v<T, U>
+       Owned(Owned<U> &&other): Handle<T>(other) { other.ptr = nullptr; }
+
+       Owned &operator=(Owned &&other) { assign(std::move(other)); return *this; }
+
+       template<typename U>
+               requires std::is_base_of_v<T, U>
+       Owned &operator=(Owned<U> &&other) { assign(std::move(other)); return *this; }
+
        ~Owned() { destroy(); }
 
 private:
+       template<typename U>
+       void assign(Owned<U> &&);
+
        template<typename O>
        static Stage &get_stage(O &);
 
@@ -35,32 +50,44 @@ private:
 
 
 template<typename T>
-template<typename... Args>
-Owned<T>::Owned(Handle<Entity> parent, Args &&... args)
+template<typename P, typename... Args>
+Owned<T>::Owned(Handle<P> parent, Args &&... args)
 {
+#ifdef DEBUG
+       AccessGuard::get_instance().check<AccessGuard::Create>();
+#endif
+
        if(!parent)
                throw std::invalid_argument("Owned::Owned");
 
-       using DependentEntity = std::conditional_t<sizeof(T), Entity, Entity>;
-       Handle<DependentEntity> dparent = parent;
-
-       Pool<T> &pool = get_stage(*dparent).get_pools().template get_pool<T>();
+       Stage &stage = get_stage(*parent);
+       Pool<T> &pool = stage.get_pools().get_pool<T>();
+       bool first_created = !pool.get_capacity();
        this->ptr = pool.create(parent, std::forward<Args>(args)...);
        if constexpr(std::is_base_of_v<Component, T>)
-               dparent->add_component(*this);
+       {
+               if(first_created)
+                       stage.get_reflector().get_or_create_class<T>().template set_polymorphic_base<Component>(**this);
+               parent->add_component(*this);
+               stage.get_event_source().emit<Events::ComponentCreated>(*this);
+       }
        else
-               dparent->add_child(*this);
+       {
+               if(first_created)
+                       stage.get_reflector().get_or_create_class<T>().template set_polymorphic_base<Entity>(**this);
+               parent->add_child(*this);
+               stage.get_event_source().emit<Events::EntityCreated>(*this);
+       }
 }
 
 template<typename T>
-Owned<T> &Owned<T>::operator=(Owned &&other)
+template<typename U>
+void Owned<T>::assign(Owned<U> &&other)
 {
        destroy();
 
        this->ptr = other.ptr;
        other.ptr = nullptr;
-
-       return *this;
 }
 
 template<typename T>
@@ -80,13 +107,24 @@ void Owned<T>::destroy()
        if(!obj)
                return;
 
-       Pool<T> &pool = get_stage(*obj).get_pools().template get_pool<T>();
+#ifdef DEBUG
+       AccessGuard::get_instance().check<AccessGuard::Destroy>();
+#endif
+
+       Stage &stage = get_stage(*obj);
 
        if constexpr(std::is_base_of_v<Component, T>)
+       {
+               stage.get_event_source().emit<Events::ComponentDestroyed>(*this);
                obj->get_entity()->remove_component(*this);
+       }
        else if(auto parent = obj->get_parent().get())
+       {
+               stage.get_event_source().emit<Events::EntityDestroyed>(*this);
                parent->remove_child(*this);
+       }
 
+       Pool<T> &pool = stage.get_pools().get_pool<T>();
        pool.destroy(this->ptr);
 }