Files
LuaVox/Src/Server/GameServer.hpp
2025-07-01 17:47:35 +06:00

218 lines
7.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <Common/Net.hpp>
#include <Common/Lockable.hpp>
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/io_context.hpp>
#include <filesystem>
#include "RemoteClient.hpp"
#include "Server/Abstract.hpp"
#include <TOSLib.hpp>
#include <memory>
#include <set>
#include <thread>
#include <unordered_map>
#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<std::set<std::string>> ConnectedPlayersSet;
Lockable<std::list<std::unique_ptr<RemoteClient>>> 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<ResourceFile> zeroTexture,
std::shared_ptr<ResourceFile> zeroAnimation,
std::shared_ptr<ResourceFile> zeroModel,
std::shared_ptr<ResourceFile> zeroSound,
std::shared_ptr<ResourceFile> zeroFont)
: Texture(ioc, zeroTexture),
Animation(ioc, zeroAnimation),
Model(ioc, zeroModel),
Sound(ioc, zeroSound),
Font(ioc, zeroFont)
{}
} Content;
struct {
std::vector<std::unique_ptr<ContentEventController>> CECs;
ServerTime AfterStartTime = {0, 0};
} Game;
struct Expanse_t {
std::unordered_map<ContentBridgeId_t, ContentBridge> ContentBridges;
// Вычисляет окружности обозримой области
// depth ограничивает глубину входа в ContentBridges
std::vector<ContentViewCircle> accumulateContentViewCircles(ContentViewCircle circle, int depth = 2);
// Вынести в отдельный поток
static ContentViewInfo makeContentViewInfo(const std::vector<ContentViewCircle> &views);
ContentViewInfo makeContentViewInfo(ContentViewCircle circle, int depth = 2) {
return makeContentViewInfo(accumulateContentViewCircles(circle, depth));
}
// std::unordered_map<WorldId_t, std::vector<ContentViewCircle>> remapCVCsByWorld(const std::vector<ContentViewCircle> &list);
// std::unordered_map<WorldId_t, std::vector<ContentViewCircle>> calcAndRemapCVC(ContentViewCircle circle, int depth = 2) {
// return remapCVCsByWorld(calcCVCs(circle, depth));
// }
std::unordered_map<WorldId_t, std::unique_ptr<World>> Worlds;
/*
Регистрация миров по строке
*/
/*
*/
private:
void _accumulateContentViewCircles(ContentViewCircle circle, int depth);
} Expanse;
struct {
std::unique_ptr<IWorldSaveBackend> World;
std::unique_ptr<IPlayerSaveBackend> Player;
std::unique_ptr<IAuthSaveBackend> Auth;
std::unique_ptr<IModStorageSaveBackend> 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();
/*
Пересчёт зон видимости игроков, если необходимо
Выгрузить более не используемые регионы
Сохранение регионов
Создание списка регионов необходимых для загрузки (бд автоматически будет предзагружать)
<Синхронизация с модулем сохранений>
Очередь загрузки, выгрузка регионов и получение загруженных из бд регионов
Получить список регионов отсутствующих в сохранении и требующих генерации
Подпись на загруженные регионы (отправить полностью на клиент)
*/
IWorldSaveBackend::TickSyncInfo_Out stepDatabaseSync();
/*
Синхронизация с генератором карт (отправка запросов на генерацию и получение шума для обработки модами)
Обработка модами сырых регионов полученных с бд
Синхронизация с потоками модов
*/
void stepGeneratorAndLuaAsync(IWorldSaveBackend::TickSyncInfo_Out db);
/*
Пакеты игроков получает асинхронный поток в RemoteClient
Остаётся только обработать распаршенные пакеты
*/
void stepPlayerProceed();
/*
Физика
*/
void stepWorldPhysic();
/*
Глобальный такт
*/
void stepGlobalStep();
/*
Обработка запросов двоичных ресурсов и определений
Отправка пакетов игрокам
*/
void stepSyncContent();
};
}