mirror of
https://github.com/MadeOfJelly/MushMachine.git
synced 2025-06-19 19:26:36 +02:00
initial import, >900commits predate this
This commit is contained in:
34
framework/engine/CMakeLists.txt
Normal file
34
framework/engine/CMakeLists.txt
Normal file
@ -0,0 +1,34 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(engine CXX)
|
||||
|
||||
add_library(engine
|
||||
src/mm/engine_fwd.hpp
|
||||
src/mm/engine.hpp
|
||||
src/mm/engine.cpp
|
||||
|
||||
src/mm/services/service.hpp
|
||||
|
||||
src/mm/services/default_service.cpp
|
||||
src/mm/services/default_service.hpp
|
||||
|
||||
src/mm/services/scene_service_interface.hpp
|
||||
src/mm/services/scene_service_interface.cpp
|
||||
|
||||
src/mm/services/net_channeled_interface.hpp
|
||||
)
|
||||
|
||||
# find . -type f -exec sed -i 's/simple_scene\/services\/simple_scene_ss.hpp/services\/scene_service_interface.hpp/g' {} \;
|
||||
|
||||
target_include_directories(engine PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||
|
||||
target_link_libraries(engine
|
||||
tracy_client
|
||||
logger
|
||||
entt
|
||||
glm
|
||||
)
|
||||
|
||||
if (BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
263
framework/engine/src/mm/engine.cpp
Normal file
263
framework/engine/src/mm/engine.cpp
Normal file
@ -0,0 +1,263 @@
|
||||
#include "./engine.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
|
||||
#include <memory>
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
#include <mm/logger.hpp>
|
||||
#define LOG_CRIT(...) __LOG_CRIT( "Engine", __VA_ARGS__)
|
||||
#define LOG_ERROR(...) __LOG_ERROR("Engine", __VA_ARGS__)
|
||||
#define LOG_WARN(...) __LOG_WARN( "Engine", __VA_ARGS__)
|
||||
#define LOG_INFO(...) __LOG_INFO( "Engine", __VA_ARGS__)
|
||||
#define LOG_DEBUG(...) __LOG_DEBUG("Engine", __VA_ARGS__)
|
||||
#define LOG_TRACE(...) __LOG_TRACE("Engine", __VA_ARGS__)
|
||||
|
||||
namespace MM {
|
||||
|
||||
Engine::FunctionDataHandle Engine::addUpdate(std::function<void(Engine&)> function) {
|
||||
if (!function) {
|
||||
LOG_ERROR("could not add Update, empty function!");
|
||||
return {};
|
||||
}
|
||||
|
||||
FunctionDataHandle r = _update_functions.emplace_back(std::make_shared<FunctionDataType>(function));
|
||||
_update_functions_modified = true;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
Engine::FunctionDataHandle Engine::addFixedUpdate(std::function<void(Engine&)> function) {
|
||||
if (!function) {
|
||||
LOG_ERROR("could not add fixedUpdate, empty function!");
|
||||
return {};
|
||||
}
|
||||
|
||||
FunctionDataHandle r = _fixed_update_functions.emplace_back(std::make_shared<FunctionDataType>(function));
|
||||
_fixed_update_functions_modified = true;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void Engine::removeUpdate(FunctionDataHandle handle) {
|
||||
if (handle.expired()) {
|
||||
LOG_ERROR("could not remove Update, invalid handle!");
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = handle.lock();
|
||||
auto it = std::find(_update_functions.begin(), _update_functions.end(), lock);
|
||||
if (it != _update_functions.end()) {
|
||||
_update_functions.erase(it);
|
||||
} else {
|
||||
LOG_ERROR("could not remove Update, unknown handle!");
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::removeFixedUpdate(FunctionDataHandle handle) {
|
||||
if (handle.expired()) {
|
||||
LOG_ERROR("could not remove fixedUpdate, invalid handle!");
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = handle.lock();
|
||||
auto it = std::find(_fixed_update_functions.begin(), _fixed_update_functions.end(), lock);
|
||||
if (it != _fixed_update_functions.end()) {
|
||||
_fixed_update_functions.erase(it);
|
||||
} else {
|
||||
LOG_ERROR("could not remove fixedUpdate, unknown handle!");
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::addFixedDefer(std::function<void(Engine&)> function) {
|
||||
_fixed_defered.emplace_back(function);
|
||||
}
|
||||
|
||||
void Engine::traverseUpdateFunctions(std::vector<std::shared_ptr<FunctionDataType>>& list) {
|
||||
for (auto& entry : list) {
|
||||
entry->f(*this);
|
||||
}
|
||||
}
|
||||
|
||||
Engine::Engine(float f_delta_time) : _fixed_delta_time(f_delta_time) {
|
||||
if (!MM::Logger::initialized) {
|
||||
MM::Logger::init();
|
||||
}
|
||||
|
||||
MM::Logger::initSectionLogger("Engine");
|
||||
}
|
||||
|
||||
Engine::~Engine(void) {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void Engine::cleanup(void) {
|
||||
// disable all enabled services
|
||||
// in reverse order
|
||||
for (auto s_it = _service_enable_order.rbegin(); s_it != _service_enable_order.rend(); s_it++) {
|
||||
auto& s_e = _services[*s_it];
|
||||
if (s_e.get()->first) {
|
||||
if (auto* ss = s_e.get()->second.get(); ss != nullptr) {
|
||||
ss->disable(*this);
|
||||
LOG_INFO("- disabled Service '{}'", ss->name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_service_enable_order.clear();
|
||||
|
||||
_update_functions.clear();
|
||||
_fixed_update_functions.clear();
|
||||
|
||||
spdlog::get("Engine")->flush();
|
||||
}
|
||||
|
||||
void Engine::update(void) {
|
||||
FrameMarkStart("update")
|
||||
if (_update_functions_modified) {
|
||||
ZoneScopedN("MM::Engine::update::sort_update_functions")
|
||||
std::sort(_update_functions.begin(), _update_functions.end(), [](const auto& a, const auto& b) { return a->priority > b->priority; });
|
||||
_update_functions_modified = false;
|
||||
}
|
||||
|
||||
{
|
||||
ZoneScopedN("MM::Engine::update::traverseUpdateFunctions")
|
||||
traverseUpdateFunctions(_update_functions);
|
||||
}
|
||||
|
||||
FrameMarkEnd("update")
|
||||
}
|
||||
|
||||
void Engine::fixedUpdate(void) {
|
||||
FrameMarkStart("fixedUpdate")
|
||||
if (_fixed_update_functions_modified) {
|
||||
ZoneScopedN("MM::Engine::fixedUpdate::sort_update_functions")
|
||||
|
||||
std::sort(_fixed_update_functions.begin(), _fixed_update_functions.end(), [](const auto& a, const auto& b) { return a->priority > b->priority; });
|
||||
_fixed_update_functions_modified = false;
|
||||
}
|
||||
|
||||
{
|
||||
ZoneScopedN("MM::Engine::fixedUpdate::traverseUpdateFunctions")
|
||||
traverseUpdateFunctions(_fixed_update_functions);
|
||||
}
|
||||
|
||||
if (!_fixed_defered.empty()) {
|
||||
ZoneScopedN("MM::Engine::fixedUpdate::defered")
|
||||
for (auto& fn : _fixed_defered) {
|
||||
fn(*this);
|
||||
}
|
||||
|
||||
_fixed_defered.clear();
|
||||
}
|
||||
|
||||
FrameMarkEnd("fixedUpdate")
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
|
||||
static void emscripten_update(void* arg) {
|
||||
using clock = std::chrono::high_resolution_clock;
|
||||
static long long int accumulator = 0;
|
||||
static auto now = clock::now();
|
||||
|
||||
auto* e = (MM::Engine*)arg;
|
||||
|
||||
auto newNow = clock::now();
|
||||
auto deltaTime = std::chrono::duration_cast<std::chrono::nanoseconds>(newNow - now);
|
||||
now = newNow;
|
||||
accumulator += deltaTime.count();
|
||||
auto dt = e->getFixedDeltaTime() * 1'000'000'000.0f;
|
||||
while (accumulator >= dt) {
|
||||
accumulator -= dt;
|
||||
e->fixedUpdate();
|
||||
}
|
||||
|
||||
e->update();
|
||||
}
|
||||
#endif
|
||||
|
||||
void Engine::run(void) {
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_set_main_loop_arg(emscripten_update, this, 0, 1);
|
||||
#else
|
||||
using clock = std::chrono::high_resolution_clock;
|
||||
|
||||
_is_running = true;
|
||||
long long int accumulator = 0;
|
||||
auto now = clock::now();
|
||||
while (_is_running) {
|
||||
auto newNow = clock::now();
|
||||
auto deltaTime = std::chrono::duration_cast<std::chrono::nanoseconds>(newNow - now);
|
||||
now = newNow;
|
||||
accumulator += deltaTime.count();
|
||||
auto dt = _fixed_delta_time * 1'000'000'000.0f;
|
||||
|
||||
|
||||
size_t continuous_counter = 0;
|
||||
while (accumulator >= dt) {
|
||||
continuous_counter++;
|
||||
accumulator -= static_cast<long long int>(dt);
|
||||
fixedUpdate();
|
||||
}
|
||||
|
||||
if (continuous_counter > 2) {
|
||||
LOG_WARN("had {} contiguous fixedUpdates!", std::to_string(continuous_counter));
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Engine::stop(void) {
|
||||
_is_running = false;
|
||||
}
|
||||
|
||||
bool Engine::enableService(service_family::family_type s_t) {
|
||||
if (_services.count(s_t)) {
|
||||
auto* ss_entry = _services[s_t].get();
|
||||
if (ss_entry->first) {
|
||||
return false; // already enabled
|
||||
}
|
||||
|
||||
_service_enable_order.emplace_back(s_t); // TODO: make sure
|
||||
return ss_entry->first = ss_entry->second.get()->enable(*this);
|
||||
}
|
||||
|
||||
// not found
|
||||
assert(false && "first add Service");
|
||||
return false;
|
||||
}
|
||||
|
||||
void Engine::disableService(service_family::family_type s_t) {
|
||||
if (_services.count(s_t)) {
|
||||
auto* s_entry = _services[s_t].get();
|
||||
if (s_entry->first) {
|
||||
s_entry->first = false;
|
||||
s_entry->second.get()->disable(*this);
|
||||
//_service_enable_order.emplace_back(service_family::type<T>);
|
||||
auto it = std::find(_service_enable_order.begin(), _service_enable_order.end(), s_t);
|
||||
if (it != _service_enable_order.end()) {
|
||||
_service_enable_order.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Engine::provide(service_family::family_type I, service_family::family_type T) {
|
||||
if (!_services.count(T)) {
|
||||
// TODO: log error
|
||||
return false;
|
||||
}
|
||||
|
||||
_services[I] = _services[T];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // MM
|
||||
|
182
framework/engine/src/mm/engine.hpp
Normal file
182
framework/engine/src/mm/engine.hpp
Normal file
@ -0,0 +1,182 @@
|
||||
#pragma once
|
||||
|
||||
#include <entt/core/family.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include <mm/services/service.hpp>
|
||||
|
||||
namespace MM {
|
||||
|
||||
class Engine {
|
||||
private:
|
||||
using service_family = entt::family<struct internal_service_family>;
|
||||
|
||||
public:
|
||||
using service_family_type = service_family::family_type;
|
||||
|
||||
// the services "internal" interface
|
||||
//private:
|
||||
public:
|
||||
struct FunctionPriorityDataStructure {
|
||||
std::function<void(Engine&)> f;
|
||||
int16_t priority = 0; // 0 is equal to scene update, the higher the prio the earlier
|
||||
std::string name;
|
||||
|
||||
explicit FunctionPriorityDataStructure(std::function<void(Engine&)> fun) : f(fun) {}
|
||||
FunctionPriorityDataStructure(const FunctionPriorityDataStructure& rhs)
|
||||
: f(rhs.f), priority(rhs.priority), name(rhs.name) {}
|
||||
};
|
||||
|
||||
using FunctionDataType = FunctionPriorityDataStructure;
|
||||
//using FunctionDataHandle = FunctionDataType*; // important: its a pointer
|
||||
using FunctionDataHandle = std::weak_ptr<FunctionDataType>; // important: its a pointer
|
||||
|
||||
// return nullptr on error
|
||||
[[nodiscard]] FunctionDataHandle addUpdate(std::function<void(Engine&)> function);
|
||||
[[nodiscard]] FunctionDataHandle addFixedUpdate(std::function<void(Engine&)> function);
|
||||
|
||||
void removeUpdate(FunctionDataHandle handle);
|
||||
void removeFixedUpdate(FunctionDataHandle handle);
|
||||
|
||||
// dont use, if you are not using it to modify the engine.
|
||||
// you usualy dont need to use this, if you think you need to use this, you probably dont.
|
||||
void addFixedDefer(std::function<void(Engine&)> function);
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<FunctionDataType>> _update_functions;
|
||||
bool _update_functions_modified;
|
||||
|
||||
std::vector<std::shared_ptr<FunctionDataType>> _fixed_update_functions;
|
||||
bool _fixed_update_functions_modified;
|
||||
|
||||
std::vector<std::function<void(Engine&)>> _fixed_defered;
|
||||
|
||||
private:
|
||||
void traverseUpdateFunctions(std::vector<std::shared_ptr<FunctionDataType>>& list); // traverses an update list, gets called by update()/fixedUpdate()
|
||||
|
||||
private:
|
||||
volatile bool _is_running = false;
|
||||
const float _fixed_delta_time;
|
||||
|
||||
public:
|
||||
explicit Engine(float f_delta_time = 1.f/60.f);
|
||||
~Engine(void);
|
||||
|
||||
// called from destructor or explicitly
|
||||
void cleanup(void);
|
||||
|
||||
[[nodiscard]] float getFixedDeltaTime(void) const { return _fixed_delta_time; };
|
||||
|
||||
void update(void);
|
||||
void fixedUpdate(void);
|
||||
|
||||
void run(void); // calls update()/fixedUpdate() until stopped
|
||||
void stop(void);
|
||||
|
||||
private:
|
||||
std::vector<service_family::family_type> _service_add_order; // ?
|
||||
std::vector<service_family::family_type> _service_enable_order; // ?
|
||||
|
||||
//std::unordered_map<service_family::family_type, std::pair<bool, std::unique_ptr<Service>>> _services;
|
||||
std::unordered_map<
|
||||
service_family::family_type,
|
||||
std::shared_ptr<std::pair<
|
||||
bool,
|
||||
std::unique_ptr<Services::Service>
|
||||
>>
|
||||
> _services;
|
||||
|
||||
// maps I to T
|
||||
//std::unordered_map<service_family::family_type, service_family::family_type> _implementation_provider;
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
constexpr auto type(void) {
|
||||
return service_family::type<T>;
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
T& addService(Args&& ... args) {
|
||||
assert(!tryService<T>());
|
||||
|
||||
auto& ss_entry = _services[service_family::type<T>] =
|
||||
std::make_shared<std::pair<bool, std::unique_ptr<Services::Service>>>(
|
||||
std::make_pair<bool, std::unique_ptr<Services::Service>>(
|
||||
false,
|
||||
std::make_unique<T>(std::forward<Args>(args)...)
|
||||
)
|
||||
);
|
||||
|
||||
_service_add_order.emplace_back(service_family::type<T>);
|
||||
|
||||
return (T&)*ss_entry.get()->second.get();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] T* tryService(void) const {
|
||||
if (_services.count(service_family::type<T>)) {
|
||||
return static_cast<T*>(_services.at(service_family::type<T>).get()->second.get());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[deprecated("use tryService() instead")]]
|
||||
[[nodiscard]] T* tryGetService(void) const {
|
||||
return tryService<T>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] T& getService(void) const {
|
||||
T* tmp = tryService<T>();
|
||||
assert(tmp);
|
||||
return *tmp;
|
||||
}
|
||||
|
||||
bool enableService(service_family::family_type s_t);
|
||||
void disableService(service_family::family_type s_t);
|
||||
|
||||
template<typename T>
|
||||
bool enableService(void) {
|
||||
return enableService(service_family::type<T>);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void disableService(void) {
|
||||
disableService(service_family::type<T>);
|
||||
}
|
||||
|
||||
// provide T as I implementation
|
||||
// T needs to be an added Service
|
||||
bool provide(service_family::family_type I, service_family::family_type T);
|
||||
|
||||
// provide T as I implementation
|
||||
// T needs to be an added Service
|
||||
template<typename I, typename T>
|
||||
bool provide(void) {
|
||||
static_assert(std::is_base_of_v<I, T>, "T is not derived from I!");
|
||||
static_assert(!std::is_same_v<I, T>, "I and T are the same, makes no sense!");
|
||||
|
||||
return provide(service_family::type<I>, service_family::type<T>);
|
||||
}
|
||||
|
||||
// TODO: reimplement???
|
||||
//template<typename I>
|
||||
//void removeProvider(void) {
|
||||
//if (auto it = _implementation_provider.find(service_family::type<I>); it != _implementation_provider.end()) {
|
||||
//_implementation_provider.erase(it);
|
||||
//}
|
||||
//}
|
||||
};
|
||||
|
||||
} // MM
|
||||
|
12
framework/engine/src/mm/engine_fwd.hpp
Normal file
12
framework/engine/src/mm/engine_fwd.hpp
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
// this is a forwarding header
|
||||
|
||||
#include <entt/fwd.hpp>
|
||||
|
||||
namespace MM {
|
||||
class Engine;
|
||||
using Entity = entt::entity;
|
||||
using Scene = entt::basic_registry<Entity>;
|
||||
}
|
||||
|
52
framework/engine/src/mm/services/default_service.cpp
Normal file
52
framework/engine/src/mm/services/default_service.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include "./default_service.hpp"
|
||||
|
||||
namespace MM::Services {
|
||||
|
||||
// TODO: error handling
|
||||
bool DefaultService::enable(Engine& engine) {
|
||||
{
|
||||
_func_handles[0] = engine.addUpdate([this](Engine& e) { this->preSceneUpdate(e); });
|
||||
auto tmp_lock = _func_handles[0].lock();
|
||||
tmp_lock->priority = 1;
|
||||
tmp_lock->name = "DefaultService::preSceneUpdate";
|
||||
}
|
||||
|
||||
{
|
||||
_func_handles[1] = engine.addUpdate([this](Engine& e) { this->postSceneUpdate(e); });
|
||||
auto tmp_lock = _func_handles[1].lock();
|
||||
tmp_lock->priority = -1;
|
||||
tmp_lock->name = "DefaultService::postSceneUpdate";
|
||||
}
|
||||
|
||||
{
|
||||
_func_handles[2] = engine.addFixedUpdate([this](Engine& e) { this->preSceneFixedUpdate(e); });
|
||||
auto tmp_lock = _func_handles[2].lock();
|
||||
tmp_lock->priority = 1;
|
||||
tmp_lock->name = "DefaultService::preSceneFixedUpdate";
|
||||
}
|
||||
|
||||
{
|
||||
_func_handles[3] = engine.addFixedUpdate([this](Engine& e) { this->postSceneFixedUpdate(e); });
|
||||
auto tmp_lock = _func_handles[3].lock();
|
||||
tmp_lock->priority = -1;
|
||||
tmp_lock->name = "DefaultService::postSceneFixedUpdate";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DefaultService::disable(Engine& engine) {
|
||||
engine.removeUpdate(_func_handles[0]);
|
||||
engine.removeUpdate(_func_handles[1]);
|
||||
|
||||
engine.removeFixedUpdate(_func_handles[2]);
|
||||
engine.removeFixedUpdate(_func_handles[3]);
|
||||
|
||||
_func_handles[0].reset();
|
||||
_func_handles[1].reset();
|
||||
_func_handles[2].reset();
|
||||
_func_handles[3].reset();
|
||||
}
|
||||
|
||||
} // MM::Services
|
||||
|
26
framework/engine/src/mm/services/default_service.hpp
Normal file
26
framework/engine/src/mm/services/default_service.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "./service.hpp"
|
||||
#include <mm/engine.hpp>
|
||||
|
||||
namespace MM::Services {
|
||||
|
||||
class DefaultService : public Service {
|
||||
private:
|
||||
Engine::FunctionDataHandle _func_handles[4];
|
||||
|
||||
public:
|
||||
virtual const char* name(void) override { return "DefaultService"; }
|
||||
|
||||
virtual bool enable(Engine& engine) override;
|
||||
virtual void disable(Engine& engine) override;
|
||||
|
||||
virtual void preSceneUpdate(Engine&) {}
|
||||
virtual void postSceneUpdate(Engine&) {}
|
||||
virtual void preSceneFixedUpdate(Engine&) {}
|
||||
virtual void postSceneFixedUpdate(Engine&) {}
|
||||
};
|
||||
|
||||
} //MM::Services
|
||||
|
||||
|
77
framework/engine/src/mm/services/net_channeled_interface.hpp
Normal file
77
framework/engine/src/mm/services/net_channeled_interface.hpp
Normal file
@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/engine.hpp>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
namespace MM::Services {
|
||||
|
||||
class NetChanneledInterface : public Service {
|
||||
public:
|
||||
using channel_id = uint8_t;
|
||||
enum class channel_type {
|
||||
LOSSY,
|
||||
LOSSLESS
|
||||
};
|
||||
using peer_id = uint64_t; // might be truncated by backends
|
||||
|
||||
using packet_type = uint16_t; // can be aliased to an enum by the user
|
||||
|
||||
protected:
|
||||
std::set<peer_id> _peer_list;
|
||||
|
||||
public: // support querrys
|
||||
|
||||
// returns the number (highest number??) maximum channels supported by backend
|
||||
virtual channel_id getMaxChannels(void) = 0;
|
||||
|
||||
// returns wether the channel type is supported
|
||||
virtual bool getSupportedChannelType(channel_type type) = 0;
|
||||
|
||||
virtual size_t getMaxPacketSize(void) = 0;
|
||||
|
||||
// TODO: add set channel type utils
|
||||
|
||||
public:
|
||||
|
||||
// ok , we manage the peer list now
|
||||
virtual bool addPeer(peer_id peer) { return _peer_list.emplace(peer).second; }
|
||||
virtual bool removePeer(peer_id peer) { return _peer_list.erase(peer); }
|
||||
virtual void clearPeerlist(void) { _peer_list.clear(); }
|
||||
|
||||
// calls fn for each peer
|
||||
virtual void forEachPeer(std::function<void(peer_id)> fn) {
|
||||
for (peer_id peer : _peer_list) {
|
||||
fn(peer);
|
||||
}
|
||||
}
|
||||
|
||||
public: // send/recv
|
||||
|
||||
// sends a packet of max getMaxPacketSize() bytes
|
||||
virtual bool sendPacket(peer_id peer, channel_id channel, uint8_t* data, size_t data_size) = 0;
|
||||
|
||||
// sends a packet, automatically split if too big
|
||||
// !! only on lossless channels
|
||||
virtual bool sendPacketLarge(peer_id peer, channel_id channel, uint8_t* data, size_t data_size) = 0;
|
||||
|
||||
// TODO: broadcast?
|
||||
// has any?
|
||||
|
||||
//virtual bool getPacket
|
||||
|
||||
// calls fn for each packet and fills in peer, channel, data_ptr, and data_size
|
||||
// returns number of fn calls
|
||||
virtual size_t forEachPacket(std::function<void(peer_id, channel_id, uint8_t*, size_t)> fn) = 0;
|
||||
|
||||
// calls fn for each packet and fills in channel, data_ptr, and data_size
|
||||
// returns number of fn calls
|
||||
virtual size_t forEachPacketPeer(peer_id peer, std::function<void(peer_id, channel_id, uint8_t*, size_t)> fn) = 0;
|
||||
|
||||
// calls fn for each packet and fills in data_ptr, and data_size
|
||||
// returns number of fn calls
|
||||
virtual size_t forEachPacketPeerChannel(peer_id peer, channel_id channel, std::function<void(peer_id, channel_id, uint8_t*, size_t)> fn) = 0;
|
||||
};
|
||||
|
||||
} // MM::Services
|
||||
|
27
framework/engine/src/mm/services/scene_service_interface.cpp
Normal file
27
framework/engine/src/mm/services/scene_service_interface.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "./scene_service_interface.hpp"
|
||||
|
||||
#include <entt/entity/registry.hpp>
|
||||
|
||||
namespace MM {
|
||||
|
||||
struct DefaultSystemsContainer {
|
||||
// list of callables, expecting a Scene (ecs) and a step size (delta)
|
||||
std::vector<std::function<void(Scene&, float)>> systems;
|
||||
};
|
||||
|
||||
void AddSystemToScene(::MM::Scene& scene, ::MM::System fn) {
|
||||
auto& sc = scene.ctx_or_set<DefaultSystemsContainer>();
|
||||
sc.systems.emplace_back(std::move(fn));
|
||||
}
|
||||
|
||||
void EachSystemInScene(::MM::Scene& scene, std::function<void(::MM::Scene&, ::MM::System&)> fn) {
|
||||
auto* sc = scene.try_ctx<DefaultSystemsContainer>();
|
||||
if (sc != nullptr) {
|
||||
for (auto& system : sc->systems) {
|
||||
fn(scene, system);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // MM
|
||||
|
44
framework/engine/src/mm/services/scene_service_interface.hpp
Normal file
44
framework/engine/src/mm/services/scene_service_interface.hpp
Normal file
@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/engine.hpp>
|
||||
|
||||
#include <entt/entity/fwd.hpp>
|
||||
|
||||
namespace MM {
|
||||
|
||||
using Entity = entt::entity;
|
||||
using Scene = entt::basic_registry<::MM::Entity>;
|
||||
using System = std::function<void(::MM::Scene&, float)>;
|
||||
|
||||
// opaque way to add a System to a Scene
|
||||
void AddSystemToScene(::MM::Scene& scene, ::MM::System fn);
|
||||
|
||||
// opaque way to iterate over the Systems
|
||||
void EachSystemInScene(::MM::Scene& scene, std::function<void(::MM::Scene&, ::MM::System&)> fn);
|
||||
|
||||
} // MM
|
||||
|
||||
namespace MM::Services {
|
||||
|
||||
class SceneServiceInterface : public Service {
|
||||
public: // Scene stuff
|
||||
// get current Scene
|
||||
virtual ::MM::Scene& getScene(void) = 0;
|
||||
|
||||
// enques a new Scene to be put in place
|
||||
virtual void changeScene(std::unique_ptr<::MM::Scene> new_scene) = 0;
|
||||
|
||||
// sets the new Scene to be provided.
|
||||
// dont use, except for when you know what you are doing!
|
||||
// be carefull of that one (lol)
|
||||
virtual void changeSceneNow(std::unique_ptr<::MM::Scene> new_scene) = 0;
|
||||
|
||||
// adds a System to current Scene.
|
||||
// default impl. will use getScene() !
|
||||
inline virtual void addSystemToScene(::MM::System fn) {
|
||||
::MM::AddSystemToScene(getScene(), std::move(fn));
|
||||
}
|
||||
};
|
||||
|
||||
} // MM::Services
|
||||
|
24
framework/engine/src/mm/services/service.hpp
Normal file
24
framework/engine/src/mm/services/service.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
namespace MM {
|
||||
|
||||
class Engine;
|
||||
|
||||
namespace Services {
|
||||
|
||||
class Service {
|
||||
public:
|
||||
virtual ~Service(void) {}
|
||||
|
||||
virtual const char* name(void) { return "UnNamedService"; }
|
||||
//virtual const char* name(void) = 0; // use this to find unnamed services
|
||||
|
||||
// required
|
||||
virtual bool enable(Engine& engine) = 0;
|
||||
virtual void disable(Engine& engine) = 0;
|
||||
};
|
||||
|
||||
} // Services
|
||||
|
||||
} //MM
|
||||
|
16
framework/engine/test/CMakeLists.txt
Normal file
16
framework/engine/test/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
||||
add_executable(engine_test
|
||||
update_test.cpp
|
||||
run_test.cpp
|
||||
service_system_test.cpp
|
||||
default_service_test.cpp
|
||||
)
|
||||
|
||||
target_include_directories(engine_test PRIVATE ".")
|
||||
|
||||
target_link_libraries(engine_test
|
||||
engine
|
||||
gtest_main
|
||||
)
|
||||
|
||||
add_test(NAME engine_test COMMAND engine_test)
|
||||
|
38
framework/engine/test/default_service_test.cpp
Normal file
38
framework/engine/test/default_service_test.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <mm/engine.hpp>
|
||||
#include <mm/services/default_service.hpp>
|
||||
|
||||
TEST(engine_default_service_system, add_en_dis) {
|
||||
|
||||
MM::Engine e;
|
||||
|
||||
e.addService<MM::Services::DefaultService>();
|
||||
ASSERT_TRUE(e.enableService<MM::Services::DefaultService>());
|
||||
|
||||
{
|
||||
auto* dss = e.tryService<MM::Services::DefaultService>();
|
||||
ASSERT_NE(dss, nullptr);
|
||||
}
|
||||
|
||||
e.disableService<MM::Services::DefaultService>();
|
||||
}
|
||||
|
||||
TEST(engine_default_service_system, tick) {
|
||||
|
||||
MM::Engine e;
|
||||
|
||||
e.addService<MM::Services::DefaultService>();
|
||||
ASSERT_TRUE(e.enableService<MM::Services::DefaultService>());
|
||||
|
||||
e.update();
|
||||
e.fixedUpdate();
|
||||
|
||||
{
|
||||
auto* dss = e.tryService<MM::Services::DefaultService>();
|
||||
ASSERT_NE(dss, nullptr);
|
||||
}
|
||||
|
||||
e.disableService<MM::Services::DefaultService>();
|
||||
}
|
||||
|
61
framework/engine/test/run_test.cpp
Normal file
61
framework/engine/test/run_test.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <mm/engine.hpp>
|
||||
|
||||
TEST(engine_run, test_run) {
|
||||
MM::Engine engine;
|
||||
|
||||
bool run = false;
|
||||
|
||||
auto test_fun = [&run](auto& e) {
|
||||
run = true;
|
||||
e.stop();
|
||||
};
|
||||
|
||||
auto handle = engine.addFixedUpdate(test_fun);
|
||||
ASSERT_NE(handle.lock(), nullptr);
|
||||
|
||||
handle.lock()->priority = 1;
|
||||
|
||||
ASSERT_FALSE(run);
|
||||
engine.run();
|
||||
ASSERT_TRUE(run);
|
||||
|
||||
engine.removeFixedUpdate(handle);
|
||||
}
|
||||
|
||||
TEST(engine_run, test_mult_run) {
|
||||
MM::Engine engine;
|
||||
|
||||
bool run = false;
|
||||
unsigned int fu_count = 0;
|
||||
unsigned int u_count = 0;
|
||||
|
||||
const unsigned int f_to_do = 4;
|
||||
|
||||
auto test_f_fun = [&](auto& e) {
|
||||
run = true;
|
||||
fu_count++;
|
||||
|
||||
if (fu_count >= f_to_do)
|
||||
e.stop();
|
||||
};
|
||||
|
||||
auto handle_f = engine.addFixedUpdate(test_f_fun);
|
||||
ASSERT_NE(handle_f.lock(), nullptr);
|
||||
handle_f.lock()->priority = 1;
|
||||
|
||||
auto handle = engine.addUpdate([&u_count](auto&) { u_count++; });
|
||||
ASSERT_NE(handle_f.lock(), nullptr);
|
||||
handle.lock()->priority = 1;
|
||||
|
||||
ASSERT_FALSE(run);
|
||||
engine.run();
|
||||
ASSERT_TRUE(run);
|
||||
|
||||
EXPECT_GT(u_count, f_to_do) << "expected more update runs than fixed update runs...";
|
||||
std::cout << "while performing " << f_to_do << " fixed updates, the engine did " << u_count << " updates.\n";
|
||||
|
||||
engine.removeFixedUpdate(handle_f);
|
||||
}
|
||||
|
228
framework/engine/test/service_system_test.cpp
Normal file
228
framework/engine/test/service_system_test.cpp
Normal file
@ -0,0 +1,228 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <mm/engine.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 TestService2Derived : public TestService2 {
|
||||
public:
|
||||
const char* name(void) override { return "TestService2Derived"; }
|
||||
|
||||
bool enable(MM::Engine&) override { return true; }
|
||||
void disable(MM::Engine&) override {}
|
||||
};
|
||||
|
||||
TEST(engine_service, add) {
|
||||
MM::Engine e;
|
||||
|
||||
e.addService<TestService1>();
|
||||
|
||||
auto* tss = e.tryService<TestService1>();
|
||||
ASSERT_NE(tss, nullptr);
|
||||
}
|
||||
|
||||
TEST(engine_service, get_fail) {
|
||||
MM::Engine e;
|
||||
|
||||
auto* tss = e.tryService<TestService1>();
|
||||
ASSERT_EQ(tss, nullptr);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
TEST(engine_service, _fail) {
|
||||
MM::Engine e;
|
||||
|
||||
e.addService<TestService1>();
|
||||
|
||||
ASSERT_DEATH({
|
||||
e.addService<TestService1>(); // adding the same
|
||||
}, "failed");
|
||||
|
||||
//auto* tss = e.tryService<TestService1>();
|
||||
//ASSERT_EQ(tss, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(engine_service, add_int_en_dis) {
|
||||
MM::Engine e;
|
||||
|
||||
{
|
||||
auto& tss = e.addService<TestService1>();
|
||||
ASSERT_TRUE(tss.enable(e));
|
||||
}
|
||||
|
||||
{
|
||||
auto* tss = e.tryService<TestService1>();
|
||||
ASSERT_NE(tss, nullptr);
|
||||
|
||||
tss->disable(e);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(engine_service, add_en_dis) {
|
||||
MM::Engine e;
|
||||
|
||||
e.addService<TestService1>();
|
||||
ASSERT_TRUE(e.enableService<TestService1>());
|
||||
|
||||
{
|
||||
auto* tss = e.tryService<TestService1>();
|
||||
ASSERT_NE(tss, nullptr);
|
||||
}
|
||||
|
||||
e.disableService<TestService1>();
|
||||
}
|
||||
|
||||
TEST(engine_service, add_en_dis_mult) {
|
||||
MM::Engine e;
|
||||
|
||||
e.addService<TestService1>();
|
||||
ASSERT_TRUE(e.enableService<TestService1>());
|
||||
|
||||
e.addService<TestService2>();
|
||||
ASSERT_TRUE(e.enableService<TestService2>());
|
||||
|
||||
{
|
||||
auto* tss = e.tryService<TestService1>();
|
||||
ASSERT_NE(tss, nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
auto* tss = e.tryService<TestService2>();
|
||||
ASSERT_NE(tss, nullptr);
|
||||
}
|
||||
|
||||
e.disableService<TestService1>();
|
||||
e.disableService<TestService2>();
|
||||
}
|
||||
|
||||
TEST(engine_service, provide) {
|
||||
MM::Engine e;
|
||||
|
||||
e.addService<TestService2Derived>();
|
||||
ASSERT_TRUE(e.enableService<TestService2Derived>());
|
||||
|
||||
bool r;
|
||||
|
||||
// "mark" TestService2Derived as provider for TestService2
|
||||
r = e.provide<TestService2, TestService2Derived>(); ASSERT_TRUE(r);
|
||||
|
||||
// should not compile
|
||||
//r = e.provide<TestService2Derived, TestService2>();
|
||||
//r = e.provide<TestService2, TestService2>();
|
||||
//r = e.provide<TestService2Derived, TestService2Derived>();
|
||||
|
||||
{
|
||||
auto* tdss = e.tryService<TestService2Derived>();
|
||||
ASSERT_NE(tdss, nullptr);
|
||||
|
||||
auto* iss = e.tryService<TestService2>();
|
||||
ASSERT_NE(iss, nullptr);
|
||||
|
||||
// they are the same (ptr)
|
||||
ASSERT_EQ(tdss, iss);
|
||||
}
|
||||
|
||||
e.disableService<TestService2Derived>();
|
||||
}
|
||||
|
||||
TEST(engine_service, type_ids) {
|
||||
MM::Engine e;
|
||||
|
||||
auto tss1_id = e.type<TestService1>();
|
||||
auto tss2_id = e.type<TestService2>();
|
||||
auto tss2d_id = e.type<TestService2Derived>();
|
||||
|
||||
ASSERT_NE(tss1_id, tss2_id);
|
||||
ASSERT_NE(tss1_id, tss2d_id);
|
||||
ASSERT_NE(tss2_id, tss2d_id);
|
||||
}
|
||||
|
||||
TEST(engine_service, add_en_dis_mult_type_ids) {
|
||||
MM::Engine e;
|
||||
|
||||
auto tss1_id = e.type<TestService1>();
|
||||
auto tss2_id = e.type<TestService2>();
|
||||
ASSERT_NE(tss1_id, tss2_id);
|
||||
|
||||
e.addService<TestService1>();
|
||||
ASSERT_TRUE(e.enableService(tss1_id));
|
||||
|
||||
e.addService<TestService2>();
|
||||
ASSERT_TRUE(e.enableService(tss2_id));
|
||||
|
||||
{
|
||||
auto* tss1 = e.tryService<TestService1>();
|
||||
ASSERT_NE(tss1, nullptr);
|
||||
|
||||
auto* tss2 = e.tryService<TestService2>();
|
||||
ASSERT_NE(tss2, nullptr);
|
||||
|
||||
ASSERT_NE((void*)tss1, (void*)tss2);
|
||||
}
|
||||
|
||||
e.disableService(tss1_id);
|
||||
e.disableService<TestService2>(); // mixin'
|
||||
}
|
||||
|
||||
TEST(engine_service, provide_type_ids) {
|
||||
MM::Engine e;
|
||||
|
||||
auto tss2_id = e.type<TestService2>();
|
||||
auto tss2d_id = e.type<TestService2Derived>();
|
||||
|
||||
e.addService<TestService2Derived>();
|
||||
ASSERT_TRUE(e.enableService(tss2d_id));
|
||||
|
||||
bool r;
|
||||
|
||||
// "mark" TestService2Derived as provider for TestService2
|
||||
r = e.provide(tss2_id, tss2d_id); ASSERT_TRUE(r); // typeid variant
|
||||
//r = e.provide<TestService2, TestService2Derived>(); ASSERT_TRUE(r);
|
||||
|
||||
{
|
||||
auto* tdss = e.tryService<TestService2Derived>();
|
||||
ASSERT_NE(tdss, nullptr);
|
||||
|
||||
auto* iss = e.tryService<TestService2>();
|
||||
ASSERT_NE(iss, nullptr);
|
||||
|
||||
// they are the same (ptr)
|
||||
ASSERT_EQ((void*)tdss, (void*)iss);
|
||||
}
|
||||
|
||||
e.disableService(tss2d_id);
|
||||
}
|
||||
|
||||
TEST(engine_service, run) {
|
||||
MM::Engine e;
|
||||
|
||||
e.addService<TestService1>();
|
||||
ASSERT_TRUE(e.enableService<TestService1>());
|
||||
|
||||
{
|
||||
auto* tss = e.tryService<TestService1>();
|
||||
ASSERT_NE(tss, nullptr);
|
||||
}
|
||||
|
||||
e.addFixedUpdate([](auto& e) { e.stop(); });
|
||||
|
||||
e.run();
|
||||
|
||||
e.disableService<TestService1>();
|
||||
}
|
||||
|
230
framework/engine/test/update_test.cpp
Normal file
230
framework/engine/test/update_test.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <mm/engine.hpp>
|
||||
|
||||
TEST(engine_fixed_update, empty_add_rm) {
|
||||
MM::Engine engine;
|
||||
|
||||
auto test_fun = [](auto&) {};
|
||||
|
||||
auto handle = engine.addFixedUpdate(test_fun);
|
||||
ASSERT_NE(handle.lock(), nullptr);
|
||||
|
||||
handle.lock()->priority = 1;
|
||||
|
||||
engine.removeFixedUpdate(handle);
|
||||
}
|
||||
|
||||
TEST(engine_update, empty_add_rm) {
|
||||
MM::Engine engine;
|
||||
|
||||
auto test_fun = [](auto&) {};
|
||||
|
||||
auto handle = engine.addUpdate(test_fun);
|
||||
ASSERT_NE(handle.lock(), nullptr);
|
||||
|
||||
handle.lock()->priority = 1;
|
||||
|
||||
engine.removeUpdate(handle);
|
||||
}
|
||||
|
||||
TEST(engine_fixed_update, empty_run) {
|
||||
MM::Engine engine;
|
||||
|
||||
auto test_fun = [](auto&) {};
|
||||
|
||||
auto handle = engine.addFixedUpdate(test_fun);
|
||||
ASSERT_NE(handle.lock(), nullptr);
|
||||
|
||||
handle.lock()->priority = 1;
|
||||
|
||||
engine.fixedUpdate(); // single update
|
||||
|
||||
engine.removeFixedUpdate(handle);
|
||||
}
|
||||
|
||||
TEST(engine_update, empty_run) {
|
||||
MM::Engine engine;
|
||||
|
||||
auto test_fun = [](auto&) {};
|
||||
|
||||
auto handle = engine.addUpdate(test_fun);
|
||||
ASSERT_NE(handle.lock(), nullptr);
|
||||
|
||||
handle.lock()->priority = 1;
|
||||
|
||||
engine.update();
|
||||
|
||||
engine.removeUpdate(handle);
|
||||
}
|
||||
|
||||
TEST(engine_fixed_update, test_run) {
|
||||
MM::Engine engine;
|
||||
|
||||
bool run = false;
|
||||
|
||||
auto test_fun = [&run](auto&) { run = true; };
|
||||
|
||||
auto handle = engine.addFixedUpdate(test_fun);
|
||||
ASSERT_NE(handle.lock(), nullptr);
|
||||
|
||||
handle.lock()->priority = 1;
|
||||
|
||||
ASSERT_FALSE(run);
|
||||
engine.fixedUpdate(); // single update
|
||||
ASSERT_TRUE(run);
|
||||
|
||||
engine.removeFixedUpdate(handle);
|
||||
}
|
||||
|
||||
TEST(engine_update, test_run) {
|
||||
MM::Engine engine;
|
||||
|
||||
bool run = false;
|
||||
|
||||
auto test_fun = [&run](auto&) { run = true; };
|
||||
|
||||
auto handle = engine.addUpdate(test_fun);
|
||||
ASSERT_NE(handle.lock(), nullptr);
|
||||
|
||||
handle.lock()->priority = 1;
|
||||
|
||||
ASSERT_FALSE(run);
|
||||
engine.update();
|
||||
ASSERT_TRUE(run);
|
||||
|
||||
engine.removeUpdate(handle);
|
||||
}
|
||||
|
||||
TEST(engine_fixed_update, test_order_run) {
|
||||
MM::Engine engine;
|
||||
|
||||
bool run1 = false;
|
||||
bool run2 = false;
|
||||
|
||||
auto test_fun1 = [&](auto&) {
|
||||
ASSERT_FALSE(run2);
|
||||
run1 = true;
|
||||
};
|
||||
auto test_fun2 = [&](auto&) {
|
||||
ASSERT_TRUE(run1);
|
||||
run2 = true;
|
||||
};
|
||||
|
||||
auto handle1 = engine.addFixedUpdate(test_fun1);
|
||||
ASSERT_NE(handle1.lock(), nullptr);
|
||||
handle1.lock()->priority = 1;
|
||||
|
||||
auto handle2 = engine.addFixedUpdate(test_fun2);
|
||||
ASSERT_NE(handle2.lock(), nullptr);
|
||||
handle2.lock()->priority = 0;
|
||||
|
||||
ASSERT_FALSE(run1);
|
||||
ASSERT_FALSE(run2);
|
||||
engine.fixedUpdate(); // single update
|
||||
ASSERT_TRUE(run1);
|
||||
ASSERT_TRUE(run2);
|
||||
|
||||
engine.removeFixedUpdate(handle1);
|
||||
engine.removeFixedUpdate(handle2);
|
||||
}
|
||||
|
||||
TEST(engine_fixed_update, test_order_rev_run) {
|
||||
MM::Engine engine;
|
||||
|
||||
bool run1 = false;
|
||||
bool run2 = false;
|
||||
|
||||
auto test_fun1 = [&](auto&) {
|
||||
ASSERT_TRUE(run2);
|
||||
run1 = true;
|
||||
};
|
||||
auto test_fun2 = [&](auto&) {
|
||||
ASSERT_FALSE(run1);
|
||||
run2 = true;
|
||||
};
|
||||
|
||||
auto handle1 = engine.addFixedUpdate(test_fun1);
|
||||
ASSERT_NE(handle1.lock(), nullptr);
|
||||
handle1.lock()->priority = 0;
|
||||
|
||||
auto handle2 = engine.addFixedUpdate(test_fun2);
|
||||
ASSERT_NE(handle2.lock(), nullptr);
|
||||
handle2.lock()->priority = 1;
|
||||
|
||||
ASSERT_FALSE(run1);
|
||||
ASSERT_FALSE(run2);
|
||||
engine.fixedUpdate(); // single update
|
||||
ASSERT_TRUE(run1);
|
||||
ASSERT_TRUE(run2);
|
||||
|
||||
engine.removeFixedUpdate(handle1);
|
||||
engine.removeFixedUpdate(handle2);
|
||||
}
|
||||
|
||||
TEST(engine_update, test_order_run) {
|
||||
MM::Engine engine;
|
||||
|
||||
bool run1 = false;
|
||||
bool run2 = false;
|
||||
|
||||
auto test_fun1 = [&](auto&) {
|
||||
ASSERT_FALSE(run2);
|
||||
run1 = true;
|
||||
};
|
||||
auto test_fun2 = [&](auto&) {
|
||||
ASSERT_TRUE(run1);
|
||||
run2 = true;
|
||||
};
|
||||
|
||||
auto handle1 = engine.addUpdate(test_fun1);
|
||||
ASSERT_NE(handle1.lock(), nullptr);
|
||||
handle1.lock()->priority = 1;
|
||||
|
||||
auto handle2 = engine.addUpdate(test_fun2);
|
||||
ASSERT_NE(handle2.lock(), nullptr);
|
||||
handle2.lock()->priority = 0;
|
||||
|
||||
ASSERT_FALSE(run1);
|
||||
ASSERT_FALSE(run2);
|
||||
engine.update(); // single update
|
||||
ASSERT_TRUE(run1);
|
||||
ASSERT_TRUE(run2);
|
||||
|
||||
engine.removeUpdate(handle1);
|
||||
engine.removeUpdate(handle2);
|
||||
}
|
||||
|
||||
TEST(engine_update, test_order_rev_run) {
|
||||
MM::Engine engine;
|
||||
|
||||
bool run1 = false;
|
||||
bool run2 = false;
|
||||
|
||||
auto test_fun1 = [&](auto&) {
|
||||
ASSERT_TRUE(run2);
|
||||
run1 = true;
|
||||
};
|
||||
auto test_fun2 = [&](auto&) {
|
||||
ASSERT_FALSE(run1);
|
||||
run2 = true;
|
||||
};
|
||||
|
||||
auto handle1 = engine.addUpdate(test_fun1);
|
||||
ASSERT_NE(handle1.lock(), nullptr);
|
||||
handle1.lock()->priority = 0;
|
||||
|
||||
auto handle2 = engine.addUpdate(test_fun2);
|
||||
ASSERT_NE(handle2.lock(), nullptr);
|
||||
handle2.lock()->priority = 1;
|
||||
|
||||
ASSERT_FALSE(run1);
|
||||
ASSERT_FALSE(run2);
|
||||
engine.update(); // single update
|
||||
ASSERT_TRUE(run1);
|
||||
ASSERT_TRUE(run2);
|
||||
|
||||
engine.removeUpdate(handle1);
|
||||
engine.removeUpdate(handle2);
|
||||
}
|
||||
|
Reference in New Issue
Block a user