From 70e3bf002680b9042982f970da232a841daa1a5d Mon Sep 17 00:00:00 2001 From: DrSocalkwe3n Date: Tue, 18 Feb 2025 15:48:32 +0600 Subject: [PATCH] - --- .gitignore | 1 + Src/Client/Abstract.hpp | 2 +- Src/Client/ServerSession.cpp | 85 +++++++++++++++++++---- Src/Client/ServerSession.hpp | 2 + Src/Client/Vulkan/Vulkan.cpp | 4 ++ Src/Client/Vulkan/VulkanRenderSession.cpp | 52 +++++++++++--- Src/Common/Packets.hpp | 3 +- Src/Server/ContentEventController.cpp | 6 +- Src/Server/GameServer.cpp | 61 +++++++++------- Src/Server/RemoteClient.cpp | 40 ++++++++--- Src/Server/RemoteClient.hpp | 3 + 11 files changed, 194 insertions(+), 65 deletions(-) diff --git a/.gitignore b/.gitignore index c3fc602..797818f 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ /libassets.a /resources.cpp /imgui.ini +/data diff --git a/Src/Client/Abstract.hpp b/Src/Client/Abstract.hpp index 429b202..ad4e157 100644 --- a/Src/Client/Abstract.hpp +++ b/Src/Client/Abstract.hpp @@ -11,7 +11,7 @@ namespace LV::Client { struct GlobalTime { - uint32_t Seconds : 22, Sub : 10; + uint32_t Seconds : 22 = 0, Sub : 10 = 0; GlobalTime() = default; GlobalTime(double gTime) { diff --git a/Src/Client/ServerSession.cpp b/Src/Client/ServerSession.cpp index dc49660..ac00f28 100644 --- a/Src/Client/ServerSession.cpp +++ b/Src/Client/ServerSession.cpp @@ -28,6 +28,15 @@ struct PP_Content_ChunkVoxels : public ParsedPacket { {} }; +struct PP_Content_ChunkRemove : public ParsedPacket { + WorldId_c Id; + Pos::GlobalChunk Pos; + + PP_Content_ChunkRemove(ToClient::L1 l1, uint8_t l2, WorldId_c id, Pos::GlobalChunk pos) + : ParsedPacket(l1, l2), Id(id), Pos(pos) + {} +}; + using namespace TOS; ServerSession::~ServerSession() { @@ -246,14 +255,30 @@ void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) { // Пакеты ParsedPacket *pack; while(NetInputPackets.pop(pack)) { - if(pack->Level1 == ToClient::L1::Content && ToClient::L2Content(pack->Level2) == ToClient::L2Content::ChunkVoxels) { - PP_Content_ChunkVoxels &p = *dynamic_cast(pack); - Pos::GlobalRegion rPos(p.Pos.X >> 4, p.Pos.Y >> 4, p.Pos.Z >> 4); - Pos::Local16_u cPos(p.Pos.X & 0xf, p.Pos.Y & 0xf, p.Pos.Z & 0xf); - External.Worlds[p.Id].Regions[rPos].Chunks[cPos].Voxels = std::move(p.Cubes); + if(pack->Level1 == ToClient::L1::Content) { + ToClient::L2Content l2 = ToClient::L2Content(pack->Level2); + if(l2 == ToClient::L2Content::ChunkVoxels) { + PP_Content_ChunkVoxels &p = *dynamic_cast(pack); + Pos::GlobalRegion rPos(p.Pos.X >> 4, p.Pos.Y >> 4, p.Pos.Z >> 4); + Pos::Local16_u cPos(p.Pos.X & 0xf, p.Pos.Y & 0xf, p.Pos.Z & 0xf); - auto &pair = changeOrAddList_removeList[p.Id]; - std::get<0>(pair).insert(p.Pos); + External.Worlds[p.Id].Regions[rPos].Chunks[cPos].Voxels = std::move(p.Cubes); + + auto &pair = changeOrAddList_removeList[p.Id]; + std::get<0>(pair).insert(p.Pos); + } else if(l2 == ToClient::L2Content::RemoveChunk) { + PP_Content_ChunkRemove &p = *dynamic_cast(pack); + + Pos::GlobalRegion rPos(p.Pos.X >> 4, p.Pos.Y >> 4, p.Pos.Z >> 4); + Pos::Local16_u cPos(p.Pos.X & 0xf, p.Pos.Y & 0xf, p.Pos.Z & 0xf); + auto &obj = External.Worlds[p.Id].Regions[rPos].Chunks; + auto iter = obj.find(cPos); + if(iter != obj.end()) + obj.erase(iter); + + auto &pair = changeOrAddList_removeList[p.Id]; + std::get<1>(pair).insert(p.Pos); + } } delete pack; @@ -261,14 +286,15 @@ void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) { if(RS && !changeOrAddList_removeList.empty()) { for(auto &pair : changeOrAddList_removeList) { + // Если случится что чанк был изменён и удалён, то исключаем его обновления + for(Pos::GlobalChunk removed : std::get<1>(pair.second)) + std::get<0>(pair.second).erase(removed); + RS->onChunksChange(pair.first, std::get<0>(pair.second), std::get<1>(pair.second)); } } } - if(!RS) - return; - // Расчёт камеры { float deltaTime = 1-std::min(gTime-PYR_At, 1/PYR_TIME_DELTA)*PYR_TIME_DELTA; @@ -277,7 +303,27 @@ void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) { 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)); - RS->setCameraPos(0, Pos, 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(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)); + } } } @@ -492,9 +538,22 @@ coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) { case ToClient::L2Content::ChunkLightPrism: co_return; - case ToClient::L2Content::RemoveChunk: - + case ToClient::L2Content::RemoveChunk: { + WorldId_c wcId = co_await sock.read(); + Pos::GlobalChunk::Key posKey = co_await sock.read(); + Pos::GlobalChunk pos = *(Pos::GlobalChunk*) &posKey; + + PP_Content_ChunkRemove *packet = new PP_Content_ChunkRemove( + ToClient::L1::Content, + (uint8_t) ToClient::L2Content::RemoveChunk, + wcId, + pos + ); + + while(!NetInputPackets.push(packet)); + co_return; + } default: protocolError(); } diff --git a/Src/Client/ServerSession.hpp b/Src/Client/ServerSession.hpp index 1f797a8..f9247a7 100644 --- a/Src/Client/ServerSession.hpp +++ b/Src/Client/ServerSession.hpp @@ -51,6 +51,8 @@ class ServerSession : public AsyncObject, public IServerSession, public ISurface } Keys; Pos::Object Pos = Pos::Object(0), Speed = Pos::Object(0); + GlobalTime LastSendPYR_POS; + public: // Нужен сокет, на котором только что был согласован игровой протокол (asyncInitGameProtocol) ServerSession(asio::io_context &ioc, std::unique_ptr &&socket, IRenderSession *rs = nullptr) diff --git a/Src/Client/Vulkan/Vulkan.cpp b/Src/Client/Vulkan/Vulkan.cpp index 1caccae..bc57515 100644 --- a/Src/Client/Vulkan/Vulkan.cpp +++ b/Src/Client/Vulkan/Vulkan.cpp @@ -2129,6 +2129,10 @@ void Vulkan::gui_ConnectedToServer() { Game.RSession = nullptr; Game.Session = nullptr; Game.ImGuiInterfaces.pop_back(); + + int mode = glfwGetInputMode(Graphics.Window, GLFW_CURSOR); + if(mode == GLFW_CURSOR_DISABLED) + glfwSetInputMode(Graphics.Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); } } diff --git a/Src/Client/Vulkan/VulkanRenderSession.cpp b/Src/Client/Vulkan/VulkanRenderSession.cpp index 194edf7..cb9858d 100644 --- a/Src/Client/Vulkan/VulkanRenderSession.cpp +++ b/Src/Client/Vulkan/VulkanRenderSession.cpp @@ -3,7 +3,9 @@ #include "Client/Vulkan/Vulkan.hpp" #include "Common/Abstract.hpp" #include "assets.hpp" +#include "glm/ext/matrix_transform.hpp" #include "glm/trigonometric.hpp" +#include #include #include #include @@ -630,31 +632,41 @@ void VulkanRenderSession::onDefEntityUpdates(const std::vector &u } void VulkanRenderSession::onChunksChange(WorldId_c worldId, const std::unordered_set &changeOrAddList, const std::unordered_set &remove) { + auto &table = External.ChunkVoxelMesh[worldId]; + for(Pos::GlobalChunk pos : changeOrAddList) { Pos::GlobalRegion rPos(pos.X >> 4, pos.Y >> 4, pos.Z >> 4); Pos::Local16_u cPos(pos.X & 0xf, pos.Y & 0xf, pos.Z & 0xf); const auto &voxels = ServerSession->External.Worlds[worldId].Regions[rPos].Chunks[cPos].Voxels; - auto &table = External.ChunkVoxelMesh[worldId]; if(voxels.empty()) { auto iter = table.find(pos); if(iter != table.end()) table.erase(iter); - - if(table.empty()) - External.ChunkVoxelMesh.erase(External.ChunkVoxelMesh.find(worldId)); } else { - auto &buffer = table[pos] = std::make_unique(VkInst, voxels.size()*6*6*sizeof(NodeVertexStatic)); - NodeVertexStatic *vertex = (NodeVertexStatic*) buffer->mapMemory(); + std::vector vertexs = generateMeshForVoxelChunks(voxels); - for(const VoxelCube &cube : voxels) { - + if(!vertexs.empty()) { + auto &buffer = table[pos] = std::make_unique(VkInst, vertexs.size()*sizeof(VoxelVertexPoint)); + std::copy(vertexs.data(), vertexs.data()+vertexs.size(), (VoxelVertexPoint*) buffer->mapMemory()); + buffer->unMapMemory(); + } else { + auto iter = table.find(pos); + if(iter != table.end()) + table.erase(iter); } - - buffer->unMapMemory(); } } + + for(Pos::GlobalChunk pos : remove) { + auto iter = table.find(pos); + if(iter != table.end()) + table.erase(iter); + } + + if(table.empty()) + External.ChunkVoxelMesh.erase( External.ChunkVoxelMesh.find(worldId)); } void VulkanRenderSession::setCameraPos(WorldId_c worldId, Pos::Object pos, glm::quat quat) { @@ -719,6 +731,26 @@ void VulkanRenderSession::drawWorld(GlobalTime gTime, float dTime, VkCommandBuff vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBuffer, &vkOffsets); vkCmdDraw(drawCmd, VKCTX->TestVoxel->getSize() / sizeof(VoxelVertexPoint), 1, 0, 0); } + + { + auto iterWorld = External.ChunkVoxelMesh.find(WorldId); + if(iterWorld != External.ChunkVoxelMesh.end()) { + glm::mat4 orig = PCO.Model; + + for(auto &pair : iterWorld->second) { + glm::vec3 cpos(pair.first.X, pair.first.Y, pair.first.Z); + PCO.Model = glm::translate(orig, cpos*16.f); + vkBuffer = *pair.second; + + vkCmdPushConstants(drawCmd, MainAtlas_LightMap_PipelineLayout, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, offsetof(WorldPCO, Model), sizeof(WorldPCO::Model), &PCO.Model); + vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBuffer, &vkOffsets); + vkCmdDraw(drawCmd, pair.second->getSize() / sizeof(VoxelVertexPoint), 1, 0, 0); + } + + PCO.Model = orig; + } + } } std::vector VulkanRenderSession::generateMeshForVoxelChunks(const std::vector cubes) { diff --git a/Src/Common/Packets.hpp b/Src/Common/Packets.hpp index 10892be..f70aae1 100644 --- a/Src/Common/Packets.hpp +++ b/Src/Common/Packets.hpp @@ -65,7 +65,8 @@ enum struct L1 : uint8_t { // Второй уровень enum struct L2System : uint8_t { InitEnd, - Disconnect + Disconnect, + Test_CAM_PYR_POS }; } diff --git a/Src/Server/ContentEventController.cpp b/Src/Server/ContentEventController.cpp index 5d34188..fd8ad44 100644 --- a/Src/Server/ContentEventController.cpp +++ b/Src/Server/ContentEventController.cpp @@ -13,15 +13,15 @@ ContentEventController::ContentEventController(std::unique_ptr &&r } uint8_t ContentEventController::getViewRange() const { - return 3; + return 16; } ServerObjectPos ContentEventController::getLastPos() const { - return {0, {0, 0, 0}}; + return {0, Remote->CameraPos}; } ServerObjectPos ContentEventController::getPos() const { - return {0, {0, 0, 0}}; + return {0, Remote->CameraPos}; } void ContentEventController::onRegionsLost(WorldId_t worldId, const std::vector &lost) { diff --git a/Src/Server/GameServer.cpp b/Src/Server/GameServer.cpp index 8f41bec..2c5616b 100644 --- a/Src/Server/GameServer.cpp +++ b/Src/Server/GameServer.cpp @@ -408,6 +408,9 @@ void GameServer::stepPlayers() { wIter->second->onCEC_RegionsLost(cec.get(), wPair.second); } + + std::string username = cec->Remote->Username; + External.ConnectedPlayersSet.lock_write()->erase(username); cec.reset(); } @@ -913,6 +916,7 @@ void GameServer::stepViewContent() { cvc.WorldId = oPos.WorldId; cvc.Pos = {oPos.ObjectPos.x >> (Pos::Object_t::BS_Bit+4), oPos.ObjectPos.y >> (Pos::Object_t::BS_Bit+4), oPos.ObjectPos.z >> (Pos::Object_t::BS_Bit+4)}; cvc.Range = cec.getViewRange(); + cvc.Range *= cvc.Range; cec.ContentViewCircles = Expanse.calcAndRemapCVC(cvc); } @@ -926,34 +930,7 @@ void GameServer::stepViewContent() { ServerObjectPos oLPos = cec.getLastPos(), oPos = cec.getPos(); std::vector lost; - - // Снимаем подписки с регионов - for(auto &pairSR : cec.SubscribedRegions) { - auto CVCs = cec.ContentViewCircles.find(pairSR.first); - - if(CVCs == cec.ContentViewCircles.end()) { - lost = pairSR.second; - } else { - for(Pos::GlobalRegion ®ion : pairSR.second) { - for(ContentViewCircle &circle : CVCs->second) { - if(!circle.isIn(region)) { - lost.push_back(region); - break; - } - } - } - } - - cec.onRegionsLost(pairSR.first, lost); - - auto world = Expanse.Worlds.find(pairSR.first); - if(world != Expanse.Worlds.end()) - world->second->onCEC_RegionsLost(&cec, lost); - - lost.clear(); - } - // Проверяем отслеживаемые регионы std::vector regionsResult; for(auto &pair : cec.ContentViewCircles) { @@ -992,6 +969,36 @@ void GameServer::stepViewContent() { regionsResult.clear(); } } + + // Снимаем подписки с регионов + for(auto &pairSR : cec.SubscribedRegions) { + auto CVCs = cec.ContentViewCircles.find(pairSR.first); + + if(CVCs == cec.ContentViewCircles.end()) { + lost = pairSR.second; + } else { + for(Pos::GlobalRegion ®ion : pairSR.second) { + bool inView = false; + for(ContentViewCircle &circle : CVCs->second) { + if(circle.isIn(region)) { + inView = true; + break; + } + } + + if(!inView) + lost.push_back(region); + } + } + + cec.onRegionsLost(pairSR.first, lost); + + auto world = Expanse.Worlds.find(pairSR.first); + if(world != Expanse.Worlds.end()) + world->second->onCEC_RegionsLost(&cec, lost); + + lost.clear(); + } } } diff --git a/Src/Server/RemoteClient.cpp b/Src/Server/RemoteClient.cpp index 8ac961d..a4e4b8d 100644 --- a/Src/Server/RemoteClient.cpp +++ b/Src/Server/RemoteClient.cpp @@ -124,6 +124,8 @@ void RemoteClient::prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk LOG.debug() << "Воксели чанка: " << worldId << " / " << chunkPos.X << ":" << chunkPos.Y << ":" << chunkPos.Z; + checkPacketBorder(voxels.size()*(2+6)+16); + NextPacket << (uint8_t) ToClient::L1::Content << (uint8_t) ToClient::L2Content::ChunkVoxels << wcId << Pos::GlobalChunk::Key(chunkPos); @@ -164,7 +166,9 @@ void RemoteClient::prepareChunkRemove(WorldId_t worldId, Pos::GlobalChunk chunkP } LOG.debug() << "Чанк потерян: " << worldId << " / " << chunkPos.X << ":" << chunkPos.Y << ":" << chunkPos.Z; - WorldId_c cwId = ResRemap.Worlds.toClient(worldId); + WorldId_c cwId = worldId ? ResRemap.Worlds.toClient(worldId) : worldId; + + checkPacketBorder(16); NextPacket << (uint8_t) ToClient::L1::Content << (uint8_t) ToClient::L2Content::RemoveChunk << cwId << Pos::GlobalChunk::Key(chunkPos); @@ -189,6 +193,8 @@ void RemoteClient::prepareWorldNew(WorldId_t worldId, World* world) WorldId_c cId = ResRemap.Worlds.toClient(worldId); LOG.debug() << "Новый мир: " << worldId << " -> " << int(cId); + + checkPacketBorder(16); NextPacket << (uint8_t) ToClient::L1::Content << (uint8_t) ToClient::L2Content::World << cId; @@ -231,7 +237,7 @@ void RemoteClient::prepareWorldUpdate(WorldId_t worldId, World* world) decrementBinary(lostTextures, lostSounds, lostModels); decrementBinary(newTextures, newSounds, newModels); - WorldId_c cId = ResRemap.Worlds.toClient(worldId); + WorldId_c cId = worldId ? ResRemap.Worlds.toClient(worldId) : worldId; // TODO: отправить пакет об изменении мира LOG.debug() << "Изменение мира: " << worldId << " -> " << cId; } @@ -242,7 +248,7 @@ void RemoteClient::prepareWorldRemove(WorldId_t worldId) // Понизим зависимости ресурсов ResUsesObj::WorldResourceUse &res = ResUses.Worlds[worldId]; - WorldId_c cWorld = ResUses.Worlds.erase(worldId); + WorldId_c cWorld = worldId ? ResUses.Worlds.erase(worldId) : worldId; LOG.debug() << "Мир потерян: " << worldId << " -> " << cWorld; NextPacket << (uint8_t) ToClient::L1::Content @@ -323,6 +329,7 @@ void RemoteClient::prepareEntityRemove(GlobalEntityId_t entityId) LOG.debug() << "Сущность потеряна: " << cId; + checkPacketBorder(16); NextPacket << (uint8_t) ToClient::L1::Content << (uint8_t) ToClient::L2Content::RemoveEntity << cId; @@ -357,6 +364,7 @@ void RemoteClient::informateDefTexture(const std::unordered_mapHash) @@ -373,18 +381,12 @@ void RemoteClient::informateDefTexture(const std::unordered_mapData.size()) { - if(NextPacket.size() > 64000) { - SimplePackets.push_back(std::move(NextPacket)); - } - + checkPacketBorder(0); size_t need = std::min(pair.second->Data.size()-pos, std::min(NextPacket.size(), 64000)); NextPacket.write(pair.second->Data.data()+pos, need); pos += need; } } - - if(NextPacket.size()) - SimplePackets.push_back(std::move(NextPacket)); } void RemoteClient::informateDefSound(const std::unordered_map> &sounds) @@ -396,6 +398,7 @@ void RemoteClient::informateDefSound(const std::unordered_mapHash) @@ -534,6 +537,12 @@ void RemoteClient::informateDefPortals(const std::unordered_map RemoteClient::rP_System(Net::AsyncSocket &sock) { co_return; } + case ToServer::L2System::Test_CAM_PYR_POS: + { + CameraPos.x = co_await sock.read(); + CameraPos.y = co_await sock.read(); + CameraPos.z = co_await sock.read(); + + for(int iter = 0; iter < 5; iter++) + CameraQuat.Data[iter] = co_await sock.read(); + + co_return; + } default: protocolError(); } diff --git a/Src/Server/RemoteClient.hpp b/Src/Server/RemoteClient.hpp index af5c615..c160021 100644 --- a/Src/Server/RemoteClient.hpp +++ b/Src/Server/RemoteClient.hpp @@ -266,6 +266,8 @@ class RemoteClient { public: const std::string Username; + Pos::Object CameraPos = {0, 0, 0}; + ToServer::PacketQuat CameraQuat = {0}; public: RemoteClient(asio::io_context &ioc, tcp::socket socket, const std::string username) @@ -331,6 +333,7 @@ public: void informateDefPortals(const std::unordered_map &portals); private: + void checkPacketBorder(uint16_t size); void protocolError(); coro<> readPacket(Net::AsyncSocket &sock); coro<> rP_System(Net::AsyncSocket &sock);