#include "ServerMainloop.hpp" #include "Engine.hpp" #include "logic/scripting/scripting.hpp" #include "logic/LevelController.hpp" #include "interfaces/Process.hpp" #include "debug/Logger.hpp" #include "world/Level.hpp" #include "world/World.hpp" #include "util/platform.hpp" #include using namespace std::chrono; static debug::Logger logger("mainloop"); ServerMainloop::ServerMainloop(Engine& engine) : engine(engine) { } ServerMainloop::~ServerMainloop() = default; void ServerMainloop::run() { const auto& coreParams = engine.getCoreParameters(); auto& time = engine.getTime(); if (coreParams.scriptFile.empty()) { logger.info() << "nothing to do"; return; } engine.setLevelConsumer([this](auto level, auto) { setLevel(std::move(level)); }); auto process = scripting::start_app_script( "script:" + coreParams.scriptFile.filename().u8string() ); double targetDelta = 1.0 / static_cast(coreParams.tps); double delta = targetDelta; auto begin = system_clock::now(); auto startupTime = begin; while (process->isActive()) { if (engine.isQuitSignal()) { process->terminate(); logger.info() << "script has been terminated due to quit signal"; break; } if (coreParams.testMode) { time.step(delta); } else { auto now = system_clock::now(); time.update( duration_cast(now - startupTime).count() / 1e6); delta = time.getDelta(); } process->update(); if (controller) { controller->getLevel()->getWorld()->updateTimers(delta); controller->update(glm::min(delta, 0.2), false); } engine.applicationTick(); engine.postUpdate(); if (!coreParams.testMode) { auto end = system_clock::now(); int64_t millis = targetDelta * 1000 - duration_cast(end - begin).count() / 1000; if (millis > 0) { platform::sleep(millis); } begin = system_clock::now(); } } logger.info() << "script finished"; } void ServerMainloop::setLevel(std::unique_ptr level) { if (level == nullptr) { controller->onWorldQuit(); engine.getPaths().setCurrentWorldFolder(""); controller = nullptr; } else { controller = std::make_unique( &engine, std::move(level), nullptr ); } }