aboutsummaryrefslogtreecommitdiff
path: root/src/crepe/manager
diff options
context:
space:
mode:
Diffstat (limited to 'src/crepe/manager')
-rw-r--r--src/crepe/manager/CMakeLists.txt3
-rw-r--r--src/crepe/manager/ComponentManager.cpp11
-rw-r--r--src/crepe/manager/ComponentManager.h73
-rw-r--r--src/crepe/manager/ComponentManager.hpp81
-rw-r--r--src/crepe/manager/Mediator.h5
-rw-r--r--src/crepe/manager/ResourceManager.cpp30
-rw-r--r--src/crepe/manager/ResourceManager.h78
-rw-r--r--src/crepe/manager/ResourceManager.hpp27
-rw-r--r--src/crepe/manager/SaveManager.cpp33
-rw-r--r--src/crepe/manager/SaveManager.h32
10 files changed, 308 insertions, 65 deletions
diff --git a/src/crepe/manager/CMakeLists.txt b/src/crepe/manager/CMakeLists.txt
index 29d6df0..f73e165 100644
--- a/src/crepe/manager/CMakeLists.txt
+++ b/src/crepe/manager/CMakeLists.txt
@@ -5,6 +5,7 @@ target_sources(crepe PUBLIC
SaveManager.cpp
SceneManager.cpp
LoopTimerManager.cpp
+ ResourceManager.cpp
)
target_sources(crepe PUBLIC FILE_SET HEADERS FILES
@@ -18,5 +19,7 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
SceneManager.h
SceneManager.hpp
LoopTimerManager.h
+ ResourceManager.h
+ ResourceManager.hpp
)
diff --git a/src/crepe/manager/ComponentManager.cpp b/src/crepe/manager/ComponentManager.cpp
index 80cf8b4..df30d27 100644
--- a/src/crepe/manager/ComponentManager.cpp
+++ b/src/crepe/manager/ComponentManager.cpp
@@ -1,4 +1,5 @@
#include "../api/GameObject.h"
+#include "../api/Metadata.h"
#include "../types.h"
#include "../util/Log.h"
@@ -61,3 +62,13 @@ GameObject ComponentManager::new_object(const string & name, const string & tag,
void ComponentManager::set_persistent(game_object_id_t id, bool persistent) {
this->persistent[id] = persistent;
}
+
+set<game_object_id_t> ComponentManager::get_objects_by_name(const string & name) const {
+ return this->get_objects_by_predicate<Metadata>(
+ [name](const Metadata & data) { return data.name == name; });
+}
+
+set<game_object_id_t> ComponentManager::get_objects_by_tag(const string & tag) const {
+ return this->get_objects_by_predicate<Metadata>(
+ [tag](const Metadata & data) { return data.tag == tag; });
+}
diff --git a/src/crepe/manager/ComponentManager.h b/src/crepe/manager/ComponentManager.h
index 44429d9..19a8e81 100644
--- a/src/crepe/manager/ComponentManager.h
+++ b/src/crepe/manager/ComponentManager.h
@@ -1,6 +1,7 @@
#pragma once
#include <memory>
+#include <set>
#include <typeindex>
#include <unordered_map>
#include <vector>
@@ -134,8 +135,77 @@ public:
*/
template <typename T>
RefVector<T> get_components_by_type() const;
+ /**
+ * \brief Get all components of a specific type on a GameObject with name \c name
+ *
+ * \tparam T The type of the component
+ * \param name Metadata::name for the same game_object_id as the returned components
+ * \return Components matching criteria
+ */
+ template <typename T>
+ RefVector<T> get_components_by_name(const std::string & name) const;
+ /**
+ * \brief Get all components of a specific type on a GameObject with tag \c tag
+ *
+ * \tparam T The type of the component
+ * \param name Metadata::tag for the same game_object_id as the returned components
+ * \return Components matching criteria
+ */
+ template <typename T>
+ RefVector<T> get_components_by_tag(const std::string & tag) const;
+
+private:
+ /**
+ * \brief Get object IDs by predicate function
+ *
+ * This function calls the predicate function \c pred for all components matching type \c T,
+ * and adds their parent game_object_id to a \c std::set if the predicate returns true.
+ *
+ * \tparam T The type of the component to check the predicate against
+ * \param pred Predicate function
+ *
+ * \note The predicate function may be called for multiple components with the same \c
+ * game_object_id. In this case, the ID is added if *any* call returns \c true.
+ *
+ * \returns game_object_id for all components where the predicate returned true
+ */
+ template <typename T>
+ std::set<game_object_id_t>
+ get_objects_by_predicate(const std::function<bool(const T &)> & pred) const;
+
+ /**
+ * \brief Get components of type \c T for multiple game object IDs
+ *
+ * \tparam T The type of the components to return
+ * \param ids The object IDs
+ *
+ * \return All components matching type \c T and one of the IDs in \c ids
+ */
+ template <typename T>
+ RefVector<T> get_components_by_ids(const std::set<game_object_id_t> & ids) const;
+
+ /**
+ * \brief Get object IDs for objects with name \c name
+ *
+ * \param name Object name to match
+ * \returns Object IDs where Metadata::name is equal to \c name
+ */
+ std::set<game_object_id_t> get_objects_by_name(const std::string & name) const;
+ /**
+ * \brief Get object IDs for objects with tag \c tag
+ *
+ * \param tag Object tag to match
+ * \returns Object IDs where Metadata::tag is equal to \c tag
+ */
+ std::set<game_object_id_t> get_objects_by_tag(const std::string & tag) const;
private:
+ //! By Component \c std::type_index (readability helper type)
+ template <typename T>
+ using by_type = std::unordered_map<std::type_index, T>;
+ //! By \c game_object_id index (readability helper type)
+ template <typename T>
+ using by_id_index = std::vector<T>;
/**
* \brief The components
*
@@ -146,8 +216,7 @@ private:
* The first vector is for the ids of the GameObjects and the second vector is for the
* components (because a GameObject might have multiple components).
*/
- std::unordered_map<std::type_index, std::vector<std::vector<std::unique_ptr<Component>>>>
- components;
+ by_type<by_id_index<std::vector<std::unique_ptr<Component>>>> components;
//! Persistent flag for each GameObject
std::unordered_map<game_object_id_t, bool> persistent;
diff --git a/src/crepe/manager/ComponentManager.hpp b/src/crepe/manager/ComponentManager.hpp
index ffb38ec..9e70865 100644
--- a/src/crepe/manager/ComponentManager.hpp
+++ b/src/crepe/manager/ComponentManager.hpp
@@ -95,32 +95,25 @@ 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;
+ static_assert(is_base_of<Component, T>::value,
+ "get_components_by_id must recieve a derivative class of Component");
- // Add the dereferenced raw pointer to the vector<>
- component_vector.push_back(*casted_component);
+ type_index type = typeid(T);
+ if (!this->components.contains(type)) return {};
+
+ const by_id_index<vector<unique_ptr<Component>>> & components_by_id
+ = this->components.at(type);
+ if (id >= components_by_id.size()) return {};
+
+ RefVector<T> out = {};
+ const vector<unique_ptr<Component>> & 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<T &>(component));
}
- return component_vector;
+ return out;
}
template <typename T>
@@ -158,4 +151,46 @@ RefVector<T> ComponentManager::get_components_by_type() const {
return component_vector;
}
+template <typename T>
+std::set<game_object_id_t>
+ComponentManager::get_objects_by_predicate(const std::function<bool(const T &)> & pred) const {
+ using namespace std;
+
+ set<game_object_id_t> objects = {};
+ RefVector<T> components = this->get_components_by_type<T>();
+
+ for (const T & component : components) {
+ game_object_id_t id = dynamic_cast<const Component &>(component).game_object_id;
+ if (objects.contains(id)) continue;
+ if (!pred(component)) continue;
+ objects.insert(id);
+ }
+
+ return objects;
+}
+
+template <typename T>
+RefVector<T>
+ComponentManager::get_components_by_ids(const std::set<game_object_id_t> & ids) const {
+ using namespace std;
+
+ RefVector<T> out = {};
+ for (game_object_id_t id : ids) {
+ RefVector<T> components = get_components_by_id<T>(id);
+ out.insert(out.end(), components.begin(), components.end());
+ }
+
+ return out;
+}
+
+template <typename T>
+RefVector<T> ComponentManager::get_components_by_name(const std::string & name) const {
+ return this->get_components_by_ids<T>(this->get_objects_by_name(name));
+}
+
+template <typename T>
+RefVector<T> ComponentManager::get_components_by_tag(const std::string & tag) const {
+ return this->get_components_by_ids<T>(this->get_objects_by_tag(tag));
+}
+
} // namespace crepe
diff --git a/src/crepe/manager/Mediator.h b/src/crepe/manager/Mediator.h
index ad51cc6..dfb37dc 100644
--- a/src/crepe/manager/Mediator.h
+++ b/src/crepe/manager/Mediator.h
@@ -11,6 +11,8 @@ namespace crepe {
class ComponentManager;
class SceneManager;
+class SaveManager;
+class ResourceManager;
class LoopTimerManager;
class EventManager;
@@ -31,7 +33,8 @@ struct Mediator {
OptionalRef<SceneManager> scene_manager;
OptionalRef<EventManager> event_manager;
OptionalRef<LoopTimerManager> loop_timer;
- OptionalRef<SaveManager> save_manager = SaveManager::get_instance();
+ OptionalRef<SaveManager> save_manager;
+ OptionalRef<ResourceManager> resource_manager;
OptionalRef<SDLContext> sdl_context = SDLContext::get_instance();
};
diff --git a/src/crepe/manager/ResourceManager.cpp b/src/crepe/manager/ResourceManager.cpp
new file mode 100644
index 0000000..7c01808
--- /dev/null
+++ b/src/crepe/manager/ResourceManager.cpp
@@ -0,0 +1,30 @@
+#include "util/Log.h"
+
+#include "ResourceManager.h"
+
+using namespace crepe;
+using namespace std;
+
+ResourceManager::ResourceManager(Mediator & mediator) : Manager(mediator) {
+ mediator.resource_manager = *this;
+ dbg_trace();
+}
+ResourceManager::~ResourceManager() { dbg_trace(); }
+
+void ResourceManager::clear() {
+ std::erase_if(this->resources, [](const pair<const Asset, CacheEntry> & pair) {
+ const CacheEntry & entry = pair.second;
+ return entry.persistent == false;
+ });
+}
+
+void ResourceManager::clear_all() { this->resources.clear(); }
+
+void ResourceManager::set_persistent(const Asset & asset, bool persistent) {
+ this->get_entry(asset).persistent = persistent;
+}
+
+ResourceManager::CacheEntry & ResourceManager::get_entry(const Asset & asset) {
+ if (!this->resources.contains(asset)) this->resources[asset] = {};
+ return this->resources.at(asset);
+}
diff --git a/src/crepe/manager/ResourceManager.h b/src/crepe/manager/ResourceManager.h
new file mode 100644
index 0000000..84b275d
--- /dev/null
+++ b/src/crepe/manager/ResourceManager.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include <memory>
+#include <unordered_map>
+
+#include "../Resource.h"
+#include "../api/Asset.h"
+
+#include "Manager.h"
+
+namespace crepe {
+
+/**
+ * \brief Owner of concrete Resource instances
+ *
+ * ResourceManager caches concrete Resource instances per Asset. Concrete resources are
+ * destroyed at the end of scenes by default, unless the game programmer marks them as
+ * persistent.
+ */
+class ResourceManager : public Manager {
+public:
+ ResourceManager(Mediator & mediator);
+ virtual ~ResourceManager(); // dbg_trace
+
+private:
+ //! Cache entry
+ struct CacheEntry {
+ //! Concrete resource instance
+ std::unique_ptr<Resource> resource = nullptr;
+ //! Prevent ResourceManager::clear from removing this entry
+ bool persistent = false;
+ };
+ //! Internal cache
+ std::unordered_map<const Asset, CacheEntry> resources;
+ /**
+ * \brief Ensure a cache entry exists for this asset and return a mutable reference to it
+ *
+ * \param asset Asset the concrete resource is instantiated from
+ *
+ * \returns Mutable reference to cache entry
+ */
+ CacheEntry & get_entry(const Asset & asset);
+
+public:
+ /**
+ * \brief Mark a resource as persistent (i.e. used across multiple scenes)
+ *
+ * \param asset Asset the concrete resource is instantiated from
+ * \param persistent Whether this resource is persistent (true=keep, false=destroy)
+ */
+ void set_persistent(const Asset & asset, bool persistent);
+
+ /**
+ * \brief Retrieve reference to concrete Resource by Asset
+ *
+ * \param asset Asset the concrete resource is instantiated from
+ * \tparam Resource Concrete derivative of Resource
+ *
+ * This class instantiates the concrete resource if it is not yet stored in the internal
+ * cache, or returns a reference to the cached resource if it already exists.
+ *
+ * \returns Reference to concrete resource
+ *
+ * \throws std::runtime_error if the \c Resource parameter does not match with the actual
+ * type of the resource stored in the cache for this Asset
+ */
+ template <typename Resource>
+ Resource & get(const Asset & asset);
+
+ //! Clear non-persistent resources from cache
+ void clear();
+ //! Clear all resources from cache regardless of persistence
+ void clear_all();
+};
+
+} // namespace crepe
+
+#include "ResourceManager.hpp"
diff --git a/src/crepe/manager/ResourceManager.hpp b/src/crepe/manager/ResourceManager.hpp
new file mode 100644
index 0000000..5167d71
--- /dev/null
+++ b/src/crepe/manager/ResourceManager.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <format>
+
+#include "ResourceManager.h"
+
+namespace crepe {
+
+template <typename T>
+T & ResourceManager::get(const Asset & asset) {
+ using namespace std;
+ static_assert(is_base_of<Resource, T>::value,
+ "cache must recieve a derivative class of Resource");
+
+ CacheEntry & entry = this->get_entry(asset);
+ if (entry.resource == nullptr) entry.resource = make_unique<T>(asset);
+
+ T * concrete_resource = dynamic_cast<T *>(entry.resource.get());
+ if (concrete_resource == nullptr)
+ throw runtime_error(format("ResourceManager: mismatch between requested type and "
+ "actual type of resource ({})",
+ asset.get_path()));
+
+ return *concrete_resource;
+}
+
+} // namespace crepe
diff --git a/src/crepe/manager/SaveManager.cpp b/src/crepe/manager/SaveManager.cpp
index d4ed1c1..691ea2f 100644
--- a/src/crepe/manager/SaveManager.cpp
+++ b/src/crepe/manager/SaveManager.cpp
@@ -1,13 +1,25 @@
#include "../ValueBroker.h"
#include "../api/Config.h"
#include "../facade/DB.h"
-#include "../util/Log.h"
#include "SaveManager.h"
using namespace std;
using namespace crepe;
+SaveManager::SaveManager(Mediator & mediator) : Manager(mediator) {
+ mediator.save_manager = *this;
+}
+
+DB & SaveManager::get_db() {
+ if (this->db == nullptr) {
+ Config & cfg = Config::get_instance();
+ this->db
+ = {new DB(cfg.savemgr.location), [](void * db) { delete static_cast<DB *>(db); }};
+ }
+ return *static_cast<DB *>(this->db.get());
+}
+
template <>
string SaveManager::serialize(const string & value) const noexcept {
return value;
@@ -90,22 +102,6 @@ int32_t SaveManager::deserialize(const string & value) const noexcept {
return deserialize<int64_t>(value);
}
-SaveManager::SaveManager() { dbg_trace(); }
-
-SaveManager & SaveManager::get_instance() {
- dbg_trace();
- static SaveManager instance;
- return instance;
-}
-
-DB & SaveManager::get_db() {
- Config & cfg = Config::get_instance();
- // TODO: make this path relative to XDG_DATA_HOME on Linux and whatever the
- // default equivalent is on Windows using some third party library
- static DB db(cfg.savemgr.location);
- return db;
-}
-
bool SaveManager::has(const string & key) {
DB & db = this->get_db();
return db.has(key);
@@ -155,7 +151,8 @@ ValueBroker<T> SaveManager::get(const string & key) {
return {
[this, key](const T & target) { this->set<T>(key, target); },
[this, key, value]() mutable -> const T & {
- value = this->deserialize<T>(this->get_db().get(key));
+ DB & db = this->get_db();
+ value = this->deserialize<T>(db.get(key));
return value;
},
};
diff --git a/src/crepe/manager/SaveManager.h b/src/crepe/manager/SaveManager.h
index 3d8c852..61a978d 100644
--- a/src/crepe/manager/SaveManager.h
+++ b/src/crepe/manager/SaveManager.h
@@ -1,9 +1,12 @@
#pragma once
+#include <functional>
#include <memory>
#include "../ValueBroker.h"
+#include "Manager.h"
+
namespace crepe {
class DB;
@@ -18,7 +21,7 @@ class DB;
*
* The underlying database is a key-value store.
*/
-class SaveManager {
+class SaveManager : public Manager {
public:
/**
* \brief Get a read/write reference to a value and initialize it if it does not yet exist
@@ -63,8 +66,8 @@ public:
*/
bool has(const std::string & key);
-private:
- SaveManager();
+public:
+ SaveManager(Mediator & mediator);
virtual ~SaveManager() = default;
private:
@@ -89,26 +92,13 @@ private:
template <typename T>
T deserialize(const std::string & value) const noexcept;
-public:
- // singleton
- static SaveManager & get_instance();
- SaveManager(const SaveManager &) = delete;
- SaveManager(SaveManager &&) = delete;
- SaveManager & operator=(const SaveManager &) = delete;
- SaveManager & operator=(SaveManager &&) = delete;
+protected:
+ //! Create or return DB
+ virtual DB & get_db();
private:
- /**
- * \brief Create an instance of DB and return its reference
- *
- * \returns DB instance
- *
- * This function exists because DB is a facade class, which can't directly be used in the API
- * without workarounds
- *
- * TODO: better solution
- */
- static DB & get_db();
+ //! Database
+ std::unique_ptr<void, std::function<void(void *)>> db = nullptr;
};
} // namespace crepe