diff --git a/src/data/setting.h b/src/data/setting.h index 1146b8ac..e25ee864 100644 --- a/src/data/setting.h +++ b/src/data/setting.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "../typedefs.h" #include "../delegates.h" @@ -30,13 +31,35 @@ public: virtual std::string toString() const = 0; }; +using observer_handler = std::shared_ptr; + +template +class Observers { + int nextid = 1; + std::unordered_map> observers; +public: + observer_handler observe(consumer callback) { + const int id = nextid++; + observers.emplace(id, callback); + return std::shared_ptr(new int(id), [this](int* id) { + observers.erase(*id); + }); + } + + void notify(T value) { + for (auto& entry : observers) { + entry.second(value); + } + } +}; + class NumberSetting : public Setting { protected: number_t initial; number_t value; number_t min; number_t max; - std::vector> consumers; + Observers observers; public: NumberSetting( number_t value, @@ -63,9 +86,7 @@ public: return; } this->value = value; - for (auto& callback : consumers) { - callback(value); - } + observers.notify(value); } number_t getMin() const { @@ -80,12 +101,12 @@ public: return (value - min) / (max - min); } - void observe(consumer callback) { - consumers.push_back(callback); + observer_handler observe(consumer callback) { + return observers.observe(callback); } virtual void resetToDefault() override { - value = initial; + set(initial); } virtual std::string toString() const override; @@ -101,7 +122,7 @@ protected: integer_t value; integer_t min; integer_t max; - std::vector> consumers; + Observers observers; public: IntegerSetting( integer_t value, @@ -128,9 +149,7 @@ public: return; } this->value = value; - for (auto& callback : consumers) { - callback(value); - } + observers.notify(value); } integer_t getMin() const { @@ -145,12 +164,12 @@ public: return (value - min) / (max - min); } - void observe(consumer callback) { - consumers.push_back(callback); + observer_handler observe(consumer callback) { + return observers.observe(callback); } virtual void resetToDefault() override { - value = initial; + set(initial); } virtual std::string toString() const override; @@ -160,7 +179,7 @@ class FlagSetting : public Setting { protected: bool initial; bool value; - std::vector> consumers; + Observers observers; public: FlagSetting( bool value, @@ -183,17 +202,15 @@ public: return; } this->value = value; - for (auto& callback : consumers) { - callback(value); - } + observers.notify(value); } - void observe(consumer callback) { - consumers.push_back(callback); + observer_handler observe(consumer callback) { + return observers.observe(callback); } virtual void resetToDefault() override { - value = initial; + set(initial); } virtual std::string toString() const override; diff --git a/src/engine.cpp b/src/engine.cpp index 3821fafa..54d62ec5 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -47,13 +47,13 @@ void addWorldGenerators() { WorldGenerators::addGenerator("core:flat"); } -inline void create_channel(std::string name, NumberSetting& setting) { +inline void create_channel(Engine* engine, std::string name, NumberSetting& setting) { if (name != "master") { audio::create_channel(name); } - setting.observe([=](auto value) { + engine->keepAlive(setting.observe([=](auto value) { audio::get_channel(name)->setVolume(value*value); - }); + })); } Engine::Engine(EngineSettings& settings, EnginePaths* paths) @@ -64,11 +64,11 @@ Engine::Engine(EngineSettings& settings, EnginePaths* paths) throw initialize_error("could not initialize window"); } audio::initialize(settings.audio.enabled); - create_channel("master", settings.audio.volumeMaster); - create_channel("regular", settings.audio.volumeRegular); - create_channel("music", settings.audio.volumeMusic); - create_channel("ambient", settings.audio.volumeAmbient); - create_channel("ui", settings.audio.volumeUI); + create_channel(this, "master", settings.audio.volumeMaster); + create_channel(this, "regular", settings.audio.volumeRegular); + create_channel(this, "music", settings.audio.volumeMusic); + create_channel(this, "ambient", settings.audio.volumeAmbient); + create_channel(this, "ui", settings.audio.volumeUI); auto resdir = paths->getResources(); diff --git a/src/engine.h b/src/engine.h index f4ba4878..36d61806 100644 --- a/src/engine.h +++ b/src/engine.h @@ -11,6 +11,7 @@ #include "content/PacksManager.h" #include "files/engine_paths.h" #include "files/settings_io.h" +#include "util/ObjectsKeeper.hpp" #include #include @@ -38,7 +39,7 @@ public: initialize_error(const std::string& message) : std::runtime_error(message) {} }; -class Engine { +class Engine : public util::ObjectsKeeper { EngineSettings& settings; SettingsHandler settingsHandler; EnginePaths* paths; diff --git a/src/frontend/screens.cpp b/src/frontend/screens.cpp index bd6b9dc9..63877fb1 100644 --- a/src/frontend/screens.cpp +++ b/src/frontend/screens.cpp @@ -86,8 +86,6 @@ void MenuScreen::draw(float delta) { batch->flush(); } -static bool backlight; - LevelScreen::LevelScreen(Engine* engine, Level* level) : Screen(engine) { auto& settings = engine->getSettings(); auto assets = engine->getAssets(); @@ -100,8 +98,12 @@ LevelScreen::LevelScreen(Engine* engine, Level* level) : Screen(engine) { worldRenderer = std::make_unique(engine, frontend.get(), controller->getPlayer()); hud = std::make_unique(engine, frontend.get(), controller->getPlayer()); - - backlight = settings.graphics.backlight.get(); + keepAlive(settings.graphics.backlight.observe([=](bool flag) { + controller->getLevel()->chunks->saveAndClear(); + })); + keepAlive(settings.camera.fov.observe([=](double value) { + controller->getPlayer()->camera->setFov(glm::radians(value)); + })); animator = std::make_unique(); animator->addAnimations(assets->getAnimations()); @@ -163,14 +165,6 @@ void LevelScreen::update(float delta) { camera->up ); - // TODO: subscribe for setting change - EngineSettings& settings = engine->getSettings(); - controller->getPlayer()->camera->setFov(glm::radians(settings.camera.fov.get())); - if (settings.graphics.backlight.get() != backlight) { - controller->getLevel()->chunks->saveAndClear(); - backlight = settings.graphics.backlight.get(); - } - if (!hud->isPause()) { controller->getLevel()->getWorld()->updateTimers(delta); animator->update(delta); diff --git a/src/frontend/screens.h b/src/frontend/screens.h index fe0d5989..98be2ec7 100644 --- a/src/frontend/screens.h +++ b/src/frontend/screens.h @@ -3,6 +3,7 @@ #include #include "../settings.h" +#include "../util/ObjectsKeeper.hpp" class Assets; class Level; @@ -16,7 +17,7 @@ class LevelController; class TextureAnimator; /// @brief Screen is a mainloop state -class Screen { +class Screen : public util::ObjectsKeeper { protected: Engine* engine; std::unique_ptr batch; diff --git a/src/util/ObjectsKeeper.hpp b/src/util/ObjectsKeeper.hpp new file mode 100644 index 00000000..1791b341 --- /dev/null +++ b/src/util/ObjectsKeeper.hpp @@ -0,0 +1,19 @@ +#ifndef UTIL_OBJECTS_KEEPER_HPP_ +#define UTIL_OBJECTS_KEEPER_HPP_ + +#include +#include + +namespace util { + class ObjectsKeeper { + std::vector> ptrs; + public: + virtual ~ObjectsKeeper() {} + + virtual void keepAlive(std::shared_ptr ptr) { + ptrs.push_back(ptr); + } + }; +} + +#endif // UTIL_OBJECTS_KEEPER_HPP_