mirror of
https://github.com/MadeOfJelly/MushMachine.git
synced 2025-06-18 18:56:36 +02:00
initial import, >900commits predate this
This commit is contained in:
23
framework/screen_director/CMakeLists.txt
Normal file
23
framework/screen_director/CMakeLists.txt
Normal file
@ -0,0 +1,23 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(screen_director CXX)
|
||||
|
||||
add_library(screen_director
|
||||
src/mm/services/screen_director.hpp
|
||||
src/mm/services/screen_director.cpp
|
||||
)
|
||||
|
||||
target_include_directories(screen_director PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||
|
||||
target_link_libraries(screen_director
|
||||
engine
|
||||
logger
|
||||
entt
|
||||
)
|
||||
|
||||
message("screen_director_simple ALIAS TODO: remove!!")
|
||||
add_library(screen_director_simple ALIAS screen_director)
|
||||
|
||||
if (BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
107
framework/screen_director/src/mm/services/screen_director.cpp
Normal file
107
framework/screen_director/src/mm/services/screen_director.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
#include "./screen_director.hpp"
|
||||
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
#include <mm/logger.hpp>
|
||||
|
||||
namespace MM::Services {
|
||||
|
||||
bool ScreenDirector::enable(MM::Engine& engine) {
|
||||
if (!_update_handle.expired())
|
||||
return false;
|
||||
|
||||
{
|
||||
_update_handle = engine.addFixedUpdate([this](Engine& e) { this->update(e); });
|
||||
auto tmp_lock = _update_handle.lock();
|
||||
tmp_lock->priority = -100; // post everything ?
|
||||
tmp_lock->name = "ScreenDirector::update";
|
||||
}
|
||||
|
||||
|
||||
// start initial screen
|
||||
if (!queued_screen_id.empty()) {
|
||||
auto next_screen_id = queued_screen_id;
|
||||
auto& next_screen = screens[next_screen_id];
|
||||
|
||||
startScreen(engine, next_screen);
|
||||
|
||||
curr_screen_id = next_screen_id;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScreenDirector::disable(MM::Engine& engine) {
|
||||
engine.removeFixedUpdate(_update_handle);
|
||||
_update_handle.reset();
|
||||
}
|
||||
|
||||
void ScreenDirector::update(MM::Engine& engine) {
|
||||
if (curr_screen_id != queued_screen_id) {
|
||||
engine.addFixedDefer([this](MM::Engine& engine) {
|
||||
changeScreenTo(engine, queued_screen_id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenDirector::startScreen(MM::Engine& engine, Screen& screen) {
|
||||
ZoneScoped;
|
||||
for (auto service_id : screen.start_disable) {
|
||||
engine.disableService(service_id);
|
||||
}
|
||||
|
||||
for (auto service_id : screen.start_enable) {
|
||||
engine.enableService(service_id); // TODO: check return value
|
||||
}
|
||||
|
||||
for (auto [i_id, t_id] : screen.start_provide) {
|
||||
bool r = engine.provide(i_id, t_id); // TODO: check return value
|
||||
assert(r);
|
||||
}
|
||||
|
||||
screen.start_fn(engine);
|
||||
}
|
||||
|
||||
void ScreenDirector::endScreen(MM::Engine& engine, Screen& screen) {
|
||||
ZoneScoped;
|
||||
screen.end_fn(engine);
|
||||
|
||||
for (auto service_id : screen.end_disable) {
|
||||
engine.disableService(service_id);
|
||||
}
|
||||
|
||||
for (auto service_id : screen.end_enable) {
|
||||
engine.enableService(service_id); // TODO: check return value
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenDirector::changeScreenTo(MM::Engine& engine, const std::string id) {
|
||||
ZoneScoped;
|
||||
|
||||
if (screens.count(id) == 0) {
|
||||
SPDLOG_ERROR("tried to change to not defined screen '{}'", id);
|
||||
return;
|
||||
}
|
||||
|
||||
ZoneText(id.c_str(), id.size());
|
||||
|
||||
auto& curr_screen = screens[curr_screen_id];
|
||||
auto& next_screen = screens[id];
|
||||
|
||||
endScreen(engine, curr_screen);
|
||||
|
||||
startScreen(engine, next_screen);
|
||||
|
||||
curr_screen_id = id;
|
||||
}
|
||||
|
||||
void ScreenDirector::queueChangeScreenTo(const std::string& id) {
|
||||
ZoneScoped;
|
||||
ZoneText(id.c_str(), id.size());
|
||||
|
||||
// TODO: do some checks
|
||||
queued_screen_id = id;
|
||||
}
|
||||
|
||||
} // MM::Services
|
||||
|
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/engine.hpp>
|
||||
|
||||
//#include <vector> // in engine.hpp
|
||||
#include <map>
|
||||
|
||||
namespace MM::Services {
|
||||
|
||||
class ScreenDirector : public Service {
|
||||
public:
|
||||
const char* name(void) override { return "ScreenDirector"; }
|
||||
|
||||
// enable switches to queued_screen_index
|
||||
bool enable(MM::Engine&) override;
|
||||
void disable(MM::Engine&) override;
|
||||
|
||||
public:
|
||||
struct Screen {
|
||||
// lists of services relevant for this screen, disable and enable are called when its changed to
|
||||
std::vector<Engine::service_family_type> start_disable;
|
||||
std::vector<Engine::service_family_type> start_enable;
|
||||
|
||||
// register provider, when its changed to
|
||||
std::vector<
|
||||
std::pair<
|
||||
Engine::service_family_type, // I
|
||||
Engine::service_family_type // T
|
||||
>
|
||||
> start_provide;
|
||||
|
||||
// lists of services relevant for this screen, disable and enable are called when its changed from
|
||||
std::vector<Engine::service_family_type> end_disable;
|
||||
std::vector<Engine::service_family_type> end_enable;
|
||||
|
||||
// called when its changed to, after services disable and enable
|
||||
std::function<void(MM::Engine&)> start_fn = [](MM::Engine&){};
|
||||
|
||||
// called when the screen changed from
|
||||
std::function<void(MM::Engine&)> end_fn = [](MM::Engine&){};
|
||||
};
|
||||
|
||||
std::map<std::string, Screen> screens;
|
||||
|
||||
// TODO: private?
|
||||
std::string curr_screen_id = "";
|
||||
std::string queued_screen_id = "";
|
||||
|
||||
private:
|
||||
MM::Engine::FunctionDataHandle _update_handle;
|
||||
void update(MM::Engine& engine);
|
||||
|
||||
private:
|
||||
// INTERNAL helper, to reduce redundant code
|
||||
void startScreen(MM::Engine& engine, Screen& screen);
|
||||
void endScreen(MM::Engine& engine, Screen& screen);
|
||||
|
||||
public:
|
||||
void changeScreenTo(MM::Engine& engine, const std::string id);
|
||||
void queueChangeScreenTo(const std::string& id);
|
||||
};
|
||||
|
||||
} // MM::Services
|
||||
|
13
framework/screen_director/test/CMakeLists.txt
Normal file
13
framework/screen_director/test/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
add_executable(screen_director_test
|
||||
sd_test.cpp
|
||||
)
|
||||
|
||||
target_include_directories(screen_director_test PRIVATE ".")
|
||||
|
||||
target_link_libraries(screen_director_test
|
||||
screen_director
|
||||
gtest_main
|
||||
)
|
||||
|
||||
add_test(NAME screen_director_test COMMAND screen_director_test)
|
||||
|
270
framework/screen_director/test/sd_test.cpp
Normal file
270
framework/screen_director/test/sd_test.cpp
Normal file
@ -0,0 +1,270 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <mm/engine.hpp>
|
||||
#include <mm/services/screen_director.hpp>
|
||||
|
||||
class TestService1 : public MM::Services::Service {
|
||||
public:
|
||||
const char* name(void) override { return "TestService1"; }
|
||||
|
||||
bool enable(MM::Engine&) override { return true; }
|
||||
void disable(MM::Engine&) override {}
|
||||
};
|
||||
|
||||
class TestService2 : public MM::Services::Service {
|
||||
public:
|
||||
const char* name(void) override { return "TestService2"; }
|
||||
|
||||
bool enable(MM::Engine&) override { return true; }
|
||||
void disable(MM::Engine&) override {}
|
||||
};
|
||||
|
||||
class TestServiceInterface : public MM::Services::Service {
|
||||
public:
|
||||
const char* name(void) override { return "TestServiceInterface"; }
|
||||
|
||||
bool enable(MM::Engine&) override { return true; }
|
||||
void disable(MM::Engine&) override {}
|
||||
|
||||
public:
|
||||
virtual int test_method(void) = 0;
|
||||
};
|
||||
|
||||
class TestServiceInterfaceImpl1 : public TestServiceInterface {
|
||||
public:
|
||||
const char* name(void) override { return "TestServiceInterfaceImpl1"; }
|
||||
|
||||
bool enable(MM::Engine&) override { return true; }
|
||||
void disable(MM::Engine&) override {}
|
||||
|
||||
public:
|
||||
int test_method(void) override {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
class TestServiceInterfaceImpl2 : public TestServiceInterface {
|
||||
public:
|
||||
const char* name(void) override { return "TestServiceInterfaceImpl2"; }
|
||||
|
||||
bool enable(MM::Engine&) override { return true; }
|
||||
void disable(MM::Engine&) override {}
|
||||
|
||||
public:
|
||||
int test_method(void) override {
|
||||
return 2;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(SceneDirectorSimple, offline) {
|
||||
MM::Engine engine;
|
||||
|
||||
engine.addService<TestService1>();
|
||||
engine.addService<TestService2>();
|
||||
|
||||
auto& sd = engine.addService<MM::Services::ScreenDirector>();
|
||||
|
||||
// setup scene director
|
||||
ASSERT_EQ(sd.screens.size(), 0);
|
||||
|
||||
// id 0 - start point, not required
|
||||
{
|
||||
auto& screen_0 = sd.screens["screen_0"];
|
||||
ASSERT_TRUE(screen_0.start_disable.empty()); // none
|
||||
ASSERT_TRUE(screen_0.start_enable.empty()); // none
|
||||
ASSERT_TRUE(screen_0.end_disable.empty()); // none
|
||||
ASSERT_TRUE(screen_0.end_enable.empty()); // none
|
||||
}
|
||||
|
||||
// id 1
|
||||
{
|
||||
auto& screen_1 = sd.screens["screen_1"];
|
||||
screen_1.start_disable.push_back(engine.type<TestService2>());
|
||||
screen_1.start_enable.push_back(engine.type<TestService1>());
|
||||
screen_1.start_fn = [](auto&) {
|
||||
std::cout << "now in screen_1\n";
|
||||
};
|
||||
screen_1.end_fn = [](auto&) {
|
||||
std::cout << "exiting screen_1\n";
|
||||
};
|
||||
}
|
||||
|
||||
// id 2
|
||||
{
|
||||
auto& screen_2 = sd.screens["screen_2"];
|
||||
screen_2.start_disable.push_back(engine.type<TestService1>());
|
||||
screen_2.start_enable.push_back(engine.type<TestService2>());
|
||||
screen_2.start_fn = [](auto&) {
|
||||
std::cout << "now in screen_2\n";
|
||||
};
|
||||
screen_2.end_fn = [](auto&) {
|
||||
std::cout << "exiting screen_2\n";
|
||||
};
|
||||
}
|
||||
|
||||
sd.queued_screen_id = "screen_0"; // set to screen_0
|
||||
|
||||
ASSERT_TRUE(engine.enableService<MM::Services::ScreenDirector>());
|
||||
|
||||
sd.changeScreenTo(engine, "screen_1"); ASSERT_EQ(sd.curr_screen_id, "screen_1");
|
||||
sd.changeScreenTo(engine, "screen_2"); ASSERT_EQ(sd.curr_screen_id, "screen_2");
|
||||
sd.changeScreenTo(engine, "screen_1"); ASSERT_EQ(sd.curr_screen_id, "screen_1");
|
||||
sd.changeScreenTo(engine, "screen_0"); ASSERT_EQ(sd.curr_screen_id, "screen_0");
|
||||
sd.changeScreenTo(engine, "somthing which does not exits"); ASSERT_EQ(sd.curr_screen_id, "screen_0"); // does not exist, does nothing
|
||||
}
|
||||
|
||||
TEST(SceneDirectorSimple, online) {
|
||||
MM::Engine engine;
|
||||
|
||||
engine.addService<TestService1>();
|
||||
engine.addService<TestService2>();
|
||||
|
||||
auto& sd = engine.addService<MM::Services::ScreenDirector>();
|
||||
|
||||
// setup scene director
|
||||
ASSERT_EQ(sd.screens.size(), 0);
|
||||
|
||||
// id 0 - start point
|
||||
{
|
||||
auto& screen_0 = sd.screens["screen_0"];
|
||||
//screen_0.start_disable.empty(); // none
|
||||
//screen_0.start_enable.empty(); // none
|
||||
ASSERT_TRUE(screen_0.start_disable.empty()); // none
|
||||
ASSERT_TRUE(screen_0.start_enable.empty()); // none
|
||||
ASSERT_TRUE(screen_0.end_disable.empty()); // none
|
||||
ASSERT_TRUE(screen_0.end_enable.empty()); // none
|
||||
}
|
||||
|
||||
// id 1
|
||||
{
|
||||
auto& screen_1 = sd.screens["screen_1"];
|
||||
screen_1.start_disable.push_back(engine.type<TestService2>());
|
||||
screen_1.start_enable.push_back(engine.type<TestService1>());
|
||||
screen_1.start_fn = [](MM::Engine& engine) {
|
||||
std::cout << "now in screen_1\n";
|
||||
|
||||
// and queue next screen immediately (for the purpose of this test)
|
||||
engine.tryService<MM::Services::ScreenDirector>()->queueChangeScreenTo("screen_2");
|
||||
};
|
||||
screen_1.end_fn = [](auto&) {
|
||||
std::cout << "exiting screen_1\n";
|
||||
};
|
||||
}
|
||||
|
||||
// id 2
|
||||
{
|
||||
auto& screen_2 = sd.screens["screen_2"];
|
||||
screen_2.start_disable.push_back(engine.type<TestService1>());
|
||||
screen_2.start_enable.push_back(engine.type<TestService2>());
|
||||
screen_2.start_fn = [](MM::Engine& engine) {
|
||||
std::cout << "now in screen_2\n";
|
||||
|
||||
// and queue next screen immediately (for the purpose of this test)
|
||||
engine.tryService<MM::Services::ScreenDirector>()->queueChangeScreenTo("screen_end");
|
||||
};
|
||||
screen_2.end_fn = [](auto&) {
|
||||
std::cout << "exiting screen_2\n";
|
||||
};
|
||||
}
|
||||
|
||||
// id end, quits the engine
|
||||
{
|
||||
auto& screen_end = sd.screens["screen_end"];
|
||||
screen_end.start_fn = [](MM::Engine& engine) {
|
||||
engine.stop();
|
||||
};
|
||||
}
|
||||
|
||||
sd.queued_screen_id = "screen_0"; // init
|
||||
|
||||
ASSERT_TRUE(engine.enableService<MM::Services::ScreenDirector>());
|
||||
|
||||
// TODO: remove screen 0
|
||||
sd.queueChangeScreenTo("screen_1"); // start "chain" (bc screen_0 does nothing), this is the same as an assigment
|
||||
|
||||
engine.run();
|
||||
}
|
||||
|
||||
TEST(SceneDirectorSimple, offline_provide) {
|
||||
MM::Engine engine;
|
||||
|
||||
engine.addService<TestServiceInterfaceImpl1>();
|
||||
engine.addService<TestServiceInterfaceImpl2>();
|
||||
|
||||
auto& sd = engine.addService<MM::Services::ScreenDirector>();
|
||||
|
||||
// setup scene director
|
||||
ASSERT_EQ(sd.screens.size(), 0);
|
||||
|
||||
// id 0 - start point, not required
|
||||
{
|
||||
auto& screen_0 = sd.screens["screen_0"];
|
||||
ASSERT_TRUE(screen_0.start_disable.empty()); // none
|
||||
ASSERT_TRUE(screen_0.start_enable.empty()); // none
|
||||
ASSERT_TRUE(screen_0.end_disable.empty()); // none
|
||||
ASSERT_TRUE(screen_0.end_enable.empty()); // none
|
||||
}
|
||||
|
||||
// id 1
|
||||
{
|
||||
auto& screen_1 = sd.screens["screen_1"];
|
||||
screen_1.start_disable.push_back(engine.type<TestServiceInterface>()); // if already provided for
|
||||
screen_1.start_enable.push_back(engine.type<TestServiceInterfaceImpl1>());
|
||||
screen_1.start_provide.emplace_back(
|
||||
engine.type<TestServiceInterface>(),
|
||||
engine.type<TestServiceInterfaceImpl1>()
|
||||
);
|
||||
screen_1.start_fn = [](auto&) {
|
||||
std::cout << "now in screen_1\n";
|
||||
std::cout << "impl1 is provided\n";
|
||||
};
|
||||
screen_1.end_fn = [](auto&) {
|
||||
std::cout << "exiting screen_1\n";
|
||||
};
|
||||
}
|
||||
|
||||
// id 2
|
||||
{
|
||||
auto& screen_2 = sd.screens["screen_2"];
|
||||
screen_2.start_disable.push_back(engine.type<TestServiceInterface>()); // if already provided for
|
||||
screen_2.start_enable.push_back(engine.type<TestServiceInterfaceImpl2>());
|
||||
screen_2.start_provide.emplace_back(
|
||||
engine.type<TestServiceInterface>(),
|
||||
engine.type<TestServiceInterfaceImpl2>()
|
||||
);
|
||||
screen_2.start_fn = [](auto&) {
|
||||
std::cout << "now in screen_2\n";
|
||||
std::cout << "impl2 is provided\n";
|
||||
};
|
||||
screen_2.end_fn = [](auto&) {
|
||||
std::cout << "exiting screen_2\n";
|
||||
};
|
||||
}
|
||||
|
||||
sd.queued_screen_id = "screen_0"; // set to screen_0
|
||||
|
||||
ASSERT_TRUE(engine.enableService<MM::Services::ScreenDirector>());
|
||||
// now in screen_0
|
||||
|
||||
|
||||
ASSERT_NE(engine.tryService<TestServiceInterfaceImpl1>(), nullptr);
|
||||
ASSERT_NE(engine.tryService<TestServiceInterfaceImpl2>(), nullptr);
|
||||
|
||||
|
||||
sd.changeScreenTo(engine, "screen_1"); ASSERT_EQ(sd.curr_screen_id, "screen_1");
|
||||
ASSERT_NE(engine.tryService<TestServiceInterface>(), nullptr);
|
||||
ASSERT_EQ(engine.tryService<TestServiceInterface>()->test_method(), 1);
|
||||
|
||||
sd.changeScreenTo(engine, "screen_2"); ASSERT_EQ(sd.curr_screen_id, "screen_2");
|
||||
ASSERT_NE(engine.tryService<TestServiceInterface>(), nullptr);
|
||||
ASSERT_EQ(engine.tryService<TestServiceInterface>()->test_method(), 2);
|
||||
|
||||
sd.changeScreenTo(engine, "screen_1"); ASSERT_EQ(sd.curr_screen_id, "screen_1");
|
||||
ASSERT_NE(engine.tryService<TestServiceInterface>(), nullptr);
|
||||
ASSERT_EQ(engine.tryService<TestServiceInterface>()->test_method(), 1);
|
||||
|
||||
sd.changeScreenTo(engine, "screen_0"); ASSERT_EQ(sd.curr_screen_id, "screen_0");
|
||||
|
||||
sd.changeScreenTo(engine, "somthing which does not exits"); ASSERT_EQ(sd.curr_screen_id, "screen_0"); // does not exist, does nothing
|
||||
}
|
||||
|
Reference in New Issue
Block a user