#pragma once #include <type_traits> #include "ComponentManager.h" #include "types.h" namespace crepe { template <class T, typename... Args> T & ComponentManager::add_component(game_object_id_t id, Args &&... args) { using namespace std; static_assert(is_base_of<Component, T>::value, "add_component must recieve a derivative class of Component"); // Determine the type of T (this is used as the key of the unordered_map<>) type_index type = typeid(T); // Check if this component type is already in the unordered_map<> if (this->components.find(type) == this->components.end()) { //If not, create a new (empty) vector<> of vector<unique_ptr<Component>> this->components[type] = vector<vector<unique_ptr<Component>>>(); } // Resize the vector<> if the id is greater than the current size if (id >= this->components[type].size()) { // Initialize new slots to nullptr (resize does automatically init to nullptr) this->components[type].resize(id + 1); } // Create a new component of type T (arguments directly forwarded). The // constructor must be called by ComponentManager. T * instance_ptr = new T(id, forward<Args>(args)...); if (instance_ptr == nullptr) throw std::bad_alloc(); T & instance_ref = *instance_ptr; unique_ptr<T> instance = unique_ptr<T>(instance_ptr); // Check if the vector size is not greater than get_instances_max int max_instances = instance->get_instances_max(); if (max_instances != -1 && components[type][id].size() >= max_instances) { // TODO: Exception throw std::runtime_error( "Exceeded maximum number of instances for this component type"); } // store its unique_ptr in the vector<> this->components[type][id].push_back(std::move(instance)); return instance_ref; } template <typename T> void ComponentManager::delete_components_by_id(game_object_id_t id) { using namespace std; // Determine the type of T (this is used as the key of the unordered_map<>) type_index type = typeid(T); // Find the type (in the unordered_map<>) if (this->components.find(type) != this->components.end()) { // Get the correct vector<> vector<vector<unique_ptr<Component>>> & component_array = this->components[type]; // Make sure that the id (that we are looking for) is within the boundaries of the vector<> if (id < component_array.size()) { // Clear the whole vector<> of this specific type and id component_array[id].clear(); } } } template <typename T> void ComponentManager::delete_components() { // Determine the type of T (this is used as the key of the unordered_map<>) std::type_index type = typeid(T); if (this->components.find(type) == this->components.end()) return; this->components[type].clear(); } template <typename T> std::vector<std::reference_wrapper<T>> ComponentManager::get_components_by_id(game_object_id_t id) const { using namespace std; // Determine the type of T (this is used as the key of the unordered_map<>) type_index type = typeid(T); // Create an empty vector<> vector<reference_wrapper<T>> component_vector; if (this->components.find(type) == this->components.end()) return component_vector; // Get the correct vector<> const vector<vector<unique_ptr<Component>>> & component_array = this->components.at(type); // Make sure that the id (that we are looking for) is within the boundaries of the vector<> if (id >= component_array.size()) return component_vector; // Loop trough the whole vector<> for (const unique_ptr<Component> & component_ptr : component_array[id]) { // Cast the unique_ptr to a raw pointer T * casted_component = static_cast<T *>(component_ptr.get()); if (casted_component == nullptr) continue; // Add the dereferenced raw pointer to the vector<> component_vector.push_back(*casted_component); } return component_vector; } template <typename T> std::vector<std::reference_wrapper<T>> ComponentManager::get_components_by_type() const { using namespace std; // Determine the type of T (this is used as the key of the unordered_map<>) type_index type = typeid(T); // Create an empty vector<> vector<reference_wrapper<T>> component_vector; // Find the type (in the unordered_map<>) if (this->components.find(type) == this->components.end()) return component_vector; // Get the correct vector<> const vector<vector<unique_ptr<Component>>> & component_array = this->components.at(type); // Loop through the whole vector<> for (const vector<unique_ptr<Component>> & component : component_array) { // Loop trough the whole vector<> for (const unique_ptr<Component> & component_ptr : component) { // Cast the unique_ptr to a raw pointer T * casted_component = static_cast<T *>(component_ptr.get()); // Ensure that the cast was successful if (casted_component == nullptr) continue; // Add the dereferenced raw pointer to the vector<> component_vector.emplace_back(ref(*casted_component)); } } // Return the vector<> return component_vector; } } // namespace crepe