Files
LuaVox/Src/Client/ServerSession.cpp

791 lines
26 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.

#include "ServerSession.hpp"
#include "Client/Abstract.hpp"
#include "Common/Abstract.hpp"
#include "Common/Net.hpp"
#include "TOSAsync.hpp"
#include "TOSLib.hpp"
#include "glm/ext/quaternion_geometric.hpp"
#include <GLFW/glfw3.h>
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/this_coro.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
#include <functional>
#include <memory>
#include <Common/Packets.hpp>
#include <glm/ext.hpp>
#include <unordered_map>
#include <unordered_set>
namespace LV::Client {
ServerSession::ServerSession(asio::io_context &ioc, std::unique_ptr<Net::AsyncSocket>&& socket)
: IAsyncDestructible(ioc), Socket(std::move(socket)), NetInputPackets(1024)
{
assert(Socket.get());
try {
AM = AssetsManager::Create(ioc, "Cache");
asio::co_spawn(ioc, run(AUC.use()), asio::detached);
// TODO: добавить оптимизацию для подключения клиента к внутреннему серверу
} catch(const std::exception &exc) {
MAKE_ERROR("Ошибка инициализации обработчика объекта подключения к серверу:\n" << exc.what());
}
}
coro<> ServerSession::asyncDestructor() {
co_await IAsyncDestructible::asyncDestructor();
}
ParsedPacket::~ParsedPacket() = default;
struct PP_Content_ChunkVoxels : public ParsedPacket {
WorldId_t Id;
Pos::GlobalChunk Pos;
std::vector<VoxelCube> Cubes;
PP_Content_ChunkVoxels(WorldId_t id, Pos::GlobalChunk pos, std::vector<VoxelCube> &&cubes)
: ParsedPacket(ToClient::L1::Content, (uint8_t) ToClient::L2Content::ChunkVoxels), Id(id), Pos(pos), Cubes(std::move(cubes))
{}
};
struct PP_Content_ChunkNodes : public ParsedPacket {
WorldId_t Id;
Pos::GlobalChunk Pos;
std::array<Node, 16*16*16> Nodes;
PP_Content_ChunkNodes(WorldId_t id, Pos::GlobalChunk pos)
: ParsedPacket(ToClient::L1::Content, (uint8_t) ToClient::L2Content::ChunkNodes), Id(id), Pos(pos)
{
}
};
struct PP_Content_RegionRemove : public ParsedPacket {
WorldId_t Id;
Pos::GlobalRegion Pos;
PP_Content_RegionRemove(WorldId_t id, Pos::GlobalRegion pos)
: ParsedPacket(ToClient::L1::Content, (uint8_t) ToClient::L2Content::RemoveRegion), Id(id), Pos(pos)
{}
};
struct PP_Definition_Voxel : public ParsedPacket {
DefVoxelId Id;
DefVoxel_t Def;
PP_Definition_Voxel(DefVoxelId id, DefVoxel_t def)
: ParsedPacket(ToClient::L1::Definition, (uint8_t) ToClient::L2Definition::Voxel),
Id(id), Def(def)
{}
};
struct PP_Definition_FreeVoxel : public ParsedPacket {
DefVoxelId Id;
PP_Definition_FreeVoxel(DefVoxelId id)
: ParsedPacket(ToClient::L1::Definition, (uint8_t) ToClient::L2Definition::FreeVoxel),
Id(id)
{}
};
struct PP_Definition_Node : public ParsedPacket {
DefNodeId Id;
DefNode_t Def;
PP_Definition_Node(DefNodeId id, DefNode_t def)
: ParsedPacket(ToClient::L1::Definition, (uint8_t) ToClient::L2Definition::Node),
Id(id), Def(def)
{}
};
struct PP_Definition_FreeNode : public ParsedPacket {
DefNodeId Id;
PP_Definition_FreeNode(DefNodeId id)
: ParsedPacket(ToClient::L1::Definition, (uint8_t) ToClient::L2Definition::FreeNode),
Id(id)
{}
};
using namespace TOS;
ServerSession::~ServerSession() {
}
coro<> ServerSession::asyncAuthorizeWithServer(tcp::socket &socket, const std::string username, const std::string token, int a_ar_r, std::function<void(const std::string&)> onProgress) {
assert(a_ar_r >= 0 && a_ar_r <= 2);
std::string progress;
auto addLog = [&](const std::string &msg) {
progress += '\n';
progress += msg;
if(onProgress)
onProgress('\n'+msg);
};
if(username.size() > 255) {
addLog("Имя пользователя слишком велико (>255)");
MAKE_ERROR(progress);
}
if(token.size() > 255) {
addLog("Пароль слишком велик (>255)");
MAKE_ERROR(progress);
}
Net::Packet packet;
packet.write((const std::byte*) "AlterLuanti", 11);
packet << uint8_t(0) << uint8_t(a_ar_r) << username << token;
addLog("Отправляем первый пакет, авторизация или регистрация");
co_await packet.sendAndFastClear(socket);
addLog("Ожидаем код ответа");
uint8_t code = co_await Net::AsyncSocket::read<uint8_t>(socket);
if(code == 0) {
addLog("Код = Авторизированы");
} else if(code == 1) {
addLog("Код = Зарегистрированы и авторизированы");
} else if(code == 2 || code == 3) {
if(code == 2)
addLog("Код = Не удалось зарегистрироваться");
else
addLog("Код = Не удалось авторизоваться");
std::string reason = co_await Net::AsyncSocket::read<std::string>(socket);
addLog(reason);
if(code == 2)
MAKE_ERROR("Не удалось зарегистрироваться, причина: " << reason);
else
MAKE_ERROR("Не удалось авторизоваться, причина: " << reason);
} else {
addLog("Получен неизвестный код ответа (может это не игровой сервер?), прерываем");
MAKE_ERROR(progress);
}
}
coro<std::unique_ptr<Net::AsyncSocket>> ServerSession::asyncInitGameProtocol(asio::io_context &ioc, tcp::socket &&socket, std::function<void(const std::string&)> onProgress) {
std::string progress;
auto addLog = [&](const std::string &msg) {
progress += '\n';
progress += msg;
if(onProgress)
onProgress('\n'+msg);
};
addLog("Инициализируем игровой протокол");
uint8_t code = 0;
co_await Net::AsyncSocket::write<>(socket, code);
asio::deadline_timer timer(socket.get_executor());
while(true) {
code = co_await Net::AsyncSocket::read<uint8_t>(socket);
if(code == 0) {
addLog("Код = Успешно");
break;
} else if(code == 1) {
addLog("Код = Ошибка с причиной");
addLog(co_await Net::AsyncSocket::read<std::string>(socket));
MAKE_ERROR(progress);
} else if(code == 2) {
addLog("Код = Подождать 4 секунды");
timer.expires_from_now(boost::posix_time::seconds(4));
co_await timer.async_wait();
addLog("Ожидаем новый код");
} else {
addLog("Получен неизвестный код ответа (может это не игровой сервер?), прерываем");
MAKE_ERROR(progress);
}
}
co_return std::make_unique<Net::AsyncSocket>(ioc, std::move(socket));
}
void ServerSession::shutdown(EnumDisconnect type) {
IsGoingShutdown = true;
Socket->closeRead();
Net::Packet packet;
packet << (uint8_t) ToServer::L1::System
<< (uint8_t) ToServer::L2System::Disconnect
<< (uint8_t) type;
Socket->pushPacket(std::move(packet));
std::string reason;
if(type == EnumDisconnect::ByInterface)
reason = "по запросу интерфейса";
else if(type == EnumDisconnect::CriticalError)
reason = "на сервере произошла критическая ошибка";
else if(type == EnumDisconnect::ProtocolError)
reason = "ошибка протокола (клиент)";
LOG.info() << "Отключение от сервера: " << reason;
}
void ServerSession::onResize(uint32_t width, uint32_t height) {
}
void ServerSession::onChangeFocusState(bool isFocused) {
if(!isFocused)
CursorMode = EnumCursorMoveMode::Default;
}
void ServerSession::onCursorPosChange(int32_t width, int32_t height) {
}
void ServerSession::onCursorMove(float xMove, float yMove) {
xMove /= 10.f;
yMove /= 10.f;
glm::vec3 deltaPYR;
static constexpr float PI = glm::pi<float>(), PI2 = PI*2, PI_HALF = PI/2, PI_DEG = PI/180;
deltaPYR.x = std::clamp(PYR.x - yMove*PI_DEG, -PI_HALF+PI_DEG, PI_HALF-PI_DEG)-PYR.x;
deltaPYR.y = std::fmod(PYR.y - xMove*PI_DEG, PI2)-PYR.y;
deltaPYR.z = 0;
double gTime = GTime;
float deltaTime = 1-std::min<float>(gTime-PYR_At, 1/PYR_TIME_DELTA)*PYR_TIME_DELTA;
PYR_At = GTime;
PYR += deltaPYR;
PYR_Offset = deltaPYR+deltaTime*PYR_Offset;
}
void ServerSession::onCursorBtn(ISurfaceEventListener::EnumCursorBtn btn, bool state) {
if(!state)
return;
if(btn == EnumCursorBtn::Left) {
Net::Packet packet;
packet << (uint8_t) ToServer::L1::System
<< (uint8_t) ToServer::L2System::BlockChange
<< uint8_t(0);
Socket->pushPacket(std::move(packet));
} else if(btn == EnumCursorBtn::Right) {
Net::Packet packet;
packet << (uint8_t) ToServer::L1::System
<< (uint8_t) ToServer::L2System::BlockChange
<< uint8_t(1);
Socket->pushPacket(std::move(packet));
}
}
void ServerSession::onKeyboardBtn(int btn, int state) {
if(btn == GLFW_KEY_TAB && !state) {
CursorMode = CursorMode == EnumCursorMoveMode::Default ? EnumCursorMoveMode::MoveAndHidden : EnumCursorMoveMode::Default;
Keys.clear();
}
if(CursorMode == EnumCursorMoveMode::MoveAndHidden)
{
if(btn == GLFW_KEY_W)
Keys.W = state;
else if(btn == GLFW_KEY_A)
Keys.A = state;
else if(btn == GLFW_KEY_S)
Keys.S = state;
else if(btn == GLFW_KEY_D)
Keys.D = state;
else if(btn == GLFW_KEY_LEFT_SHIFT)
Keys.SHIFT = state;
else if(btn == GLFW_KEY_SPACE)
Keys.SPACE = state;
else if(btn == GLFW_KEY_LEFT_CONTROL)
Keys.CTRL = state;
}
}
void ServerSession::onJoystick() {
}
void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) {
GTime = gTime;
Pos += glm::vec3(Speed) * dTime;
Speed -= glm::dvec3(Speed) * double(dTime);
glm::mat4 rot(1);
float deltaTime = 1-std::min<float>(gTime-PYR_At, 1/PYR_TIME_DELTA)*PYR_TIME_DELTA;
rot = glm::rotate(rot, PYR.y-deltaTime*PYR_Offset.y, {0, 1, 0});
float mltpl = 16*dTime*Pos::Object_t::BS;
if(Keys.CTRL)
mltpl *= 16;
Speed += glm::vec3(rot*glm::vec4(0, 0, -1, 1)*float(Keys.W))*mltpl;
Speed += glm::vec3(rot*glm::vec4(-1, 0, 0, 1)*float(Keys.A))*mltpl;
Speed += glm::vec3(rot*glm::vec4(0, 0, 1, 1)*float(Keys.S))*mltpl;
Speed += glm::vec3(rot*glm::vec4(1, 0, 0, 1)*float(Keys.D))*mltpl;
Speed += glm::vec3(0, -1, 0)*float(Keys.SHIFT)*mltpl;
Speed += glm::vec3(0, 1, 0)*float(Keys.SPACE)*mltpl;
{
std::unordered_map<WorldId_t, std::tuple<std::unordered_set<Pos::GlobalChunk>, std::unordered_set<Pos::GlobalRegion>>> changeOrAddList_removeList;
std::unordered_map<EnumDefContent, std::vector<ResourceId>> onContentDefinesAdd;
std::unordered_map<EnumDefContent, std::vector<ResourceId>> onContentDefinesLost;
// Пакеты
ParsedPacket *pack;
while(NetInputPackets.pop(pack)) {
if(pack->Level1 == ToClient::L1::Definition) {
ToClient::L2Definition l2 = ToClient::L2Definition(pack->Level2);
if(l2 == ToClient::L2Definition::Voxel) {
PP_Definition_Voxel &p = *dynamic_cast<PP_Definition_Voxel*>(pack);
Registry.DefVoxel[p.Id] = p.Def;
onContentDefinesAdd[EnumDefContent::Voxel].push_back(p.Id);
} else if(l2 == ToClient::L2Definition::FreeVoxel) {
PP_Definition_FreeVoxel &p = *dynamic_cast<PP_Definition_FreeVoxel*>(pack);
{
auto iter = Registry.DefVoxel.find(p.Id);
if(iter != Registry.DefVoxel.end())
Registry.DefVoxel.erase(iter);
}
onContentDefinesLost[EnumDefContent::Voxel].push_back(p.Id);
} else if(l2 == ToClient::L2Definition::Node) {
PP_Definition_Node &p = *dynamic_cast<PP_Definition_Node*>(pack);
Registry.DefNode[p.Id] = p.Def;
onContentDefinesAdd[EnumDefContent::Node].push_back(p.Id);
} else if(l2 == ToClient::L2Definition::FreeNode) {
PP_Definition_FreeNode &p = *dynamic_cast<PP_Definition_FreeNode*>(pack);
{
auto iter = Registry.DefNode.find(p.Id);
if(iter != Registry.DefNode.end())
Registry.DefNode.erase(iter);
}
onContentDefinesLost[EnumDefContent::Node].push_back(p.Id);
}
} else if(pack->Level1 == ToClient::L1::Content) {
ToClient::L2Content l2 = ToClient::L2Content(pack->Level2);
if(l2 == ToClient::L2Content::ChunkVoxels) {
PP_Content_ChunkVoxels &p = *dynamic_cast<PP_Content_ChunkVoxels*>(pack);
Pos::GlobalRegion rPos = p.Pos >> 2;
Pos::bvec4u cPos = p.Pos & 0x3;
Data.Worlds[p.Id].Regions[rPos].Chunks[cPos.pack()].Voxels = std::move(p.Cubes);
auto &pair = changeOrAddList_removeList[p.Id];
std::get<0>(pair).insert(p.Pos);
} else if(l2 == ToClient::L2Content::ChunkNodes) {
PP_Content_ChunkNodes &p = *dynamic_cast<PP_Content_ChunkNodes*>(pack);
Pos::GlobalRegion rPos = p.Pos >> 2;
Pos::bvec4u cPos = p.Pos & 0x3;
Node *nodes = (Node*) Data.Worlds[p.Id].Regions[rPos].Chunks[cPos.pack()].Nodes.data();
std::copy(p.Nodes.begin(), p.Nodes.end(), nodes);
auto &pair = changeOrAddList_removeList[p.Id];
std::get<0>(pair).insert(p.Pos);
} else if(l2 == ToClient::L2Content::RemoveRegion) {
PP_Content_RegionRemove &p = *dynamic_cast<PP_Content_RegionRemove*>(pack);
auto &regions = Data.Worlds[p.Id].Regions;
auto obj = regions.find(p.Pos);
if(obj != regions.end()) {
regions.erase(obj);
auto &pair = changeOrAddList_removeList[p.Id];
std::get<1>(pair).insert(p.Pos);
}
}
}
delete pack;
}
if(RS && !changeOrAddList_removeList.empty()) {
for(auto &pair : changeOrAddList_removeList) {
// Если случится что чанк был изменён и удалён, то исключаем его обновления
for(Pos::GlobalRegion removed : std::get<1>(pair.second)) {
Pos::GlobalChunk pos = removed << 2;
for(int z = 0; z < 4; z++)
for(int y = 0; y < 4; y++)
for(int x = 0; x < 4; x++) {
std::get<0>(pair.second).erase(pos+Pos::GlobalChunk(x, y, z));
}
}
RS->onChunksChange(pair.first, std::get<0>(pair.second), std::get<1>(pair.second));
}
if(!onContentDefinesAdd.empty()) {
RS->onContentDefinesAdd(std::move(onContentDefinesAdd));
}
if(!onContentDefinesLost.empty()) {
RS->onContentDefinesLost(std::move(onContentDefinesLost));
}
}
}
// Расчёт камеры
{
float deltaTime = 1-std::min<float>(gTime-PYR_At, 1/PYR_TIME_DELTA)*PYR_TIME_DELTA;
glm::quat quat =
glm::angleAxis(PYR.x-deltaTime*PYR_Offset.x, glm::vec3(1.f, 0.f, 0.f))
*
glm::angleAxis(PYR.y-deltaTime*PYR_Offset.y, glm::vec3(0.f, -1.f, 0.f));
quat = glm::normalize(quat);
if(RS)
RS->setCameraPos(0, Pos, quat);
// Отправка текущей позиции камеры
if(gTime-LastSendPYR_POS > 1/20.f)
{
LastSendPYR_POS = gTime;
Net::Packet packet;
ToServer::PacketQuat q;
q.fromQuat(glm::inverse(quat));
packet << (uint8_t) ToServer::L1::System
<< (uint8_t) ToServer::L2System::Test_CAM_PYR_POS
<< Pos.x << Pos.y << Pos.z;
for(int iter = 0; iter < 5; iter++)
packet << q.Data[iter];
Socket->pushPacket(std::move(packet));
}
}
}
void ServerSession::setRenderSession(IRenderSession* session) {
RS = session;
}
coro<> ServerSession::run(AsyncUseControl::Lock) {
try {
while(!IsGoingShutdown && IsConnected) {
co_await readPacket(*Socket);
}
} catch(const std::exception &exc) {
LOG.error() << "Ошибка обработки сокета:\n" << exc.what();
}
IsConnected = false;
co_return;
}
void ServerSession::protocolError() {
shutdown(EnumDisconnect::ProtocolError);
}
coro<> ServerSession::readPacket(Net::AsyncSocket &sock) {
uint8_t first = co_await sock.read<uint8_t>();
switch((ToClient::L1) first) {
case ToClient::L1::System: co_await rP_System(sock); co_return;
case ToClient::L1::Resource: co_await rP_Resource(sock); co_return;
case ToClient::L1::Definition: co_await rP_Definition(sock); co_return;
case ToClient::L1::Content: co_await rP_Content(sock); co_return;
default:
protocolError();
}
}
coro<> ServerSession::rP_System(Net::AsyncSocket &sock) {
uint8_t second = co_await sock.read<uint8_t>();
switch((ToClient::L2System) second) {
case ToClient::L2System::Init:
co_return;
case ToClient::L2System::Disconnect:
{
EnumDisconnect type = (EnumDisconnect) co_await sock.read<uint8_t>();
std::string reason = co_await sock.read<std::string>();
if(type == EnumDisconnect::ByInterface)
reason = "по запросу интерфейса " + reason;
else if(type == EnumDisconnect::CriticalError)
reason = "на сервере произошла критическая ошибка " + reason;
else if(type == EnumDisconnect::ProtocolError)
reason = "ошибка протокола (сервер) " + reason;
LOG.info() << "Отключение от сервера: " << reason;
co_return;
}
case ToClient::L2System::LinkCameraToEntity:
co_return;
case ToClient::L2System::UnlinkCamera:
co_return;
default:
protocolError();
}
}
coro<> ServerSession::rP_Resource(Net::AsyncSocket &sock) {
uint8_t second = co_await sock.read<uint8_t>();
switch((ToClient::L2Resource) second) {
case ToClient::L2Resource::Bind:
{
uint32_t count = co_await sock.read<uint32_t>();
AsyncContext.ThisTickEntry.AssetsBinds.reserve(AsyncContext.ThisTickEntry.AssetsBinds.size()+count);
for(size_t iter = 0; iter < count; iter++) {
uint8_t type = co_await sock.read<uint8_t>();
uint32_t id = co_await sock.read<uint32_t>();
std::string domain, key;
domain = co_await sock.read<std::string>();
key = co_await sock.read<std::string>();
Hash_t hash;
co_await sock.read((std::byte*) hash.data(), hash.size());
AsyncContext.ThisTickEntry.AssetsBinds.emplace_back(
(EnumAssets) type, (ResourceId) id, std::move(domain),
std::move(key), hash
);
}
}
case ToClient::L2Resource::Lost:
{
uint32_t count = co_await sock.read<uint32_t>();
AsyncContext.ThisTickEntry.AssetsLost.reserve(AsyncContext.ThisTickEntry.AssetsLost.size()+count);
for(size_t iter = 0; iter < count; iter++) {
// uint8_t type = co_await sock.read<uint8_t>();
uint32_t id = co_await sock.read<uint32_t>();
AsyncContext.ThisTickEntry.AssetsLost.push_back(id);
}
}
case ToClient::L2Resource::InitResSend:
{
uint32_t size = co_await sock.read<uint32_t>();
Hash_t hash;
co_await sock.read((std::byte*) hash.data(), hash.size());
ResourceId id = co_await sock.read<uint32_t>();
EnumAssets type = (EnumAssets) co_await sock.read<uint8_t>();
std::string domain = co_await sock.read<std::string>();
std::string key = co_await sock.read<std::string>();
AsyncContext.AssetsLoading[hash] = AssetLoading{
type, id, std::move(domain), std::move(key),
std::u8string(size, '\0'), 0
};
co_return;
}
case ToClient::L2Resource::ChunkSend:
{
Hash_t hash;
co_await sock.read((std::byte*) hash.data(), hash.size());
uint32_t size = co_await sock.read<uint32_t>();
AssetLoading& al = AsyncContext.AssetsLoading.at(hash);
if(al.Data.size()-al.Offset < size)
MAKE_ERROR("Несоответствие ожидаемого размера ресурса");
co_await sock.read((std::byte*) al.Data.data() + al.Offset, size);
al.Offset += size;
if(al.Offset == al.Data.size()) {
// Ресурс полностью загружен
AsyncContext.LoadedAssets.lock()->emplace_back(
al.Type, al.Id, std::move(al.Domain), std::move(al.Key), std::move(al.Data)
);
AsyncContext.AssetsLoading.erase(AsyncContext.AssetsLoading.find(hash));
}
co_return;
}
default:
protocolError();
}
}
coro<> ServerSession::rP_Definition(Net::AsyncSocket &sock) {
uint8_t second = co_await sock.read<uint8_t>();
switch((ToClient::L2Definition) second) {
case ToClient::L2Definition::World: {
DefWorldId cdId = co_await sock.read<DefWorldId>();
co_return;
}
case ToClient::L2Definition::FreeWorld: {
DefWorldId cdId = co_await sock.read<DefWorldId>();
co_return;
}
case ToClient::L2Definition::Voxel: {
DefVoxelId cdId = co_await sock.read<DefVoxelId>();
co_return;
}
case ToClient::L2Definition::FreeVoxel: {
DefVoxelId cdId = co_await sock.read<DefVoxelId>();
co_return;
}
case ToClient::L2Definition::Node:
{
// DefNodeId id;
// DefNode_t def;
// id = co_await sock.read<DefNodeId>();
// def.DrawType = (DefNode_t::EnumDrawType) co_await sock.read<uint8_t>();
// for(int iter = 0; iter < 6; iter++) {
// auto &pl = def.Texs[iter].Pipeline;
// pl.resize(co_await sock.read<uint16_t>());
// co_await sock.read((std::byte*) pl.data(), pl.size());
// }
// PP_Definition_Node *packet = new PP_Definition_Node(
// id,
// def
// );
// while(!NetInputPackets.push(packet));
// co_return;
}
case ToClient::L2Definition::FreeNode:
{
DefNodeId id = co_await sock.read<DefNodeId>();
PP_Definition_FreeNode *packet = new PP_Definition_FreeNode(
id
);
while(!NetInputPackets.push(packet));
co_return;
}
case ToClient::L2Definition::Portal:
co_return;
case ToClient::L2Definition::FreePortal:
co_return;
case ToClient::L2Definition::Entity:
co_return;
case ToClient::L2Definition::FreeEntity:
co_return;
default:
protocolError();
}
}
coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) {
uint8_t second = co_await sock.read<uint8_t>();
switch((ToClient::L2Content) second) {
case ToClient::L2Content::World:
co_return;
case ToClient::L2Content::RemoveWorld:
co_return;
case ToClient::L2Content::Portal:
co_return;
case ToClient::L2Content::RemovePortal:
co_return;
case ToClient::L2Content::Entity:
co_return;
case ToClient::L2Content::RemoveEntity:
co_return;
case ToClient::L2Content::ChunkVoxels:
{
WorldId_t wcId = co_await sock.read<WorldId_t>();
Pos::GlobalChunk pos;
pos.unpack(co_await sock.read<Pos::GlobalChunk::Pack>());
uint32_t compressedSize = co_await sock.read<uint32_t>();
assert(compressedSize <= std::pow(2, 24));
std::u8string compressed(compressedSize, '\0');
co_await sock.read((std::byte*) compressed.data(), compressedSize);
PP_Content_ChunkVoxels *packet = new PP_Content_ChunkVoxels(
wcId,
pos,
unCompressVoxels(compressed) // TODO: вынести в отдельный поток
);
while(!NetInputPackets.push(packet));
co_return;
}
case ToClient::L2Content::ChunkNodes:
{
WorldId_t wcId = co_await sock.read<WorldId_t>();
Pos::GlobalChunk pos;
pos.unpack(co_await sock.read<Pos::GlobalChunk::Pack>());
uint32_t compressedSize = co_await sock.read<uint32_t>();
assert(compressedSize <= std::pow(2, 24));
std::u8string compressed(compressedSize, '\0');
co_await sock.read((std::byte*) compressed.data(), compressedSize);
PP_Content_ChunkNodes *packet = new PP_Content_ChunkNodes(
wcId,
pos
);
unCompressNodes(compressed, (Node*) packet->Nodes.data()); // TODO: вынести в отдельный поток
while(!NetInputPackets.push(packet));
co_return;
}
case ToClient::L2Content::ChunkLightPrism:
co_return;
case ToClient::L2Content::RemoveRegion: {
WorldId_t wcId = co_await sock.read<WorldId_t>();
Pos::GlobalRegion pos;
pos.unpack(co_await sock.read<Pos::GlobalRegion::Pack>());
PP_Content_RegionRemove *packet = new PP_Content_RegionRemove(
wcId,
pos
);
while(!NetInputPackets.push(packet));
co_return;
}
default:
protocolError();
}
}
}