Program Listing for File Actor.hpp

Return to documentation for file (engine/include/Cacao/Actor.hpp)

#pragma once

#include "DllHelper.hpp"
#include "Transform.hpp"
#include "Exceptions.hpp"
#include "ComponentExporter.hpp"

#include <map>
#include <memory>

#include "crossguid/guid.hpp"

namespace Cacao {
    class Component;
    class Actor;
    class World;

    class ActorHandle {
      public:
        ActorHandle() {}

        Actor* operator->() {
            return actor.get();
        }

        const Actor* operator->() const {
            return actor.get();
        }

        bool IsNull() {
            return (bool)actor;
        }

      private:
        friend class Actor;
        friend class World;

        //Owning reference to actor
        std::shared_ptr<Actor> actor;

        //Owning reference to actor world
        std::shared_ptr<World> world;
    };

    class CACAO_API Actor : protected std::enable_shared_from_this<Actor> {
      public:
        static ActorHandle Create(const std::string& name, ActorHandle parent);

        static ActorHandle Create(const std::string& name, std::shared_ptr<World> world);

        std::string name;
        const xg::Guid guid;
        Transform transform;

        glm::mat4 GetWorldTransformMatrix() const;

        ActorHandle GetParent() const;

        bool IsActive() const {
            return functionallyActive;
        }

        void SetActive(bool state);

        void Reparent(ActorHandle newParent);

        template<typename T, typename... Args>
            requires std::is_base_of_v<Component, T> && std::is_constructible_v<T, Args&&...>
        void MountComponent(Args&&... args) {
            Check<ExistingValueException>(!components.contains(std::type_index(typeid(T))), "A component of the type specified already exists on the actor!");
            components.insert_or_assign(std::type_index(typeid(T)), std::make_shared<T>(std::forward<Args...>(args...)));
            PostMountComponent(components[std::type_index(typeid(T))]);
        }

        void MountComponent(std::shared_ptr<ComponentExporter> exporter) {
            Check<ExistingValueException>(!components.contains(std::type_index(exporter->type)), "A component of the type specified already exists on the actor!");
            components.insert_or_assign(std::type_index(std::type_index(exporter->type)), exporter->Instantiate());
            PostMountComponent(components[std::type_index(std::type_index(exporter->type))]);
        }

        template<typename T, typename... Args>
            requires std::is_base_of_v<Component, T>
        bool HasComponent() const {
            return components.contains(std::type_index(typeid(T)));
        }

        template<typename T, typename... Args>
            requires std::is_base_of_v<Component, T>
        std::shared_ptr<T> GetComponent() const {
            Check<NonexistentValueException>(components.contains(std::type_index(typeid(T))), "A component of the type specified does not exist on the actor!");
            return std::dynamic_pointer_cast<T>(components.at(std::type_index(typeid(T))));
        }

        template<typename T, typename... Args>
            requires std::is_base_of_v<Component, T>
        void DeleteComponent() {
            Check<NonexistentValueException>(components.contains(std::type_index(typeid(T))), "A component of the type specified does not exist on the actor!");
            components.erase(std::type_index(typeid(T)));
        }

        std::map<std::type_index, std::shared_ptr<Component>> GetAllComponents() const {
            return components;
        }

        std::vector<ActorHandle> GetAllChildren() const {
            return children;
        }

        ~Actor();

      private:
        Actor(const std::string& name, ActorHandle parent);
        friend class World;

        std::weak_ptr<Actor> parentPtr;
        std::weak_ptr<World> world;
        std::map<std::type_index, std::shared_ptr<Component>> components;
        std::vector<ActorHandle> children;

        void PostMountComponent(std::shared_ptr<Component> c);
        void NotifyFunctionallyActiveStateChanged();

        bool active, functionallyActive;
        bool isRoot = false;
    };
}