diff options
| -rw-r--r-- | src/crepe/api/Script.cpp | 8 | ||||
| -rw-r--r-- | src/crepe/api/Script.h | 3 | ||||
| -rw-r--r-- | src/crepe/api/Script.hpp | 6 | ||||
| -rw-r--r-- | src/crepe/manager/Mediator.h | 4 | ||||
| -rw-r--r-- | src/crepe/manager/SaveManager.cpp | 32 | ||||
| -rw-r--r-- | src/crepe/manager/SaveManager.h | 32 | ||||
| -rw-r--r-- | src/crepe/util/OptionalRef.h | 10 | ||||
| -rw-r--r-- | src/crepe/util/OptionalRef.hpp | 7 | ||||
| -rw-r--r-- | src/example/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/example/asset_manager.cpp | 36 | ||||
| -rw-r--r-- | src/example/savemgr.cpp | 44 | ||||
| -rw-r--r-- | src/test/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/test/SaveManagerTest.cpp | 40 | ||||
| -rw-r--r-- | src/test/ScriptSaveManagerTest.cpp | 35 | 
14 files changed, 128 insertions, 133 deletions
diff --git a/src/crepe/api/Script.cpp b/src/crepe/api/Script.cpp index 4091fd4..753a9e3 100644 --- a/src/crepe/api/Script.cpp +++ b/src/crepe/api/Script.cpp @@ -8,8 +8,7 @@ using namespace crepe;  using namespace std;  Script::~Script() { -	Mediator & mediator = this->mediator; -	EventManager & mgr = mediator.event_manager; +	EventManager & mgr = this->mediator->event_manager;  	for (auto id : this->listeners) {  		mgr.unsubscribe(id);  	} @@ -21,7 +20,8 @@ void Script::subscribe(const EventHandler<CollisionEvent> & callback) {  }  void Script::set_next_scene(const string & name) { -	Mediator & mediator = this->mediator; -	SceneManager & mgr = mediator.scene_manager; +	SceneManager & mgr = this->mediator->scene_manager;  	mgr.set_next_scene(name);  } + +SaveManager & Script::get_save_manager() const { return this->mediator->save_manager; } diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index d99ab0e..3417bb4 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -113,6 +113,9 @@ protected:  	 */  	void set_next_scene(const std::string & name); +	//! Retrieve SaveManager reference +	SaveManager & get_save_manager() const; +  	//! \}  private: diff --git a/src/crepe/api/Script.hpp b/src/crepe/api/Script.hpp index 45f1ff1..23d69d9 100644 --- a/src/crepe/api/Script.hpp +++ b/src/crepe/api/Script.hpp @@ -20,8 +20,7 @@ T & Script::get_component() const {  template <typename T>  RefVector<T> Script::get_components() const { -	Mediator & mediator = this->mediator; -	ComponentManager & mgr = mediator.component_manager; +	ComponentManager & mgr = this->mediator->component_manager;  	return mgr.get_components_by_id<T>(this->game_object_id);  } @@ -34,8 +33,7 @@ void Script::logf(Args &&... args) {  template <typename EventType>  void Script::subscribe_internal(const EventHandler<EventType> & callback,  								event_channel_t channel) { -	Mediator & mediator = this->mediator; -	EventManager & mgr = mediator.event_manager; +	EventManager & mgr = this->mediator->event_manager;  	subscription_t listener = mgr.subscribe<EventType>(  		[this, callback](const EventType & data) -> bool {  			bool & active = this->active; diff --git a/src/crepe/manager/Mediator.h b/src/crepe/manager/Mediator.h index 8094d80..6507a74 100644 --- a/src/crepe/manager/Mediator.h +++ b/src/crepe/manager/Mediator.h @@ -5,13 +5,13 @@  // TODO: remove these singletons:  #include "../facade/SDLContext.h"  #include "EventManager.h" -#include "SaveManager.h"  #include "api/LoopTimer.h"  namespace crepe {  class ComponentManager;  class SceneManager; +class SaveManager;  /**   * Struct to pass references to classes that would otherwise need to be singletons down to @@ -28,7 +28,7 @@ class SceneManager;  struct Mediator {  	OptionalRef<ComponentManager> component_manager;  	OptionalRef<SceneManager> scene_manager; -	OptionalRef<SaveManager> save_manager = SaveManager::get_instance(); +	OptionalRef<SaveManager> save_manager;  	OptionalRef<EventManager> event_manager = EventManager::get_instance();  	OptionalRef<SDLContext> sdl_context = SDLContext::get_instance();  	OptionalRef<LoopTimer> timer = LoopTimer::get_instance(); diff --git a/src/crepe/manager/SaveManager.cpp b/src/crepe/manager/SaveManager.cpp index d4ed1c1..292e8fd 100644 --- a/src/crepe/manager/SaveManager.cpp +++ b/src/crepe/manager/SaveManager.cpp @@ -1,13 +1,24 @@  #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 = make_unique<DB>(cfg.savemgr.location); +	} +	return *this->db; +} +  template <>  string SaveManager::serialize(const string & value) const noexcept {  	return value; @@ -90,22 +101,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 +150,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..1b55a22 100644 --- a/src/crepe/manager/SaveManager.h +++ b/src/crepe/manager/SaveManager.h @@ -4,6 +4,8 @@  #include "../ValueBroker.h" +#include "Manager.h" +  namespace crepe {  class DB; @@ -18,7 +20,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 +65,8 @@ public:  	 */  	bool has(const std::string & key); -private: -	SaveManager(); +public: +	SaveManager(Mediator & mediator);  	virtual ~SaveManager() = default;  private: @@ -89,26 +91,12 @@ 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<DB> db = nullptr;  };  } // namespace crepe diff --git a/src/crepe/util/OptionalRef.h b/src/crepe/util/OptionalRef.h index 3201667..1b2cb3f 100644 --- a/src/crepe/util/OptionalRef.h +++ b/src/crepe/util/OptionalRef.h @@ -25,7 +25,7 @@ public:  	 */  	OptionalRef<T> & operator=(T & ref);  	/** -	 * \brief Retrieve this reference +	 * \brief Retrieve this reference (cast)  	 *  	 * \returns Internal reference if it is set  	 * @@ -33,6 +33,14 @@ public:  	 */  	operator T &() const;  	/** +	 * \brief Retrieve this reference (member access) +	 * +	 * \returns Internal reference if it is set +	 * +	 * \throws std::runtime_error if this function is called while the reference it not set +	 */ +	T * operator->() const; +	/**  	 * \brief Check if this reference is not empty  	 *  	 * \returns `true` if reference is set, or `false` if it is not diff --git a/src/crepe/util/OptionalRef.hpp b/src/crepe/util/OptionalRef.hpp index 4608c9e..5e36b3a 100644 --- a/src/crepe/util/OptionalRef.hpp +++ b/src/crepe/util/OptionalRef.hpp @@ -19,6 +19,13 @@ OptionalRef<T>::operator T &() const {  }  template <typename T> +T * OptionalRef<T>::operator->() const { +	if (this->ref == nullptr) +		throw std::runtime_error("OptionalRef: attempt to dereference nullptr"); +	return this->ref; +} + +template <typename T>  OptionalRef<T> & OptionalRef<T>::operator=(T & ref) {  	this->ref = &ref;  	return *this; diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt index 8ef71bb..5a93b1f 100644 --- a/src/example/CMakeLists.txt +++ b/src/example/CMakeLists.txt @@ -16,8 +16,6 @@ function(add_example target_name)  	add_dependencies(examples ${target_name})  endfunction() -add_example(asset_manager) -add_example(savemgr)  add_example(rendering_particle)  add_example(game)  add_example(button) diff --git a/src/example/asset_manager.cpp b/src/example/asset_manager.cpp deleted file mode 100644 index 917b547..0000000 --- a/src/example/asset_manager.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include <crepe/api/AssetManager.h> -#include <crepe/api/Texture.h> -#include <crepe/facade/Sound.h> - -using namespace crepe; - -int main() { - -	// this needs to be called before the asset manager otherwise the destructor of sdl is not in -	// the right order -	{ Texture test("../asset/texture/img.png"); } -	// FIXME: make it so the issue described by the above comment is not possible (i.e. the order -	// in which internal classes are instantiated should not impact the way the engine works). - -	auto & mgr = AssetManager::get_instance(); - -	{ -		// TODO: [design] the Sound class can't be directly included by the user as it includes -		// SoLoud headers. -		auto bgm = mgr.cache<Sound>("../mwe/audio/bgm.ogg"); -		auto sfx1 = mgr.cache<Sound>("../mwe/audio/sfx1.wav"); -		auto sfx2 = mgr.cache<Sound>("../mwe/audio/sfx2.wav"); - -		auto img = mgr.cache<Texture>("../asset/texture/img.png"); -		auto img1 = mgr.cache<Texture>("../asset/texture/second.png"); -	} - -	{ -		auto bgm = mgr.cache<Sound>("../mwe/audio/bgm.ogg"); -		auto sfx1 = mgr.cache<Sound>("../mwe/audio/sfx1.wav"); -		auto sfx2 = mgr.cache<Sound>("../mwe/audio/sfx2.wav"); - -		auto img = mgr.cache<Texture>("../asset/texture/img.png"); -		auto img1 = mgr.cache<Texture>("../asset/texture/second.png"); -	} -} diff --git a/src/example/savemgr.cpp b/src/example/savemgr.cpp deleted file mode 100644 index 65c4a34..0000000 --- a/src/example/savemgr.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/** \file - *  - * Standalone example for usage of the save manager - */ - -#include <cassert> -#include <crepe/api/Config.h> -#include <crepe/api/SaveManager.h> -#include <crepe/util/Log.h> -#include <crepe/util/Proxy.h> - -using namespace crepe; - -// unrelated setup code -int _ = []() { -	// make sure all log messages get printed -	auto & cfg = Config::get_instance(); -	cfg.log.level = Log::Level::TRACE; - -	return 0; // satisfy compiler -}(); - -int main() { -	const char * key = "mygame.test"; - -	SaveManager & mgr = SaveManager::get_instance(); - -	dbg_logf("has key = {}", mgr.has(key)); -	ValueBroker<int> prop = mgr.get<int>(key, 0); -	Proxy<int> val = mgr.get<int>(key, 0); - -	dbg_logf("val = {}", mgr.get<int>(key).get()); -	prop.set(1); -	dbg_logf("val = {}", mgr.get<int>(key).get()); -	val = 2; -	dbg_logf("val = {}", mgr.get<int>(key).get()); -	mgr.set<int>(key, 3); -	dbg_logf("val = {}", mgr.get<int>(key).get()); - -	dbg_logf("has key = {}", mgr.has(key)); -	assert(true == mgr.has(key)); - -	return 0; -} diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index c9cbac5..2cb7c7a 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -17,4 +17,6 @@ target_sources(test_main PUBLIC  	ScriptEventTest.cpp  	ScriptSceneTest.cpp  	Profiling.cpp +	SaveManagerTest.cpp +	ScriptSaveManagerTest.cpp  ) diff --git a/src/test/SaveManagerTest.cpp b/src/test/SaveManagerTest.cpp new file mode 100644 index 0000000..e9b0c29 --- /dev/null +++ b/src/test/SaveManagerTest.cpp @@ -0,0 +1,40 @@ +#include <gtest/gtest.h> + +#include <crepe/ValueBroker.h> +#include <crepe/facade/DB.h> +#include <crepe/manager/SaveManager.h> + +using namespace std; +using namespace crepe; +using namespace testing; + +class SaveManagerTest : public Test { +	Mediator m; +	class TestSaveManager : public SaveManager { +		using SaveManager::SaveManager; + +		// in-memory database for testing +		DB db{}; +		virtual DB & get_db() override { return this->db; } +	}; + +public: +	TestSaveManager mgr{m}; +}; + +TEST_F(SaveManagerTest, ReadWrite) { +	ASSERT_FALSE(mgr.has("foo")); +	mgr.set<string>("foo", "bar"); +	ASSERT_TRUE(mgr.has("foo")); + +	ValueBroker value = mgr.get<string>("foo"); +	EXPECT_EQ(value.get(), "bar"); +} + +TEST_F(SaveManagerTest, DefaultValue) { +	ValueBroker value = mgr.get<int>("foo", 3); + +	ASSERT_EQ(value.get(), 3); +	value.set(5); +	ASSERT_EQ(value.get(), 5); +} diff --git a/src/test/ScriptSaveManagerTest.cpp b/src/test/ScriptSaveManagerTest.cpp new file mode 100644 index 0000000..64403c4 --- /dev/null +++ b/src/test/ScriptSaveManagerTest.cpp @@ -0,0 +1,35 @@ +#include <gtest/gtest.h> + +// stupid hack to allow access to private/protected members under test +#define private public +#define protected public + +#include <crepe/facade/DB.h> +#include <crepe/manager/SaveManager.h> + +#include "ScriptTest.h" + +using namespace std; +using namespace crepe; +using namespace testing; + +class ScriptSaveManagerTest : public ScriptTest { +public: +	class TestSaveManager : public SaveManager { +		using SaveManager::SaveManager; + +		// in-memory database for testing +		DB db{}; +		virtual DB & get_db() override { return this->db; } +	}; + +	TestSaveManager save_mgr{mediator}; +}; + +TEST_F(ScriptSaveManagerTest, GetSaveManager) { +	MyScript & script = this->script; + +	SaveManager & mgr = script.get_save_manager(); + +	EXPECT_EQ(&mgr, &save_mgr); +}  |