#pragma once #include #include #include #include #include #include "RemoteClient.hpp" #include "Server/Abstract.hpp" #include #include #include #include #include #include "ContentEventController.hpp" #include "WorldDefManager.hpp" #include "BinaryResourceManager.hpp" #include "World.hpp" #include "SaveBackend.hpp" namespace LV::Server { namespace fs = std::filesystem; class GameServer : public AsyncObject { TOS::Logger LOG = "GameServer"; DestroyLock UseLock; std::thread RunThread; bool IsAlive = true, IsGoingShutdown = false; std::string ShutdownReason; static constexpr float PerTickDuration = 1/30.f, // Минимальная и стартовая длина такта PerTickAdjustment = 1/60.f; // Подгонка длительности такта в случае провисаний float CurrentTickDuration = PerTickDuration, // Текущая длительность такта GlobalTickLagTime = 0; // На сколько глобально запаздываем по симуляции struct { Lockable> ConnectedPlayersSet; Lockable>> NewConnectedPlayers; } External; struct ContentObj { public: // WorldDefManager WorldDM; // VoxelDefManager VoxelDM; // NodeDefManager NodeDM; BinaryResourceManager Texture; BinaryResourceManager Animation; BinaryResourceManager Model; BinaryResourceManager Sound; BinaryResourceManager Font; ContentObj(asio::io_context &ioc, std::shared_ptr zeroTexture, std::shared_ptr zeroAnimation, std::shared_ptr zeroModel, std::shared_ptr zeroSound, std::shared_ptr zeroFont) : Texture(ioc, zeroTexture), Animation(ioc, zeroAnimation), Model(ioc, zeroModel), Sound(ioc, zeroSound), Font(ioc, zeroFont) {} } Content; struct { std::vector> CECs; // Индекс игрока, у которого в следующем такте будет пересмотрен ContentEventController->ContentViewCircles uint16_t CEC_NextRebuildViewCircles = 0, CEC_NextCheckRegions = 0; ServerTime AfterStartTime = {0, 0}; } Game; struct Expanse_t { std::unordered_map ContentBridges; // Вычисляет окружности обозримой области // depth ограничивает глубину входа в ContentBridges std::vector accumulateContentViewCircles(ContentViewCircle circle, int depth = 2); // Вынести в отдельный поток static ContentViewInfo makeContentViewInfo(const std::vector &views); ContentViewInfo makeContentViewInfo(ContentViewCircle circle, int depth = 2) { return makeContentViewInfo(accumulateContentViewCircles(circle, depth)); } // std::unordered_map> remapCVCsByWorld(const std::vector &list); // std::unordered_map> calcAndRemapCVC(ContentViewCircle circle, int depth = 2) { // return remapCVCsByWorld(calcCVCs(circle, depth)); // } std::unordered_map> Worlds; /* Регистрация миров по строке */ /* */ private: void _accumulateContentViewCircles(ContentViewCircle circle, int depth); } Expanse; struct { std::unique_ptr World; std::unique_ptr Player; std::unique_ptr Auth; std::unique_ptr ModStorage; } SaveBackend; public: GameServer(asio::io_context &ioc, fs::path worldPath) : AsyncObject(ioc), Content(ioc, nullptr, nullptr, nullptr, nullptr, nullptr) { init(worldPath); } virtual ~GameServer(); void shutdown(const std::string reason) { if(ShutdownReason.empty()) ShutdownReason = reason; IsGoingShutdown = true; } bool isAlive() { return IsAlive; } void waitShutdown() { UseLock.wait_no_use(); } // Подключение tcp сокета coro<> pushSocketConnect(tcp::socket socket); // Сокет, прошедший авторизацию (onSocketConnect() передаёт его в onSocketAuthorized()) coro<> pushSocketAuthorized(tcp::socket socket, const std::string username); // Инициализация игрового протокола для сокета (onSocketAuthorized() может передать сокет в onSocketGame()) coro<> pushSocketGameProtocol(tcp::socket socket, const std::string username); /* Загрузит, сгенерирует или просто выдаст регион из мира, который должен существовать */ Region* forceGetRegion(WorldId_t worldId, Pos::GlobalRegion pos); private: void init(fs::path worldPath); void prerun(); void run(); /* Подключение/отключение игроков */ void stepConnections(); /* Переинициализация модов, если требуется */ void stepModInitializations(); /* Пересчёт зон видимости игроков, если необходимо Выгрузить более не используемые регионы Сохранение регионов Создание списка регионов необходимых для загрузки (бд автоматически будет предзагружать) <Синхронизация с модулем сохранений> Очередь загрузки, выгрузка регионов и получение загруженных из бд регионов Получить список регионов отсутствующих в сохранении и требующих генерации Подпись на загруженные регионы (отправить полностью на клиент) */ void stepDatabase(); /* Синхронизация с генератором карт (отправка запросов на генерацию и получение шума для обработки модами) Синхронизация с потоками модов */ void stepLuaAsync(); /* Получить пакеты с игроков */ void stepPlayerProceed(); /* Физика */ void stepWorldPhysic(); /* Глобальный такт */ void stepGlobalStep(); /* Обработка запросов двоичных ресурсов и определений Отправка пакетов игрокам */ void stepSyncContent(); }; }