#pragma once #include #include #include #include #include #include #include #include #include #include namespace MM { class Engine { private: using service_family = entt::family; public: using service_family_type = service_family::family_type; // the services "internal" interface //private: public: struct FunctionPriorityDataStructure { std::function f; int16_t priority = 0; // 0 is equal to scene update, the higher the prio the earlier std::string name; explicit FunctionPriorityDataStructure(std::function 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; // important: its a pointer // return nullptr on error [[nodiscard]] FunctionDataHandle addUpdate(std::function function); [[nodiscard]] FunctionDataHandle addFixedUpdate(std::function 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 function); private: std::vector> _update_functions; bool _update_functions_modified; std::vector> _fixed_update_functions; bool _fixed_update_functions_modified; std::vector> _fixed_defered; private: void traverseUpdateFunctions(std::vector>& 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_add_order; // ? std::vector _service_enable_order; // ? //std::unordered_map>> _services; std::unordered_map< service_family::family_type, std::shared_ptr >> > _services; // maps I to T //std::unordered_map _implementation_provider; 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); 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