aboutsummaryrefslogtreecommitdiff
path: root/src/crepe/ComponentManager.hpp
blob: ffb38ec9825862440e62c8d7c11f2d2c172c5234 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#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) {
		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;

	// 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<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;

	// 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 <typename T>
RefVector<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<>
	RefVector<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>
RefVector<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<>
	RefVector<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