#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; private: using service_family = entt::family; public: using service_family_type = service_family::family_type; protected: std::unique_ptr _update_strategy; public: UpdateStrategies::UpdateStrategy& getUpdateStrategy(void) { return *_update_strategy; } private: volatile bool _is_running = false; private: void setup(void); public: Engine(void); explicit Engine(std::unique_ptr us) { setup(); _update_strategy = std::move(us); } public: ~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() until stopped void stop(void); private: std::vector _service_add_order; // ? std::vector _service_enable_order; // ? //std::unordered_map>> _services; std::unordered_map< service_family::family_type, std::shared_ptr >> > _services; public: template constexpr auto type(void) { return service_family::type; } template T& addService(Args&& ... args) { assert(!tryService()); auto& ss_entry = _services[service_family::type] = std::make_shared>>( std::make_pair>( false, std::make_unique(std::forward(args)...) ) ); _service_add_order.emplace_back(service_family::type); // add updates to update strategy _update_strategy->registerService( service_family::type, ss_entry.get()->second->registerUpdates() ); return (T&)*ss_entry.get()->second.get(); } template [[nodiscard]] T* tryService(void) const { if (_services.count(service_family::type)) { return static_cast(_services.at(service_family::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(service_family::family_type s_t); void disableService(service_family::family_type s_t); template bool enableService(void) { return enableService(service_family::type); } template void disableService(void) { disableService(service_family::type); } // 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 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(service_family::type, service_family::type); } // TODO: reimplement??? //template //void removeProvider(void) { //if (auto it = _implementation_provider.find(service_family::type); it != _implementation_provider.end()) { //_implementation_provider.erase(it); //} //} }; } // MM