From 8fe8057d9cd4fa72a6bd3fce91de3ac7717c9abd Mon Sep 17 00:00:00 2001 From: DrSocalkwe3n Date: Mon, 7 Jul 2025 18:42:52 +0600 Subject: [PATCH] * --- Src/Client/Abstract.hpp | 18 --- Src/Client/ServerSession.cpp | 50 +++----- Src/Client/Vulkan/Vulkan.cpp | 7 +- Src/Client/Vulkan/VulkanRenderSession.cpp | 49 +++---- Src/Common/Abstract.cpp | 24 ++-- Src/Common/Net.cpp | 3 + Src/Server/GameServer.cpp | 149 +++++++++++++++------- Src/Server/GameServer.hpp | 75 ++++++++--- Src/Server/RemoteClient.cpp | 4 +- Src/Server/World.cpp | 4 - 10 files changed, 227 insertions(+), 156 deletions(-) diff --git a/Src/Client/Abstract.hpp b/Src/Client/Abstract.hpp index 1a78ec6..29c6bf1 100644 --- a/Src/Client/Abstract.hpp +++ b/Src/Client/Abstract.hpp @@ -33,24 +33,6 @@ struct GlobalTime { } }; -struct VoxelCube { - union { - struct { - DefVoxelId_t VoxelId : 24, Meta : 8; - }; - DefVoxelId_t Data; - }; - Pos::bvec256u Left, Size; -}; - -union Node { - struct { - DefNodeId_t NodeId : 24, Meta : 8; - }; - - DefNodeId_t Data; -}; - // 16 метров ребро // 256 вокселей ребро struct Chunk { diff --git a/Src/Client/ServerSession.cpp b/Src/Client/ServerSession.cpp index 914bb17..d445c15 100644 --- a/Src/Client/ServerSession.cpp +++ b/Src/Client/ServerSession.cpp @@ -34,10 +34,9 @@ struct PP_Content_ChunkNodes : public ParsedPacket { Pos::GlobalChunk Pos; Node Nodes[16][16][16]; - PP_Content_ChunkNodes(ToClient::L1 l1, uint8_t l2, WorldId_t id, Pos::GlobalChunk pos, Node* nodes) + PP_Content_ChunkNodes(ToClient::L1 l1, uint8_t l2, WorldId_t id, Pos::GlobalChunk pos) : ParsedPacket(l1, l2), Id(id), Pos(pos) { - std::copy(nodes, nodes+16*16*16, (Node*) Nodes); } }; @@ -281,14 +280,14 @@ void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) { 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(pack); - Pos::GlobalRegion rPos = p.Pos >> 2; - Pos::bvec4u cPos = p.Pos & 0x3; + // PP_Content_ChunkNodes &p = *dynamic_cast(pack); + // Pos::GlobalRegion rPos = p.Pos >> 2; + // Pos::bvec4u cPos = p.Pos & 0x3; - Node *nodes = (Node*) Data.Worlds[p.Id].Regions[rPos].Chunks[cPos.x][cPos.y][cPos.z].Nodes; - std::copy((const Node*)p.Nodes, ((const Node*) p.Nodes)+16*16*16, nodes); - auto &pair = changeOrAddList_removeList[p.Id]; - std::get<0>(pair).insert(p.Pos); + // Node *nodes = (Node*) Data.Worlds[p.Id].Regions[rPos].Chunks[cPos.x][cPos.y][cPos.z].Nodes; + // std::copy((const Node*) p.Nodes, ((const Node*) p.Nodes)+16*16*16, 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(pack); @@ -532,25 +531,17 @@ coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) { Pos::GlobalChunk pos; pos.unpack(co_await sock.read()); - std::vector cubes(co_await sock.read()); - - for(size_t iter = 0; iter < cubes.size(); iter++) { - VoxelCube &cube = cubes[iter]; - cube.Data = co_await sock.read(); - cube.Left.x = co_await sock.read(); - cube.Left.y = co_await sock.read(); - cube.Left.z = co_await sock.read(); - cube.Size.x = co_await sock.read(); - cube.Size.y = co_await sock.read(); - cube.Size.z = co_await sock.read(); - } + uint32_t compressedSize = co_await sock.read(); + 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( ToClient::L1::Content, (uint8_t) ToClient::L2Content::ChunkVoxels, wcId, pos, - std::move(cubes) + unCompressVoxels(compressed) ); while(!NetInputPackets.push(packet)); @@ -563,20 +554,21 @@ coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) { WorldId_t wcId = co_await sock.read(); Pos::GlobalChunk pos; pos.unpack(co_await sock.read()); - std::array nodes; - for(Node& node : nodes) { - node.Data = co_await sock.read(); - } + uint32_t compressedSize = co_await sock.read(); + 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( ToClient::L1::Content, - (uint8_t) ToClient::L2Content::ChunkVoxels, + (uint8_t) ToClient::L2Content::ChunkNodes, wcId, - pos, - nodes.data() + pos ); + unCompressNodes(compressed, (Node*) packet->Nodes); + while(!NetInputPackets.push(packet)); co_return; diff --git a/Src/Client/Vulkan/Vulkan.cpp b/Src/Client/Vulkan/Vulkan.cpp index 80f4d26..b01f9fc 100644 --- a/Src/Client/Vulkan/Vulkan.cpp +++ b/Src/Client/Vulkan/Vulkan.cpp @@ -93,6 +93,11 @@ Vulkan::Vulkan(asio::io_context &ioc) LOG.error() << "Vulkan::run: " << exc.what(); } + try { + if(Graphics.Window) + glfwSetWindowAttrib(Graphics.Window, GLFW_VISIBLE, false); + } catch(...) {} + try { Game.RSession = nullptr; } catch(const std::exception &exc) { LOG.error() << "Game.RSession = nullptr: " << exc.what(); } @@ -3832,7 +3837,7 @@ void AtlasImage::atlasChangeTextureData(uint16_t id, const uint32_t *rgba) InfoSubTexture *info = const_cast(atlasGetTextureInfo(id)); auto iter = CachedData.find(id); - // Если есть данные в кэше, то меняем их + // Если есть данные в кеше, то меняем их if(iter != CachedData.end()) { if(iter->second.size() == 0) diff --git a/Src/Client/Vulkan/VulkanRenderSession.cpp b/Src/Client/Vulkan/VulkanRenderSession.cpp index 6603b63..6a3c18b 100644 --- a/Src/Client/Vulkan/VulkanRenderSession.cpp +++ b/Src/Client/Vulkan/VulkanRenderSession.cpp @@ -2,6 +2,7 @@ #include "Client/Abstract.hpp" #include "Client/Vulkan/Vulkan.hpp" #include "Common/Abstract.hpp" +#include "TOSLib.hpp" #include "assets.hpp" #include "glm/ext/matrix_transform.hpp" #include "glm/trigonometric.hpp" @@ -198,10 +199,10 @@ void VulkanRenderSession::init(Vulkan *instance) { int width, height; bool hasAlpha; for(const char *path : { - "grass.png", - "tropical_rainforest_wood.png", - "willow_wood.png", - "xnether_blue_wood.png", + //"tropical_rainforest_wood.png", + "grass.png", + "willow_wood.png", + //"xnether_blue_wood.png", "xnether_purple_wood.png" }) { ByteBuffer image = VK::loadPNG(getResource(std::string("textures/") + path)->makeStream().Stream, width, height, hasAlpha); @@ -612,7 +613,7 @@ void VulkanRenderSession::onContentDefinesLost(std::unordered_map& changeOrAddList, const std::unordered_set& remove) { -auto &table = External.ChunkVoxelMesh[worldId]; + auto &table = External.ChunkVoxelMesh[worldId]; for(Pos::GlobalChunk pos : changeOrAddList) { Pos::GlobalRegion rPos = pos >> 4; @@ -625,7 +626,9 @@ auto &table = External.ChunkVoxelMesh[worldId]; if(iter != table.end()) table.erase(iter); } else { + Logger("Test").debug() << voxels.size(); std::vector vertexs = generateMeshForVoxelChunks(voxels); + Logger("Test").debug() << vertexs.size(); if(!vertexs.empty()) { auto &buffer = table[pos] = std::make_unique(VkInst, vertexs.size()*sizeof(VoxelVertexPoint)); @@ -743,9 +746,9 @@ std::vector VulkanRenderSession::generateMeshForVoxelChunks(co for(const VoxelCube &cube : cubes) { out.emplace_back( - cube.Left.x, - cube.Left.y, - cube.Left.z, + cube.Pos.x, + cube.Pos.y, + cube.Pos.z, 0, 0, 0, cube.Size.x, @@ -756,9 +759,9 @@ std::vector VulkanRenderSession::generateMeshForVoxelChunks(co ); out.emplace_back( - cube.Left.x, - cube.Left.y, - cube.Left.z, + cube.Pos.x, + cube.Pos.y, + cube.Pos.z, 1, 0, 0, cube.Size.x, @@ -769,9 +772,9 @@ std::vector VulkanRenderSession::generateMeshForVoxelChunks(co ); out.emplace_back( - cube.Left.x, - cube.Left.y, - cube.Left.z, + cube.Pos.x, + cube.Pos.y, + cube.Pos.z, 2, 0, 0, cube.Size.z, @@ -782,9 +785,9 @@ std::vector VulkanRenderSession::generateMeshForVoxelChunks(co ); out.emplace_back( - cube.Left.x, - cube.Left.y+cube.Size.y+1, - cube.Left.z, + cube.Pos.x, + cube.Pos.y+cube.Size.y+1, + cube.Pos.z, 3, 0, 0, cube.Size.x, @@ -795,9 +798,9 @@ std::vector VulkanRenderSession::generateMeshForVoxelChunks(co ); out.emplace_back( - cube.Left.x, - cube.Left.y, - cube.Left.z+cube.Size.z+1, + cube.Pos.x, + cube.Pos.y, + cube.Pos.z+cube.Size.z+1, 4, 0, 0, cube.Size.x, @@ -808,9 +811,9 @@ std::vector VulkanRenderSession::generateMeshForVoxelChunks(co ); out.emplace_back( - cube.Left.x+cube.Size.x+1, - cube.Left.y, - cube.Left.z, + cube.Pos.x+cube.Size.x+1, + cube.Pos.y, + cube.Pos.z, 5, 0, 0, cube.Size.z, diff --git a/Src/Common/Abstract.cpp b/Src/Common/Abstract.cpp index 0bffc87..7d659a9 100644 --- a/Src/Common/Abstract.cpp +++ b/Src/Common/Abstract.cpp @@ -456,8 +456,8 @@ CompressedNodes compressNodes_byte(const Node* nodes) { // Количество байт на идентификатор в сыром виде - uint8_t bytes_raw_profile = std::ceil(std::log2(maxValueProfile)/8); - assert(bytes_raw_profile >= 1 && bytes_raw_profile <= 3); + uint8_t bytes_raw_profile = std::ceil(std::log2(maxValueProfile+1)/8); + assert(bytes_raw_profile >= 0 && bytes_raw_profile <= 3); // Количество байт на индекс uint8_t bytes_indices_profile = std::ceil(std::log2(profiles.size())/8); assert(bytes_indices_profile >= 1 && bytes_indices_profile <= 2); @@ -473,7 +473,8 @@ CompressedNodes compressNodes_byte(const Node* nodes) { compressed.push_back((profiles.size() >> 16) & 0xff); for(DefNodeId_t id : profiles) { - compressed.push_back(id & 0xff); + if(bytes_raw_profile > 0) + compressed.push_back(id & 0xff); if(bytes_raw_profile > 1) compressed.push_back((id >> 8) & 0xff); if(bytes_raw_profile > 2) @@ -495,7 +496,8 @@ CompressedNodes compressNodes_byte(const Node* nodes) { for(size_t iter = 0; iter < 16*16*16; iter++) { const Node &node = nodes[iter]; - compressed.push_back(node.NodeId & 0xff); + if(bytes_raw_profile > 0) + compressed.push_back(node.NodeId & 0xff); if(bytes_raw_profile > 1) compressed.push_back((node.NodeId >> 8) & 0xff); if(bytes_raw_profile > 2) @@ -553,7 +555,7 @@ CompressedNodes compressNodes_bit(const Node* nodes) { // Количество бит на идентификатор в сыром виде - uint8_t bits_raw_profile = std::ceil(std::log2(maxValueProfile)); + uint8_t bits_raw_profile = std::ceil(std::log2(maxValueProfile+1)); assert(bits_raw_profile >= 1 && bits_raw_profile <= 24); // Количество бит на индекс uint8_t bits_indices_profile = std::ceil(std::log2(profiles.size())); @@ -575,7 +577,7 @@ CompressedNodes compressNodes_bit(const Node* nodes) { write(bits_indices_profile, 4); // Количество бит на идентификатор в сыром виде - uint8_t bits_raw_meta = std::ceil(std::log2(maxValueMeta)); + uint8_t bits_raw_meta = std::ceil(std::log2(maxValueMeta+1)); assert(bits_raw_meta >= 1 && bits_raw_meta <= 8); // Количество бит на индекс uint8_t bits_indices_meta = std::ceil(std::log2(meta.size())); @@ -655,8 +657,10 @@ void unCompressNodes_byte(const std::u8string& compressed, Node* ptr) { profiles.resize(read() | (read() << 8) | (read() << 16)); for(size_t iter = 0; iter < profiles.size(); iter++) { - DefNodeId_t id = read(); - + DefNodeId_t id = 0; + + if(bytes_raw_profile > 0) + id = read(); if(bytes_raw_profile > 1) id |= read() << 8; if(bytes_raw_profile > 2) @@ -677,8 +681,10 @@ void unCompressNodes_byte(const std::u8string& compressed, Node* ptr) { for(size_t iter = 0; iter < 16*16*16; iter++) { Node &node = ptr[iter]; - node.NodeId = read(); + node.NodeId = 0; + if(bytes_raw_profile > 0) + node.NodeId = read(); if(bytes_raw_profile > 1) node.NodeId |= read() << 8; if(bytes_raw_profile > 2) diff --git a/Src/Common/Net.cpp b/Src/Common/Net.cpp index 772d3be..229b1cc 100644 --- a/Src/Common/Net.cpp +++ b/Src/Common/Net.cpp @@ -43,6 +43,9 @@ AsyncSocket::~AsyncSocket() { } void AsyncSocket::pushPackets(std::vector *simplePackets, std::vector *smartPackets) { + if(simplePackets->empty() && (!smartPackets || smartPackets->empty())) + return; + boost::unique_lock lock(SendPackets.Mtx); if(Socket.is_open() diff --git a/Src/Server/GameServer.cpp b/Src/Server/GameServer.cpp index fd19aac..34dfe79 100644 --- a/Src/Server/GameServer.cpp +++ b/Src/Server/GameServer.cpp @@ -23,22 +23,42 @@ namespace LV::Server { +GameServer::GameServer(asio::io_context &ioc, fs::path worldPath) + : AsyncObject(ioc), + Content(ioc, nullptr, nullptr, nullptr, nullptr, nullptr) +{ + init(worldPath); + + BackingChunkPressure.Threads.resize(1); + BackingChunkPressure.Worlds = &Expanse.Worlds; + for(size_t iter = 0; iter < BackingChunkPressure.Threads.size(); iter++) { + BackingChunkPressure.Threads[iter] = std::thread(&BackingChunkPressure_t::run, &BackingChunkPressure, iter); + } + + BackingNoiseGenerator.Threads.resize(1); + for(size_t iter = 0; iter < BackingNoiseGenerator.Threads.size(); iter++) { + BackingNoiseGenerator.Threads[iter] = std::thread(&BackingNoiseGenerator_t::run, &BackingNoiseGenerator, iter); + } +} + GameServer::~GameServer() { shutdown("on ~GameServer"); - Backing.NeedShutdown = true; - Backing.Symaphore.notify_all(); + BackingChunkPressure.NeedShutdown = true; + BackingChunkPressure.Symaphore.notify_all(); + BackingNoiseGenerator.NeedShutdown = true; RunThread.join(); WorkDeadline.cancel(); UseLock.wait_no_use(); - Backing.stop(); + BackingChunkPressure.stop(); + BackingNoiseGenerator.stop(); LOG.info() << "Сервер уничтожен"; } void GameServer::BackingChunkPressure_t::run(int id) { - LOG.debug() << "Старт фонового потока " << id; + LOG.debug() << "Старт потока " << id; try { while(true) { @@ -46,7 +66,7 @@ void GameServer::BackingChunkPressure_t::run(int id) { std::unique_lock lock(Mutex); Symaphore.wait(lock, [&](){ return RunCollect != 0 || NeedShutdown; }); if(NeedShutdown) { - LOG.debug() << "Завершение выполнения фонового потока " << id; + LOG.debug() << "Завершение выполнения потока " << id; break; } } @@ -83,6 +103,7 @@ void GameServer::BackingChunkPressure_t::run(int id) { regionObj.IsChunkChanged_Nodes = 0; if(!regionObj.NewCECs.empty()) { + dumpRegion.CECs = regionObj.CECs; dumpRegion.NewCECs = std::move(regionObj.NewCECs); dumpRegion.Voxels = regionObj.Voxels; @@ -296,12 +317,58 @@ void GameServer::BackingChunkPressure_t::run(int id) { } catch(const std::exception& exc) { std::unique_lock lock(Mutex); NeedShutdown = true; - LOG.error() << "Ошибка выполнения фонового потока " << id << ":\n" << exc.what(); + LOG.error() << "Ошибка выполнения потока " << id << ":\n" << exc.what(); } Symaphore.notify_all(); } +void GameServer::BackingNoiseGenerator_t::run(int id) { + + LOG.debug() << "Старт потока " << id; + + try { + while(true) { + if(NeedShutdown) { + LOG.debug() << "Завершение выполнения потока " << id; + break; + } + + if(Input.get_read().empty()) + TOS::Time::sleep3(50); + + NoiseKey key; + + { + auto lock = Input.lock(); + if(lock->empty()) + continue; + + key = lock->front(); + lock->pop(); + } + + Pos::GlobalNode posNode = key.RegionPos; + posNode <<= 6; + + std::array data; + float *ptr = &data[0]; + + for(int z = 0; z < 64; z++) + for(int y = 0; y < 64; y++) + for(int x = 0; x < 64; x++, ptr++) { + *ptr = TOS::genRand(); //glm::perlin(glm::vec3(posNode.x+x, posNode.y+y, posNode.z+z)); + } + + Output.lock()->push_back({key, std::move(data)}); + } + } catch(const std::exception& exc) { + NeedShutdown = true; + LOG.error() << "Ошибка выполнения потока " << id << ":\n" << exc.what(); + } + +} + static thread_local std::vector TL_Circles; std::vector GameServer::Expanse_t::accumulateContentViewCircles(ContentViewCircle circle, int depth) @@ -596,6 +663,16 @@ void GameServer::run() { stepGlobalStep(); stepSyncContent(); + // Прочие моменты + if(!IsGoingShutdown) { + if(BackingChunkPressure.NeedShutdown + || BackingNoiseGenerator.NeedShutdown) + { + LOG.error() << "Ошибка работы одного из модулей"; + IsGoingShutdown = true; + } + } + // Сон или подгонка длительности такта при высоких нагрузках std::chrono::steady_clock::time_point atTickEnd = std::chrono::steady_clock::now(); float currentWastedTime = double((atTickEnd-atTickStart).count() * std::chrono::steady_clock::duration::period::num) / std::chrono::steady_clock::duration::period::den; @@ -629,7 +706,7 @@ void GameServer::stepConnections() { lock->clear(); } - Backing.endCollectChanges(); + BackingChunkPressure.endCollectChanges(); // Отключение игроков for(std::shared_ptr& cec : Game.CECs) { @@ -664,6 +741,7 @@ IWorldSaveBackend::TickSyncInfo_Out GameServer::stepDatabaseSync() { IWorldSaveBackend::TickSyncInfo_In toDB; for(std::shared_ptr& cec : Game.CECs) { + break; assert(cec); // Пересчитать зоны наблюдения if(cec->CrossedBorder) { @@ -754,55 +832,28 @@ void GameServer::stepGeneratorAndLuaAsync(IWorldSaveBackend::TickSyncInfo_Out db // Синхронизация с генератором шума - std::unordered_map>>> calculatedNoise; - for(auto& [worldId, regions] : db.NotExisten) { - auto &r = calculatedNoise[worldId]; - for(Pos::GlobalRegion pos : regions) { - if(IsGoingShutdown) - break; - - r.emplace_back(); - std::get<0>(r.back()) = pos; - auto ®ion = std::get<1>(r.back()); - Pos::GlobalNode posNode = pos; - posNode <<= 6; - - float *ptr = ®ion[0]; - - for(int z = 0; z < 64; z++) - for(int y = 0; y < 64; y++) - for(int x = 0; x < 64; x++, ptr++) { - *ptr = TOS::genRand(); //glm::perlin(glm::vec3(posNode.x+x, posNode.y+y, posNode.z+z)); - } - } - } - - if(IsGoingShutdown) - return; + std::vector>> calculatedNoise = BackingNoiseGenerator.tickSync(std::move(db.NotExisten)); std::unordered_map>> toLoadRegions; // Синхронизация с контроллером асинхронных обработчиков луа // 2.2 и 3.1 // Обработка шума - for(auto& [WorldId_t, regions] : calculatedNoise) { - auto &list = toLoadRegions[WorldId_t]; - - for(auto& [pos, noise] : regions) { - auto &obj = list.emplace_back(pos, World::RegionIn()).second; - - float *ptr = &noise[0]; + for(auto& [key, region] : calculatedNoise) { + LOG.debug() << "Сгенерирован " << key.WId << ' ' << key.RegionPos.x << ' ' + << key.RegionPos.y << ' ' << key.RegionPos.z; - for(int z = 0; z < 64; z++) - for(int y = 0; y < 64; y++) - for(int x = 0; x < 64; x++, ptr++) { - DefVoxelId_t id = *ptr > 0.5 ? 1 : 0; - Pos::bvec64u nodePos(x, y, z); - auto &node = obj.Nodes[Pos::bvec4u(nodePos >> 4).pack()][Pos::bvec16u(nodePos & 0xf).pack()]; - node.NodeId = id; - node.Meta = 0; - } + auto &obj = toLoadRegions[key.WId].emplace_back(key.RegionPos, World::RegionIn()).second; + float *ptr = ®ion[0]; + for(int z = 0; z < 64; z++) + for(int y = 0; y < 64; y++) + for(int x = 0; x < 64; x++, ptr++) { + DefVoxelId_t id = *ptr > 0.5 ? 1 : 0; + Pos::bvec64u nodePos(x, y, z); + auto &node = obj.Nodes[Pos::bvec4u(nodePos >> 4).pack()][Pos::bvec16u(nodePos & 0xf).pack()]; + node.NodeId = id; + node.Meta = 0; } } @@ -1349,7 +1400,7 @@ void GameServer::stepSyncContent() { full.insert(cec->Remote->pushPreparedPackets()); } - Backing.startCollectChanges(); + BackingChunkPressure.startCollectChanges(); full.uniq(); diff --git a/Src/Server/GameServer.hpp b/Src/Server/GameServer.hpp index e82382c..c76cf04 100644 --- a/Src/Server/GameServer.hpp +++ b/Src/Server/GameServer.hpp @@ -6,10 +6,12 @@ #include #include #include +#include "Common/Abstract.hpp" #include "RemoteClient.hpp" #include "Server/Abstract.hpp" #include #include +#include #include #include #include @@ -119,12 +121,6 @@ class GameServer : public AsyncObject { /* Обязательно между тактами - После окончания такта пул копирует изменённые чанки - - синхронизация сбора в stepDatabaseSync - - сжимает их и отправляет клиентам - - синхронизация в начале stepPlayerProceed - - ^ к этому моменту все данные должны быть отправлены - Далее при подписании на новые регионы они будут добавлены в пул на обработку Генерация шума OpenCL или пул @@ -139,6 +135,16 @@ class GameServer : public AsyncObject { Локальный поток должен собирать ключи профилей для базы Остальное внутри базы */ + + /* + Отправка изменений чанков клиентам + + После окончания такта пул копирует изменённые чанки + - синхронизация сбора в stepDatabaseSync - + сжимает их и отправляет клиентам + - синхронизация в начале stepPlayerProceed - + ^ к этому моменту все данные должны быть отправлены в RemoteClient + */ struct BackingChunkPressure_t { TOS::Logger LOG = "BackingChunkPressure"; bool NeedShutdown = false; @@ -176,25 +182,52 @@ class GameServer : public AsyncObject { } void run(int id); - } Backing; + } BackingChunkPressure; + + struct BackingNoiseGenerator_t { + struct NoiseKey { + WorldId_t WId; + Pos::GlobalRegion RegionPos; + }; + + TOS::Logger LOG = "BackingNoiseGenerator"; + bool NeedShutdown = false; + std::vector Threads; + TOS::SpinlockObject> Input; + TOS::SpinlockObject>>> Output; + + void stop() { + NeedShutdown = true; + + for(std::thread& thread : Threads) + thread.join(); + } + + void run(int id); + + std::vector>> + tickSync(std::unordered_map> &&input) { + { + auto lock = Input.lock(); + + for(auto& [worldId, region] : input) { + for(auto& regionPos : region) + lock->push({worldId, regionPos}); + } + } + + auto lock = Output.lock(); + std::vector>> out = std::move(*lock); + lock->reserve(8000); + + return std::move(out); + } + } BackingNoiseGenerator; public: - GameServer(asio::io_context &ioc, fs::path worldPath) - : AsyncObject(ioc), - Content(ioc, nullptr, nullptr, nullptr, nullptr, nullptr) - { - init(worldPath); - - Backing.Threads.resize(4); - Backing.Worlds = &Expanse.Worlds; - for(size_t iter = 0; iter < Backing.Threads.size(); iter++) { - Backing.Threads[iter] = std::thread(&BackingChunkPressure_t::run, &Backing, iter); - } - } - + GameServer(asio::io_context &ioc, fs::path worldPath); virtual ~GameServer(); - void shutdown(const std::string reason) { if(ShutdownReason.empty()) ShutdownReason = reason; diff --git a/Src/Server/RemoteClient.cpp b/Src/Server/RemoteClient.cpp index ffa629c..c46e0e2 100644 --- a/Src/Server/RemoteClient.cpp +++ b/Src/Server/RemoteClient.cpp @@ -137,7 +137,7 @@ bool RemoteClient::maybe_prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::Globa } } - checkPacketBorder(1+4+8+2+4+compressed_voxels.size()); + checkPacketBorder(4+4+8+2+4+compressed_voxels.size()); NextPacket << (uint8_t) ToClient::L1::Content << (uint8_t) ToClient::L2Content::ChunkVoxels << worldId << chunkPos.pack() << uint32_t(compressed_voxels.size()); @@ -211,7 +211,7 @@ bool RemoteClient::maybe_prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::Global } } - checkPacketBorder(1+4+8+4+compressed_nodes.size()); + checkPacketBorder(4+4+8+4+compressed_nodes.size()); NextPacket << (uint8_t) ToClient::L1::Content << (uint8_t) ToClient::L2Content::ChunkNodes << worldId << chunkPos.pack() << uint32_t(compressed_nodes.size()); diff --git a/Src/Server/World.cpp b/Src/Server/World.cpp index 2e42e0d..f924cb3 100644 --- a/Src/Server/World.cpp +++ b/Src/Server/World.cpp @@ -19,8 +19,6 @@ World::~World() { std::vector World::onCEC_RegionsEnter(std::shared_ptr cec, const std::vector& enter) { std::vector out; - TOS::Logger("Test").debug() << "Start"; - for(const Pos::GlobalRegion &pos : enter) { auto iterRegion = Regions.find(pos); if(iterRegion == Regions.end()) { @@ -48,8 +46,6 @@ std::vector World::onCEC_RegionsEnter(std::shared_ptr