#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 TextureM; BinaryResourceManager ModelM; BinaryResourceManager SoundM; ContentObj(asio::io_context &ioc, std::shared_ptr zeroTexture, std::shared_ptr zeroModel, std::shared_ptr zeroSound) : TextureM(ioc, zeroTexture), ModelM(ioc, zeroModel), SoundM(ioc, zeroSound) { } } Content; struct { std::vector> CECs; // Индекс игрока, у которого в следующем такте будет пересмотрен ContentEventController->ContentViewCircles uint16_t CEC_NextRebuildViewCircles = 0, CEC_NextCheckRegions = 0; ServerTime AfterStartTime = {0, 0}; } Game; struct WorldObj { std::unordered_map ContentBridges; std::vector calcCVCs(ContentViewCircle circle, int depth = 2); 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 _calcContentViewCircles(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) { 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); private: void init(fs::path worldPath); void prerun(); void run(); void stepContent(); void stepPlayers(); void stepWorlds(); void stepViewContent(); void stepSendPlayersPackets(); void stepLoadRegions(); void stepGlobal(); void stepSave(); void save(); }; }