settings observers lifecycle

This commit is contained in:
MihailRis 2024-04-22 19:10:36 +03:00
parent 201209887f
commit 5b82b18c6f
6 changed files with 75 additions and 43 deletions

View File

@ -4,6 +4,7 @@
#include <limits>
#include <string>
#include <vector>
#include <unordered_map>
#include "../typedefs.h"
#include "../delegates.h"
@ -30,13 +31,35 @@ public:
virtual std::string toString() const = 0;
};
using observer_handler = std::shared_ptr<int>;
template<class T>
class Observers {
int nextid = 1;
std::unordered_map<int, consumer<T>> observers;
public:
observer_handler observe(consumer<T> callback) {
const int id = nextid++;
observers.emplace(id, callback);
return std::shared_ptr<int>(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<consumer<number_t>> consumers;
Observers<number_t> 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<number_t> callback) {
consumers.push_back(callback);
observer_handler observe(consumer<number_t> 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<consumer<integer_t>> consumers;
Observers<integer_t> 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<integer_t> callback) {
consumers.push_back(callback);
observer_handler observe(consumer<integer_t> 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<consumer<bool>> consumers;
Observers<bool> 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<bool> callback) {
consumers.push_back(callback);
observer_handler observe(consumer<bool> callback) {
return observers.observe(callback);
}
virtual void resetToDefault() override {
value = initial;
set(initial);
}
virtual std::string toString() const override;

View File

@ -47,13 +47,13 @@ void addWorldGenerators() {
WorldGenerators::addGenerator<FlatWorldGenerator>("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();

View File

@ -11,6 +11,7 @@
#include "content/PacksManager.h"
#include "files/engine_paths.h"
#include "files/settings_io.h"
#include "util/ObjectsKeeper.hpp"
#include <filesystem>
#include <memory>
@ -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;

View File

@ -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<WorldRenderer>(engine, frontend.get(), controller->getPlayer());
hud = std::make_unique<Hud>(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<TextureAnimator>();
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);

View File

@ -3,6 +3,7 @@
#include <memory>
#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<Batch2D> batch;

View File

@ -0,0 +1,19 @@
#ifndef UTIL_OBJECTS_KEEPER_HPP_
#define UTIL_OBJECTS_KEEPER_HPP_
#include <vector>
#include <memory>
namespace util {
class ObjectsKeeper {
std::vector<std::shared_ptr<void>> ptrs;
public:
virtual ~ObjectsKeeper() {}
virtual void keepAlive(std::shared_ptr<void> ptr) {
ptrs.push_back(ptr);
}
};
}
#endif // UTIL_OBJECTS_KEEPER_HPP_