Получение пакетов клиентом

This commit is contained in:
2025-02-09 23:52:04 +06:00
parent 871b03632e
commit cea3a0ca28
26 changed files with 927 additions and 269 deletions

View File

@@ -8,20 +8,6 @@
namespace LV::Server {
// Идентификаторы на стороне клиента
using TextureId_c = uint16_t;
using SoundId_c = uint16_t;
using ModelId_c = uint16_t;
using DefWorldId_c = uint8_t;
using WorldId_c = uint8_t;
using VoxelId_c = uint16_t;
using NodeId_c = uint16_t;
using DefPortalId_c = uint8_t;
using PortalId_c = uint8_t;
using DefEntityId_c = uint16_t;
using EntityId_c = uint16_t;
using ResourceId_t = uint32_t;
// Двоичные данные

View File

@@ -1,6 +1,7 @@
#include "GameServer.hpp"
#include "Common/Abstract.hpp"
#include "Common/Net.hpp"
#include "Common/Packets.hpp"
#include "Server/Abstract.hpp"
#include "Server/ContentEventController.hpp"
#include <boost/json/parse.hpp>
@@ -248,7 +249,7 @@ void GameServer::run() {
if(IsGoingShutdown) {
// Отключить игроков
for(std::unique_ptr<ContentEventController> &cec : Game.CECs) {
cec->Remote->shutdown(ShutdownReason);
cec->Remote->shutdown(EnumDisconnect::ByInterface, ShutdownReason);
}
// Сохранить данные
@@ -259,7 +260,7 @@ void GameServer::run() {
auto lock = External.NewConnectedPlayers.lock_write();
for(std::unique_ptr<RemoteClient> &client : *lock) {
client->shutdown(ShutdownReason);
client->shutdown(EnumDisconnect::ByInterface, ShutdownReason);
}
bool hasNewConnected = !lock->empty();
@@ -361,6 +362,14 @@ void GameServer::stepPlayers() {
for(std::unique_ptr<ContentEventController> &cec : Game.CECs) {
// Убрать отключившихся
if(!cec->Remote->isConnected()) {
for(auto wPair : cec->SubscribedRegions) {
auto wIter = Expanse.Worlds.find(wPair.first);
if(wIter == Expanse.Worlds.end())
continue;
wIter->second->onCEC_RegionsLost(cec.get(), wPair.second);
}
cec.reset();
}

View File

@@ -114,7 +114,8 @@ public:
void shutdown(const std::string reason) {
ShutdownReason = reason;
if(ShutdownReason.empty())
ShutdownReason = reason;
IsGoingShutdown = true;
}

View File

@@ -14,7 +14,11 @@
namespace LV::Server {
RemoteClient::~RemoteClient() {
shutdown("~RemoteClient()");
shutdown(EnumDisconnect::ByInterface, "~RemoteClient()");
if(Socket.isAlive()) {
Socket.closeRead();
}
UseLock.wait_no_use();
}
@@ -23,7 +27,7 @@ coro<> RemoteClient::run() {
try {
while(!IsGoingShutdown && IsConnected) {
co_await Socket.read<uint8_t>();
co_await readPacket(Socket);
}
} catch(const std::exception &exc) {
if(const auto *errc = dynamic_cast<const boost::system::system_error*>(&exc);
@@ -40,7 +44,7 @@ coro<> RemoteClient::run() {
co_return;
}
void RemoteClient::shutdown(const std::string reason) {
void RemoteClient::shutdown(EnumDisconnect type, const std::string reason) {
if(IsGoingShutdown)
return;
@@ -48,7 +52,17 @@ void RemoteClient::shutdown(const std::string reason) {
NextPacket << (uint8_t) ToClient::L1::System
<< (uint8_t) ToClient::L2System::Disconnect
<< reason;
<< (uint8_t) type << reason;
std::string info;
if(type == EnumDisconnect::ByInterface)
info = "по запросу интерфейса " + reason;
else if(type == EnumDisconnect::CriticalError)
info = "на сервере произошла критическая ошибка " + reason;
else if(type == EnumDisconnect::ProtocolError)
info = "ошибка протокола (сервер) " + reason;
LOG.info() << "Игрок '" << Username << "' отключился " << info;
}
@@ -70,7 +84,7 @@ void RemoteClient::prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk
std::unordered_set<DefVoxelId_t> NeedVoxelsSet(NeedVoxels.begin(), NeedVoxels.end());
// Собираем информацию о конвертации идентификаторов
std::unordered_map<DefVoxelId_t, VoxelId_c> LocalRemapper;
std::unordered_map<DefVoxelId_t, DefVoxelId_c> LocalRemapper;
for(DefVoxelId_t vId : NeedVoxelsSet) {
LocalRemapper[vId] = ResRemap.DefVoxels.toClient(vId);
}
@@ -87,7 +101,7 @@ void RemoteClient::prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk
// Определение больше не используется
ResUses.DefVoxel.erase(ResUses.DefVoxel.find(id));
VoxelId_c cId = ResRemap.DefVoxels.erase(id);
DefVoxelId_c cId = ResRemap.DefVoxels.erase(id);
// TODO: отправить пакет потери идентификатора
LOG.debug() << "Определение вокселя потеряно: " << id << " -> " << cId;
}
@@ -99,7 +113,7 @@ void RemoteClient::prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk
if(++ResUses.DefVoxel[id] == 1) {
// Определение только появилось
NextRequest.NewVoxels.push_back(id);
VoxelId_c cId = ResRemap.DefVoxels.toClient(id);
DefVoxelId_c cId = ResRemap.DefVoxels.toClient(id);
LOG.debug() << "Новое определение вокселя: " << id << " -> " << cId;
}
}
@@ -108,24 +122,23 @@ void RemoteClient::prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk
prevSet = std::move(nextSet);
}
// TODO: отправить новую информацию о расположении вокселей
LOG.debug() << "Новый чанк: " << worldId << " / " << chunkPos.X << ":" << chunkPos.Y << ":" << chunkPos.Z;
// Packet Id
// NextPacket << uint16_t(0);
// NextPacket << wcId << Pos::GlobalChunk::Key(chunkPos);
// NextPacket << uint16_t(voxels.size());
LOG.debug() << "Воксели чанка: " << worldId << " / " << chunkPos.X << ":" << chunkPos.Y << ":" << chunkPos.Z;
// for(const VoxelCube &cube : voxels) {
// NextPacket << LocalRemapper[cube.VoxelId]
// << cube.Left.X << cube.Left.Y << cube.Left.Z
// << cube.Right.X << cube.Right.Y << cube.Right.Z;
// }
NextPacket << (uint8_t) ToClient::L1::Content
<< (uint8_t) ToClient::L2Content::ChunkVoxels << wcId
<< Pos::GlobalChunk::Key(chunkPos);
NextPacket << uint16_t(voxels.size());
// TODO:
for(const VoxelCube &cube : voxels) {
NextPacket << LocalRemapper[cube.VoxelId]
<< cube.Left.X << cube.Left.Y << cube.Left.Z
<< cube.Right.X << cube.Right.Y << cube.Right.Z;
}
}
void RemoteClient::prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::GlobalChunk chunkPos,
const std::unordered_map<Pos::Local16_u, Node> &nodes)
{
// Перебиндить идентификаторы нод
}
@@ -144,7 +157,7 @@ void RemoteClient::prepareChunkRemove(WorldId_t worldId, Pos::GlobalChunk chunkP
// Определение больше не используется
ResUses.DefVoxel.erase(ResUses.DefVoxel.find(id));
VoxelId_c cId = ResRemap.DefVoxels.erase(id);
DefVoxelId_c cId = ResRemap.DefVoxels.erase(id);
// TODO: отправить пакет потери идентификатора
LOG.debug() << "Определение вокселя потеряно: " << id << " -> " << cId;
}
@@ -154,7 +167,7 @@ void RemoteClient::prepareChunkRemove(WorldId_t worldId, Pos::GlobalChunk chunkP
WorldId_c cwId = ResRemap.Worlds.toClient(worldId);
NextPacket << (uint8_t) ToClient::L1::Content
<< (uint8_t) ToClient::L2Content::RemoveChunk
<< cwId << chunkPos.X << chunkPos.Y << chunkPos.Z;
<< cwId << Pos::GlobalChunk::Key(chunkPos);
}
void RemoteClient::prepareWorldNew(WorldId_t worldId, World* world)
@@ -166,7 +179,7 @@ void RemoteClient::prepareWorldNew(WorldId_t worldId, World* world)
DefWorldId_c cdId = ResRemap.DefWorlds.toClient(res.DefId);
NextRequest.NewWorlds.push_back(res.DefId);
LOG.debug() << "Новое определение мира: " << res.DefId << " -> " << cdId;
LOG.debug() << "Новое определение мира: " << res.DefId << " -> " << int(cdId);
NextPacket << (uint8_t) ToClient::L1::Definition
<< (uint8_t) ToClient::L2Definition::World
<< cdId;
@@ -468,7 +481,7 @@ void RemoteClient::informateDefVoxel(const std::unordered_map<DefVoxelId_t, void
if(!ResUses.DefWorld.contains(sId))
continue;
VoxelId_c cId = ResRemap.DefVoxels.toClient(sId);
DefVoxelId_c cId = ResRemap.DefVoxels.toClient(sId);
NextPacket << (uint8_t) ToClient::L1::Definition
<< (uint8_t) ToClient::L2Definition::Voxel
@@ -483,7 +496,7 @@ void RemoteClient::informateDefNode(const std::unordered_map<DefNodeId_t, void*>
if(!ResUses.DefNode.contains(sId))
continue;
NodeId_c cId = ResRemap.DefNodes.toClient(sId);
DefNodeId_c cId = ResRemap.DefNodes.toClient(sId);
NextPacket << (uint8_t) ToClient::L1::Definition
<< (uint8_t) ToClient::L2Definition::Node
@@ -521,6 +534,46 @@ void RemoteClient::informateDefPortals(const std::unordered_map<DefPortalId_t, v
}
}
void RemoteClient::protocolError() {
shutdown(EnumDisconnect::ProtocolError, "Ошибка протокола");
}
coro<> RemoteClient::readPacket(Net::AsyncSocket &sock) {
uint8_t first = co_await sock.read<uint8_t>();
switch((ToServer::L1) first) {
case ToServer::L1::System: co_await rP_System(sock); co_return;
default:
protocolError();
}
}
coro<> RemoteClient::rP_System(Net::AsyncSocket &sock) {
uint8_t second = co_await sock.read<uint8_t>();
switch((ToServer::L2System) second) {
case ToServer::L2System::InitEnd:
co_return;
case ToServer::L2System::Disconnect:
{
EnumDisconnect type = (EnumDisconnect) co_await sock.read<uint8_t>();
shutdown(EnumDisconnect::ByInterface, "Вы были отключены от игры");
std::string reason;
if(type == EnumDisconnect::CriticalError)
reason = ": Критическая ошибка";
else
reason = ": Ошибка протокола (клиент)";
LOG.info() << "Игрок '" << Username << "' отключился" << reason;
co_return;
}
default:
protocolError();
}
}
void RemoteClient::incrementBinary(std::unordered_set<BinTextureId_t> &textures, std::unordered_set<BinSoundId_t> &sounds,
std::unordered_set<BinModelId_t> &models)
{

View File

@@ -4,6 +4,7 @@
#include <Common/Lockable.hpp>
#include <Common/Net.hpp>
#include "Abstract.hpp"
#include "Common/Packets.hpp"
#include "Server/ContentEventController.hpp"
#include <Common/Abstract.hpp>
#include <bitset>
@@ -249,8 +250,8 @@ class RemoteClient {
SCSKeyRemapper<BinModelId_t, ModelId_c> BinModels;
SCSKeyRemapper<DefWorldId_t, DefWorldId_c> DefWorlds;
SCSKeyRemapper<DefVoxelId_t, VoxelId_c> DefVoxels;
SCSKeyRemapper<DefNodeId_t, NodeId_c> DefNodes;
SCSKeyRemapper<DefVoxelId_t, DefVoxelId_c> DefVoxels;
SCSKeyRemapper<DefNodeId_t, DefNodeId_c> DefNodes;
SCSKeyRemapper<DefPortalId_t, DefPortalId_c> DefPortals;
SCSKeyRemapper<DefEntityId_t, DefEntityId_c> DefEntityes;
@@ -275,7 +276,7 @@ public:
~RemoteClient();
coro<> run();
void shutdown(const std::string reason);
void shutdown(EnumDisconnect type, const std::string reason);
bool isConnected() { return IsConnected; }
void pushPackets(std::vector<Net::Packet> *simplePackets, std::vector<Net::SmartPacket> *smartPackets = nullptr) {
@@ -330,6 +331,10 @@ public:
void informateDefPortals(const std::unordered_map<DefPortalId_t, void*> &portals);
private:
void protocolError();
coro<> readPacket(Net::AsyncSocket &sock);
coro<> rP_System(Net::AsyncSocket &sock);
void incrementBinary(std::unordered_set<BinTextureId_t> &textures, std::unordered_set<BinSoundId_t> &sounds,
std::unordered_set<BinModelId_t> &models);
void decrementBinary(std::unordered_set<BinTextureId_t> &textures, std::unordered_set<BinSoundId_t> &sounds,