#pragma once #include "./engine_fwd.hpp" #include #include #include #include #include #include #include #include #include #include #include namespace MM { // fwd namespace Services { class ImGuiEngineTools; } class Engine { friend Services::ImGuiEngineTools; public: using service_id_type = entt::id_type; // alias, for future proof // UpdateStrategy protected: std::unique_ptr _update_strategy; public: UpdateStrategies::UpdateStrategy& getUpdateStrategy(void) { return *_update_strategy; } // state private: volatile bool _is_running = false; // ... just realisied: i never needed a getter ... std::vector _service_add_order; // ? std::vector _service_enable_order; // ? std::unordered_map< entt::id_type, std::shared_ptr >> > _services; // private state helper private: void setup(void); // ctr dtr ... public: Engine(void); ~Engine(void); explicit Engine(std::unique_ptr us) { setup(); _update_strategy = std::move(us); } // called from destructor or explicitly (if eg "global", u need dis) void cleanup(void); void update(void); void run(void); // calls update() until stopped void stop(void); public: template constexpr static auto type(void) { //return entt::type_id.hash(); return entt::type_hash::value(); } template T& addService(Args&& ... args) { assert(!tryService()); auto& ss_entry = _services[type()] = std::make_shared>>( std::make_pair>( false, std::make_unique(std::forward(args)...) ) ); _service_add_order.emplace_back(type()); return (T&)*ss_entry.get()->second.get(); } template [[nodiscard]] T* tryService(void) const { if (_services.count(type())) { return static_cast(_services.at(type()).get()->second.get()); } return nullptr; } template [[deprecated("use tryService() instead")]] [[nodiscard]] T* tryGetService(void) const { return tryService(); } template [[nodiscard]] T& getService(void) const { T* tmp = tryService(); assert(tmp); return *tmp; } bool enableService(entt::id_type s_t); void disableService(entt::id_type s_t); template bool enableService(void) { return enableService(type()); } template void disableService(void) { disableService(type()); } // provide T as I implementation // T needs to be an added Service bool provide(entt::id_type I, entt::id_type T); // provide T as I implementation // T needs to be an added Service template bool provide(void) { static_assert(std::is_base_of_v, "T is not derived from I!"); static_assert(!std::is_same_v, "I and T are the same, makes no sense!"); return provide(type(), type()); } // TODO: remove service //void removeProvider(void) { }; } // MM