#pragma once #include #include "ComponentManager.h" #include "types.h" namespace crepe { template T & ComponentManager::add_component(game_object_id_t id, Args &&... args) { using namespace std; static_assert(is_base_of::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> this->components[type] = vector>>(); } // 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)...); if (instance_ptr == nullptr) throw std::bad_alloc(); T & instance_ref = *instance_ptr; unique_ptr instance = unique_ptr(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) { 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 void ComponentManager::delete_components_by_id(game_object_id_t id) { using namespace std; // Do not delete persistent objects if (this->persistent[id]) { return; } // 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>> & 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 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; // Loop through the whole vector<> of this specific type for (game_object_id_t i = 0; i < this->components[type].size(); ++i) { // Do not delete persistent objects if (!this->persistent[i]) { this->components[type][i].clear(); } } } template RefVector ComponentManager::get_components_by_id(game_object_id_t id) const { using namespace std; static_assert(is_base_of::value, "get_components_by_id must recieve a derivative class of Component"); type_index type = typeid(T); if (!this->components.contains(type)) return {}; const by_id_index>> & components_by_id = this->components.at(type); if (id >= components_by_id.size()) return {}; RefVector out = {}; const vector> & components = components_by_id.at(id); for (auto & component_ptr : components) { if (component_ptr == nullptr) continue; Component & component = *component_ptr.get(); out.push_back(static_cast(component)); } return out; } template RefVector 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<> RefVector 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>> & component_array = this->components.at(type); // Loop through the whole vector<> for (const vector> & component : component_array) { // Loop trough the whole vector<> for (const unique_ptr & component_ptr : component) { // Cast the unique_ptr to a raw pointer T * casted_component = static_cast(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; } template std::set ComponentManager::get_objects_by_predicate(const std::function & pred) const { using namespace std; set objects = {}; RefVector components = this->get_components_by_type(); for (const T & component : components) { game_object_id_t id = dynamic_cast(component).game_object_id; if (objects.contains(id)) continue; if (!pred(component)) continue; objects.insert(id); } return objects; } template RefVector ComponentManager::get_components_by_ids(const std::set & ids) const { using namespace std; RefVector out = {}; for (game_object_id_t id : ids) { RefVector components = get_components_by_id(id); out.insert(out.end(), components.begin(), components.end()); } return out; } template RefVector ComponentManager::get_components_by_name(const std::string & name) const { return this->get_components_by_ids(this->get_objects_by_name(name)); } template RefVector ComponentManager::get_components_by_tag(const std::string & tag) const { return this->get_components_by_ids(this->get_objects_by_tag(tag)); } } // namespace crepe