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 <cstdint>
#include <memory>
#include <string>
#include <typeindex>
#include "crossguid/guid.hpp"
namespace Cacao {
class Actor;
class World;
class ActorRef {
public:
ActorRef() {}
Actor* operator->();
const Actor* operator->() const;
operator bool() const noexcept;
bool operator==(const ActorRef& rhs) const noexcept;
private:
friend class Actor;
friend class World;
//Non-owning World pointer
std::weak_ptr<World> world;
//Actor slot access information
uint64_t slotID;
uint64_t generation;
//Null state
bool null = true;
//Hidden valid handle constructor
ActorRef(std::weak_ptr<World> world, uint64_t slot, uint64_t generation) : world(world), slotID(slot), generation(generation), null(false) {}
//Hidden resolver function
void* Resolve() const noexcept;
};
class CACAO_API Component {
public:
bool IsEnabled() const;
void SetEnabled(bool state) {
enabled = state;
if(IsEnabled()) {
OnEnable();
}
}
ActorRef GetOwner() const {
Check<NonexistentValueException>((bool)owner, "Cannot access the invalid owner of a component!");
return owner;
}
virtual ~Component() {}
protected:
Component() {}
virtual void OnMount() {};
virtual void OnDelete() {};
virtual void OnEnable() {};
virtual void OnDisable() {};
friend class Actor;
private:
bool enabled;
ActorRef owner;
};
class CACAO_API Actor {
public:
std::string name;
const xg::Guid guid;
Transform transform;
glm::mat4 GetWorldTransformMatrix() const;
ActorRef GetParent() const {
return parent;
}
bool IsActive() const;
void SetActive(bool state);
void Reparent(ActorRef newParent);
template<typename T>
requires std::is_base_of_v<Component, T>
bool HasComponent() const {
return components.contains(std::type_index(typeid(T))) && components.at(std::type_index(typeid(T))).component;
}
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>(!HasComponent<T>(), "A component of the type specified already exists on the actor!");
//Prepare objects
std::type_index type(typeid(T));
std::unique_ptr<T> component = std::make_unique<T>(std::forward<Args...>(args...));
//Call-down to internal function
_ComponentSetup(type, std::move(component));
}
void MountComponent(const std::string& factoryID);
template<typename T>
requires std::is_base_of_v<Component, T>
T& GetComponent() const {
Check<NonexistentValueException>(HasComponent<T>(), "A component of the type specified does not exist on the actor!");
return dynamic_cast<T&>(*components.at(typeid(T)).component);
}
template<typename T>
requires std::is_base_of_v<Component, T>
void DeleteComponent() {
Check<NonexistentValueException>(HasComponent<T>(), "A component of the type specified does not exist on the actor!");
components.erase(std::type_index(typeid(T)));
}
std::unordered_map<std::type_index, Component*> GetAllComponents() const {
return _ComponentGet([](const std::unique_ptr<Component>&) { return true; });
}
template<typename F>
requires std::is_invocable_r_v<bool, F, const std::unique_ptr<Component>&>
std::unordered_map<std::type_index, Component*> GetComponentsFiltered(F filter) const {
return _ComponentGet([&filter](const std::unique_ptr<Component>& c) { return filter(c); });
}
std::vector<ActorRef> GetAllChildren() const {
return children;
}
private:
Actor(const std::string& name, ActorRef parent, xg::Guid);
friend class World;
friend class Component;
struct ComponentHandle {
std::unique_ptr<Component> component;
uint64_t generation = 0;
ComponentHandle() = default;
ComponentHandle(ComponentHandle&&) = default;
ComponentHandle& operator=(ComponentHandle&&) = default;
ComponentHandle(const ComponentHandle& o)
: component(std::make_unique<Component>(*o.component)), generation(0) {}
ComponentHandle& operator=(const ComponentHandle& o) {
if(this != &o) {
component = std::make_unique<Component>(*o.component);
generation = 0;
}
return *this;
}
};
ActorRef parent;
ActorRef self;
std::vector<ActorRef> children;
std::unordered_map<std::type_index, ComponentHandle> components;
World* world;//NON-OWNING --- DO NOT FREE THIS
void _ComponentSetup(std::type_index type, std::unique_ptr<Component>&& ptr);
std::unordered_map<std::type_index, Component*> _ComponentGet(std::function<bool(const std::unique_ptr<Component>&)> filter) const;
bool active;
};
}