diff --git a/Src/Client/Abstract.hpp b/Src/Client/Abstract.hpp index eac6792..6d5f67f 100644 --- a/Src/Client/Abstract.hpp +++ b/Src/Client/Abstract.hpp @@ -34,7 +34,12 @@ struct GlobalTime { }; struct VoxelCube { - DefVoxelId_t VoxelId; + union { + struct { + DefVoxelId_t VoxelId : 24, Meta : 8; + }; + DefVoxelId_t Data; + }; Pos::bvec256u Left, Size; }; @@ -77,39 +82,32 @@ public: virtual void onBinaryResourceAdd(std::unordered_map>) = 0; virtual void onBinaryResourceLost(std::unordered_map>) = 0; - // Профили использования двоичных ресурсов - // В этом месте нужно зарание распарсить - virtual void onBinaryProfileAdd(std::unordered_map>) = 0; - virtual void onBinaryProfileLost(std::unordered_map>) = 0; - - virtual void onContentDefines(std::unordered_map>); - EnumDefContent - - virtual void onDefWorldUpdates(const std::vector &updates) = 0; - virtual void onDefVoxelUpdates(const std::vector &updates) = 0; - virtual void onDefNodeUpdates(const std::vector &updates) = 0; - virtual void onDefPortalUpdates(const std::vector &updates) = 0; - virtual void onDefEntityUpdates(const std::vector &updates) = 0; + virtual void onContentDefinesAdd(std::unordered_map>) = 0; + virtual void onContentDefinesLost(std::unordered_map>) = 0; // Сообщаем об изменившихся чанках - virtual void onChunksChange(WorldId_c worldId, const std::unordered_set &changeOrAddList, const std::unordered_set &remove) = 0; + virtual void onChunksChange(WorldId_t worldId, const std::unordered_set &changeOrAddList, const std::unordered_set &remove) = 0; // Установить позицию для камеры - virtual void setCameraPos(WorldId_c worldId, Pos::Object pos, glm::quat quat) = 0; + virtual void setCameraPos(WorldId_t worldId, Pos::Object pos, glm::quat quat) = 0; virtual ~IRenderSession(); }; - struct Region { - std::unordered_map Chunks; + std::unordered_map Chunks; }; - struct World { - std::vector Entitys; - std::unordered_map Regions; + }; +struct DefVoxelInfo { + +}; + +struct DefNodeInfo { + +}; struct DefWorldInfo { @@ -123,10 +121,16 @@ struct DefEntityInfo { }; -struct WorldInfo { +struct DefFuncEntityInfo { }; +struct WorldInfo { + std::vector Entitys; + std::vector FuncEntitys; + std::unordered_map Regions; +}; + struct VoxelInfo { }; @@ -143,24 +147,33 @@ struct EntityInfo { }; +struct FuncEntityInfo { + +}; + +struct DefItemInfo { + +}; + /* Интерфейс обработчика сессии с сервером */ class IServerSession { public: struct { - std::unordered_map DefWorlds; - std::unordered_map DefVoxels; - std::unordered_map DefNodes; - std::unordered_map DefPortals; - std::unordered_map DefEntityes; - - std::unordered_map Worlds; - std::unordered_map Portals; - std::unordered_map Entityes; + std::unordered_map DefVoxel; + std::unordered_map DefNode; + std::unordered_map DefWorld; + std::unordered_map DefPortal; + std::unordered_map DefEntity; + std::unordered_map DefFuncEntity; + std::unordered_map DefItem; } Registry; struct { - std::unordered_map Worlds; - } External; + std::unordered_map Worlds; + std::unordered_map Portals; + std::unordered_map Entityes; + std::unordered_map FuncEntityes; + } Data; virtual ~IServerSession(); diff --git a/Src/Client/ServerSession.cpp b/Src/Client/ServerSession.cpp index 2fdff1e..3b3f4ec 100644 --- a/Src/Client/ServerSession.cpp +++ b/Src/Client/ServerSession.cpp @@ -20,20 +20,20 @@ namespace LV::Client { ParsedPacket::~ParsedPacket() = default; struct PP_Content_ChunkVoxels : public ParsedPacket { - WorldId_c Id; + WorldId_t Id; Pos::GlobalChunk Pos; std::vector Cubes; - PP_Content_ChunkVoxels(ToClient::L1 l1, uint8_t l2, WorldId_c id, Pos::GlobalChunk pos, std::vector &&cubes) + PP_Content_ChunkVoxels(ToClient::L1 l1, uint8_t l2, WorldId_t id, Pos::GlobalChunk pos, std::vector &&cubes) : ParsedPacket(l1, l2), Id(id), Pos(pos), Cubes(std::move(cubes)) {} }; struct PP_Content_ChunkRemove : public ParsedPacket { - WorldId_c Id; + WorldId_t Id; Pos::GlobalChunk Pos; - PP_Content_ChunkRemove(ToClient::L1 l1, uint8_t l2, WorldId_c id, Pos::GlobalChunk pos) + PP_Content_ChunkRemove(ToClient::L1 l1, uint8_t l2, WorldId_t id, Pos::GlobalChunk pos) : ParsedPacket(l1, l2), Id(id), Pos(pos) {} }; @@ -252,7 +252,7 @@ void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) { Speed += glm::vec3(0, 1, 0)*float(Keys.SPACE)*mltpl; { - std::unordered_map, std::unordered_set>> changeOrAddList_removeList; + std::unordered_map, std::unordered_set>> changeOrAddList_removeList; // Пакеты ParsedPacket *pack; @@ -261,19 +261,19 @@ void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) { 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); + Pos::GlobalRegion rPos = p.Pos >> 2; + Pos::bvec4u cPos = p.Pos & 0x3; - External.Worlds[p.Id].Regions[rPos].Chunks[cPos].Voxels = std::move(p.Cubes); + Data.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; + Pos::GlobalRegion rPos = p.Pos >> 2; + Pos::bvec4u cPos = p.Pos & 0x3; + auto &obj = Data.Worlds[p.Id].Regions[rPos].Chunks; auto iter = obj.find(cPos); if(iter != obj.end()) obj.erase(iter); @@ -443,22 +443,22 @@ coro<> ServerSession::rP_Definition(Net::AsyncSocket &sock) { switch((ToClient::L2Definition) second) { case ToClient::L2Definition::World: { - DefWorldId_c cdId = co_await sock.read(); + DefWorldId_t cdId = co_await sock.read(); co_return; } case ToClient::L2Definition::FreeWorld: { - DefWorldId_c cdId = co_await sock.read(); + DefWorldId_t cdId = co_await sock.read(); co_return; } case ToClient::L2Definition::Voxel: { - DefVoxelId_c cdId = co_await sock.read(); + DefVoxelId_t cdId = co_await sock.read(); co_return; } case ToClient::L2Definition::FreeVoxel: { - DefVoxelId_c cdId = co_await sock.read(); + DefVoxelId_t cdId = co_await sock.read(); co_return; } @@ -509,9 +509,9 @@ coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) { co_return; case ToClient::L2Content::ChunkVoxels: { - WorldId_c wcId = co_await sock.read(); - Pos::GlobalChunk::Key posKey = co_await sock.read(); - Pos::GlobalChunk pos = *(Pos::GlobalChunk*) &posKey; + WorldId_t wcId = co_await sock.read(); + Pos::GlobalChunk pos; + pos.unpack(co_await sock.read()); std::vector cubes(co_await sock.read()); uint16_t debugCubesCount = cubes.size(); @@ -522,13 +522,13 @@ coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) { for(size_t iter = 0; iter < cubes.size(); iter++) { VoxelCube &cube = cubes[iter]; - cube.VoxelId = 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(); + 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(); } PP_Content_ChunkVoxels *packet = new PP_Content_ChunkVoxels( @@ -551,9 +551,9 @@ coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) { co_return; 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; + WorldId_t wcId = co_await sock.read(); + Pos::GlobalChunk pos; + pos.unpack(co_await sock.read()); PP_Content_ChunkRemove *packet = new PP_Content_ChunkRemove( ToClient::L1::Content, diff --git a/Src/Client/Vulkan/VulkanRenderSession.cpp b/Src/Client/Vulkan/VulkanRenderSession.cpp index cb9858d..a43d777 100644 --- a/Src/Client/Vulkan/VulkanRenderSession.cpp +++ b/Src/Client/Vulkan/VulkanRenderSession.cpp @@ -232,16 +232,16 @@ void VulkanRenderSession::init(Vulkan *instance) { { std::vector cubes; - cubes.emplace_back(0, Pos::Local256_u{0, 0, 0}, Pos::Local256_u{0, 0, 0}); - cubes.emplace_back(1, Pos::Local256_u{255, 0, 0}, Pos::Local256_u{0, 0, 0}); - cubes.emplace_back(1, Pos::Local256_u{0, 255, 0}, Pos::Local256_u{0, 0, 0}); - cubes.emplace_back(1, Pos::Local256_u{0, 0, 255}, Pos::Local256_u{0, 0, 0}); - cubes.emplace_back(2, Pos::Local256_u{255, 255, 0}, Pos::Local256_u{0, 0, 0}); - cubes.emplace_back(2, Pos::Local256_u{0, 255, 255}, Pos::Local256_u{0, 0, 0}); - cubes.emplace_back(2, Pos::Local256_u{255, 0, 255}, Pos::Local256_u{0, 0, 0}); - cubes.emplace_back(3, Pos::Local256_u{255, 255, 255}, Pos::Local256_u{0, 0, 0}); + cubes.push_back({0, 0, Pos::bvec256u{0, 0, 0}, Pos::bvec256u{0, 0, 0}}); + cubes.push_back({1, 0, Pos::bvec256u{255, 0, 0}, Pos::bvec256u{0, 0, 0}}); + cubes.push_back({1, 0, Pos::bvec256u{0, 255, 0}, Pos::bvec256u{0, 0, 0}}); + cubes.push_back({1, 0, Pos::bvec256u{0, 0, 255}, Pos::bvec256u{0, 0, 0}}); + cubes.push_back({2, 0, Pos::bvec256u{255, 255, 0}, Pos::bvec256u{0, 0, 0}}); + cubes.push_back({2, 0, Pos::bvec256u{0, 255, 255}, Pos::bvec256u{0, 0, 0}}); + cubes.push_back({2, 0, Pos::bvec256u{255, 0, 255}, Pos::bvec256u{0, 0, 0}}); + cubes.push_back({3, 0, Pos::bvec256u{255, 255, 255}, Pos::bvec256u{0, 0, 0}}); - cubes.emplace_back(4, Pos::Local256_u{64, 64, 64}, Pos::Local256_u{127, 127, 127}); + cubes.push_back({4, 0, Pos::bvec256u{64, 64, 64}, Pos::bvec256u{127, 127, 127}}); std::vector vertexs = generateMeshForVoxelChunks(cubes); @@ -595,50 +595,30 @@ void VulkanRenderSession::init(Vulkan *instance) { } } -void VulkanRenderSession::onDefTexture(TextureId_c id, std::vector &&info) { +void VulkanRenderSession::onBinaryResourceAdd(std::unordered_map>) { } -void VulkanRenderSession::onDefTextureLost(const std::vector &&lost) { +void VulkanRenderSession::onBinaryResourceLost(std::unordered_map>) { } -void VulkanRenderSession::onDefModel(ModelId_c id, std::vector &&info) { +void VulkanRenderSession::onContentDefinesAdd(std::unordered_map>) { } -void VulkanRenderSession::onDefModelLost(const std::vector &&lost) { +void VulkanRenderSession::onContentDefinesLost(std::unordered_map>) { } -void VulkanRenderSession::onDefWorldUpdates(const std::vector &updates) { - -} - -void VulkanRenderSession::onDefVoxelUpdates(const std::vector &updates) { - -} - -void VulkanRenderSession::onDefNodeUpdates(const std::vector &updates) { - -} - -void VulkanRenderSession::onDefPortalUpdates(const std::vector &updates) { - -} - -void VulkanRenderSession::onDefEntityUpdates(const std::vector &updates) { - -} - -void VulkanRenderSession::onChunksChange(WorldId_c worldId, const std::unordered_set &changeOrAddList, const std::unordered_set &remove) { - auto &table = External.ChunkVoxelMesh[worldId]; +void VulkanRenderSession::onChunksChange(WorldId_t 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); + Pos::GlobalRegion rPos = pos >> 4; + Pos::bvec16u cPos = pos & 0xf; - const auto &voxels = ServerSession->External.Worlds[worldId].Regions[rPos].Chunks[cPos].Voxels; + const auto &voxels = ServerSession->Data.Worlds[worldId].Regions[rPos].Chunks[cPos].Voxels; if(voxels.empty()) { auto iter = table.find(pos); @@ -669,7 +649,7 @@ void VulkanRenderSession::onChunksChange(WorldId_c worldId, const std::unordered External.ChunkVoxelMesh.erase( External.ChunkVoxelMesh.find(worldId)); } -void VulkanRenderSession::setCameraPos(WorldId_c worldId, Pos::Object pos, glm::quat quat) { +void VulkanRenderSession::setCameraPos(WorldId_t worldId, Pos::Object pos, glm::quat quat) { WorldId = worldId; Pos = pos; Quat = quat; @@ -738,7 +718,7 @@ void VulkanRenderSession::drawWorld(GlobalTime gTime, float dTime, VkCommandBuff glm::mat4 orig = PCO.Model; for(auto &pair : iterWorld->second) { - glm::vec3 cpos(pair.first.X, pair.first.Y, pair.first.Z); + glm::vec3 cpos(pair.first.x, pair.first.y, pair.first.z); PCO.Model = glm::translate(orig, cpos*16.f); vkBuffer = *pair.second; @@ -759,78 +739,78 @@ std::vector VulkanRenderSession::generateMeshForVoxelChunks(co for(const VoxelCube &cube : cubes) { out.emplace_back( - cube.Left.X, - cube.Left.Y, - cube.Left.Z, + cube.Left.x, + cube.Left.y, + cube.Left.z, 0, 0, 0, - cube.Size.X, - cube.Size.Z, + cube.Size.x, + cube.Size.z, cube.VoxelId, 0, 0, 0 ); out.emplace_back( - cube.Left.X, - cube.Left.Y, - cube.Left.Z, + cube.Left.x, + cube.Left.y, + cube.Left.z, 1, 0, 0, - cube.Size.X, - cube.Size.Y, + cube.Size.x, + cube.Size.y, cube.VoxelId, 0, 0, 0 ); out.emplace_back( - cube.Left.X, - cube.Left.Y, - cube.Left.Z, + cube.Left.x, + cube.Left.y, + cube.Left.z, 2, 0, 0, - cube.Size.Z, - cube.Size.Y, + cube.Size.z, + cube.Size.y, cube.VoxelId, 0, 0, 0 ); out.emplace_back( - cube.Left.X, - cube.Left.Y+cube.Size.Y+1, - cube.Left.Z, + cube.Left.x, + cube.Left.y+cube.Size.y+1, + cube.Left.z, 3, 0, 0, - cube.Size.X, - cube.Size.Z, + cube.Size.x, + cube.Size.z, cube.VoxelId, 0, 0, 0 ); out.emplace_back( - cube.Left.X, - cube.Left.Y, - cube.Left.Z+cube.Size.Z+1, + cube.Left.x, + cube.Left.y, + cube.Left.z+cube.Size.z+1, 4, 0, 0, - cube.Size.X, - cube.Size.Y, + cube.Size.x, + cube.Size.y, cube.VoxelId, 0, 0, 0 ); out.emplace_back( - cube.Left.X+cube.Size.X+1, - cube.Left.Y, - cube.Left.Z, + cube.Left.x+cube.Size.x+1, + cube.Left.y, + cube.Left.z, 5, 0, 0, - cube.Size.Z, - cube.Size.Y, + cube.Size.z, + cube.Size.y, cube.VoxelId, 0, 0, 0 diff --git a/Src/Client/Vulkan/VulkanRenderSession.hpp b/Src/Client/Vulkan/VulkanRenderSession.hpp index 5b18add..b5ac284 100644 --- a/Src/Client/Vulkan/VulkanRenderSession.hpp +++ b/Src/Client/Vulkan/VulkanRenderSession.hpp @@ -78,7 +78,7 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent { IServerSession *ServerSession = nullptr; // Положение камеры - WorldId_c WorldId; + WorldId_t WorldId; Pos::Object Pos; glm::quat Quat; @@ -130,10 +130,10 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent { NodeStaticTransparentPipeline = VK_NULL_HANDLE; - std::map ServerToAtlas; + std::map ServerToAtlas; struct { - std::unordered_map>> ChunkVoxelMesh; + std::unordered_map>> ChunkVoxelMesh; } External; virtual void free(Vulkan *instance) override; @@ -151,19 +151,12 @@ public: assert(serverSession); } - virtual void onDefTexture(TextureId_c id, std::vector &&info) override; - virtual void onDefTextureLost(const std::vector &&lost) override; - virtual void onDefModel(ModelId_c id, std::vector &&info) override; - virtual void onDefModelLost(const std::vector &&lost) override; - - virtual void onDefWorldUpdates(const std::vector &updates) override; - virtual void onDefVoxelUpdates(const std::vector &updates) override; - virtual void onDefNodeUpdates(const std::vector &updates) override; - virtual void onDefPortalUpdates(const std::vector &updates) override; - virtual void onDefEntityUpdates(const std::vector &updates) override; - - virtual void onChunksChange(WorldId_c worldId, const std::unordered_set &changeOrAddList, const std::unordered_set &remove) override; - virtual void setCameraPos(WorldId_c worldId, Pos::Object pos, glm::quat quat) override; + virtual void onBinaryResourceAdd(std::unordered_map>) override; + virtual void onBinaryResourceLost(std::unordered_map>) override; + virtual void onContentDefinesAdd(std::unordered_map>) override; + virtual void onContentDefinesLost(std::unordered_map>) override; + virtual void onChunksChange(WorldId_t worldId, const std::unordered_set &changeOrAddList, const std::unordered_set &remove) override; + virtual void setCameraPos(WorldId_t worldId, Pos::Object pos, glm::quat quat) override; glm::mat4 calcViewMatrix(glm::quat quat, glm::vec3 camOffset = glm::vec3(0)) { return glm::translate(glm::mat4(quat), camOffset); diff --git a/Src/Common/Abstract.hpp b/Src/Common/Abstract.hpp index bc8e2f3..411984d 100644 --- a/Src/Common/Abstract.hpp +++ b/Src/Common/Abstract.hpp @@ -4,7 +4,6 @@ #include #include #include -#include namespace LV { @@ -42,10 +41,13 @@ public: BitVec3() = default; BitVec3(T value) : x(value), y(value), z(value) - { - } + {} BitVec3(const T x, const T y, const T z) : x(x), y(y), z(z) + {} + template + BitVec3(const glm::vec<3, vT, vQ> vec) + : x(vec.x), y(vec.y), z(vec.z) {} BitVec3(const BitVec3&) = default; BitVec3(BitVec3&&) = default; @@ -94,7 +96,7 @@ public: using U = std::make_unsigned_t; for(size_t iter = 0; iter < N; iter++) { - get(iter) = U((pack >> BitsPerComponent*iter) & ((Pack(1) << BitsPerComponent)-1)); + set(iter, U((pack >> BitsPerComponent*iter) & ((Pack(1) << BitsPerComponent)-1))); } } @@ -102,7 +104,7 @@ public: template operator BitVec3() const { - BitVec3 out; + BitVec3 out; for(size_t iter = 0; iter < N; iter++) { out.set(iter, T2(std::make_unsigned_t(std::make_unsigned_t(get(iter))))); } @@ -110,18 +112,24 @@ public: return out; } + + template + operator glm::vec<3, vT, vQ>() const { + return {x, y, z}; + } + BitVec3 operator+(const BitVec3 &other) const { BitVec3 out; for(size_t iter = 0; iter < N; iter++) - out[iter] = get(iter) + other[iter]; + out.set(iter, get(iter) + other[iter]); return out; } BitVec3& operator+=(const BitVec3 &other) { for(size_t iter = 0; iter < N; iter++) - get(iter) += other[iter]; + set(iter, get(iter) + other[iter]); return *this; } @@ -130,14 +138,14 @@ public: BitVec3 out; for(size_t iter = 0; iter < N; iter++) - out[iter] = get(iter) + value; + out.set(iter, get(iter) + value); return out; } BitVec3& operator+=(const T value) { for(size_t iter = 0; iter < N; iter++) - get(iter) += value; + set(iter, get(iter) + value); return *this; } @@ -146,14 +154,14 @@ public: BitVec3 out; for(size_t iter = 0; iter < N; iter++) - out[iter] = get(iter) - other[iter]; + out.set(iter, get(iter) - other[iter]); return out; } BitVec3& operator-=(const BitVec3 &other) { for(size_t iter = 0; iter < N; iter++) - get(iter) -= other[iter]; + set(iter, get(iter) - other[iter]); return *this; } @@ -162,14 +170,14 @@ public: BitVec3 out; for(size_t iter = 0; iter < N; iter++) - out[iter] = get(iter) - value; + out.set(iter, get(iter) - value); return out; } BitVec3& operator-=(const T value) { for(size_t iter = 0; iter < N; iter++) - get(iter) -= value; + set(iter, get(iter) - value); return *this; } @@ -178,14 +186,14 @@ public: BitVec3 out; for(size_t iter = 0; iter < N; iter++) - out[iter] = get(iter) * other[iter]; + out.set(iter, get(iter) * other[iter]); return out; } BitVec3& operator*=(const BitVec3 &other) { for(size_t iter = 0; iter < N; iter++) - get(iter) *= other[iter]; + set(iter, get(iter) * other[iter]); return *this; } @@ -194,14 +202,14 @@ public: BitVec3 out; for(size_t iter = 0; iter < N; iter++) - out[iter] = get(iter) * value; + out.set(iter, get(iter) * value); return out; } BitVec3& operator*=(const T value) { for(size_t iter = 0; iter < N; iter++) - get(iter) *= value; + set(iter, get(iter) * value); return *this; } @@ -210,14 +218,14 @@ public: BitVec3 out; for(size_t iter = 0; iter < N; iter++) - out[iter] = get(iter) / other[iter]; + out.set(iter, get(iter) / other[iter]); return out; } BitVec3& operator/=(const BitVec3 &other) { for(size_t iter = 0; iter < N; iter++) - get(iter) /= other[iter]; + set(iter, get(iter) / other[iter]); return *this; } @@ -226,14 +234,14 @@ public: BitVec3 out; for(size_t iter = 0; iter < N; iter++) - out[iter] = get(iter) / value; + out.set(iter, get(iter) / value); return out; } BitVec3& operator/=(const T value) { for(size_t iter = 0; iter < N; iter++) - get(iter) /= value; + set(iter, get(iter) / value); return *this; } @@ -249,7 +257,7 @@ public: BitVec3& operator>>=(const auto offset) { for(size_t iter = 0; iter < N; iter++) - get(iter) >>= offset; + set(iter, get(iter) >> offset); return *this; } @@ -258,14 +266,14 @@ public: BitVec3 out; for(size_t iter = 0; iter < N; iter++) - out[iter] = get(iter) << offset; + out.set(iter, get(iter) << offset); return out; } BitVec3& operator<<=(const auto offset) { for(size_t iter = 0; iter < N; iter++) - get(iter) <<= offset; + set(iter, get(iter) << offset); return *this; } @@ -274,14 +282,14 @@ public: BitVec3 out; for(size_t iter = 0; iter < N; iter++) - out[iter] = get(iter) | other[iter]; + out.set(iter, get(iter) | other[iter]); return out; } BitVec3& operator|=(const BitVec3 other) { for(size_t iter = 0; iter < N; iter++) - get(iter) |= other[iter]; + set(iter, get(iter) | other[iter]); return *this; } @@ -290,14 +298,14 @@ public: BitVec3 out; for(size_t iter = 0; iter < N; iter++) - out[iter] = get(iter) | value; + out.set(iter, get(iter) | value); return out; } BitVec3& operator|=(const T value) { for(size_t iter = 0; iter < N; iter++) - get(iter) |= value; + set(iter, get(iter) | value); return *this; } @@ -306,14 +314,14 @@ public: BitVec3 out; for(size_t iter = 0; iter < N; iter++) - out[iter] = get(iter) & other[iter]; + out.set(iter, get(iter) & other[iter]); return out; } BitVec3& operator&=(const BitVec3 other) { for(size_t iter = 0; iter < N; iter++) - get(iter) &= other[iter]; + set(iter, get(iter) & other[iter]); return *this; } @@ -322,14 +330,14 @@ public: BitVec3 out; for(size_t iter = 0; iter < N; iter++) - out[iter] = get(iter) & value; + out.set(iter, get(iter) & value); return out; } BitVec3& operator&=(const T value) { for(size_t iter = 0; iter < N; iter++) - get(iter) &= value; + set(iter, get(iter) & value); return *this; } @@ -343,7 +351,9 @@ using bvec16i = BitVec3; using bvec16u = BitVec3; using bvec256i = BitVec3; using bvec256u = BitVec3; -using bvec4096i = BitVec3; +using bvec1024i = BitVec3; +using bvec1024u = BitVec3; +using bvec4096i = BitVec3; using bvec4096u = BitVec3; using GlobalVoxel = BitVec3; @@ -385,25 +395,23 @@ using BinSoundId_t = ResourceId_t; using BinFontId_t = ResourceId_t; // Шаблоны использования бинарных ресурсов -using TextureId_t = ResourceId_t; -using AnimationId_t = ResourceId_t; -using ModelId_t = ResourceId_t; -using SoundId_t = ResourceId_t; -using FontId_t = ResourceId_t; +// using DefTextureId_t = ResourceId_t; +// using DefModelId_t = ResourceId_t; +// using DefSoundId_t = ResourceId_t; +// using DefFontId_t = ResourceId_t; enum class EnumDefContent { Voxel, Node, Generator, World, Portal, Entity, FuncEntitry }; // Игровые определения -using DefVoxelId_t = ResourceId_t; -using DefNodeId_t = ResourceId_t; -using DefGeneratorId_t = ResourceId_t; -using DefWorldId_t = ResourceId_t; -using DefPortalId_t = ResourceId_t; -using DefEntityId_t = ResourceId_t; +using DefVoxelId_t = ResourceId_t; +using DefNodeId_t = ResourceId_t; +using DefWorldId_t = ResourceId_t; +using DefPortalId_t = ResourceId_t; +using DefEntityId_t = ResourceId_t; using DefFuncEntityId_t = ResourceId_t; - +using DefItemId_t = ResourceId_t; // Контент, основанный на игровых определениях using WorldId_t = ResourceId_t; diff --git a/Src/Common/Collide.hpp b/Src/Common/Collide.hpp index b7c366a..1a89c92 100644 --- a/Src/Common/Collide.hpp +++ b/Src/Common/Collide.hpp @@ -1,5 +1,6 @@ -#include "Common/Abstract.hpp" -#include +#pragma once +#include + namespace LV { diff --git a/Src/Common/Packets.hpp b/Src/Common/Packets.hpp index 8023cb5..e5e884a 100644 --- a/Src/Common/Packets.hpp +++ b/Src/Common/Packets.hpp @@ -138,10 +138,14 @@ enum struct L2System : uint8_t { enum struct L2Resource : uint8_t { Texture, FreeTexture, + Animation, + FreeAnimation, Sound, FreeSound, Model, FreeModel, + Font, + FreeFont, InitResSend = 253, ChunkSend, SendCanceled @@ -157,7 +161,11 @@ enum struct L2Definition : uint8_t { Portal, FreePortal, Entity, - FreeEntity + FreeEntity, + FuncEntity, + FreeFuncEntity, + Item, + FreeItem }; enum struct L2Content : uint8_t { diff --git a/Src/Server/Abstract.hpp b/Src/Server/Abstract.hpp index 6325f92..05e8438 100644 --- a/Src/Server/Abstract.hpp +++ b/Src/Server/Abstract.hpp @@ -4,19 +4,31 @@ #include #include #include +#include +#include namespace LV::Server { +struct TexturePipeline { + std::vector BinTextures; + std::u8string Pipeline; +}; + + // В одном регионе может быть максимум 2^16 сущностей. Клиенту адресуются сущности в формате <мир>+<позиция региона>+ // И если сущность перешла из одного региона в другой, идентификатор сущности на стороне клиента сохраняется -using EntityId_t = uint16_t; -using FuncEntityId_t = uint16_t; -using ClientEntityId_t = std::tuple; +using RegionEntityId_t = uint16_t; +using ClientEntityId_t = RegionEntityId_t; +using ServerEntityId_t = std::tuple; +using RegionFuncEntityId_t = uint16_t; +using ClientFuncEntityId_t = RegionFuncEntityId_t; +using ServerFuncEntityId_t = std::tuple; using MediaStreamId_t = uint16_t; using ContentBridgeId_t = ResourceId_t; using PlayerId_t = ResourceId_t; +using DefGeneratorId_t = ResourceId_t; /* @@ -44,25 +56,66 @@ struct ServerTime { }; struct VoxelCube { - DefVoxelId_t VoxelId; - Pos::bvec256u Left, Right; + union { + struct { + DefVoxelId_t VoxelId : 24, Meta : 8; + }; - auto operator<=>(const VoxelCube&) const = default; + DefVoxelId_t Data = 0; + }; + + Pos::bvec256u Left, Right; // TODO: заменить на позицию и размер + + auto operator<=>(const VoxelCube& other) const { + if (auto cmp = Left <=> other.Left; cmp != 0) + return cmp; + + if (auto cmp = Right <=> other.Right; cmp != 0) + return cmp; + + return Data <=> other.Data; + } + + bool operator==(const VoxelCube& other) const { + return Left == other.Left && Right == other.Right && Data == other.Data; + } }; struct VoxelCube_Region { - Pos::bvec4096u Left, Right; - DefVoxelId_t VoxelId; + union { + struct { + DefVoxelId_t VoxelId : 24, Meta : 8; + }; - auto operator<=>(const VoxelCube_Region&) const = default; + DefVoxelId_t Data = 0; + }; + + Pos::bvec1024u Left, Right; // TODO: заменить на позицию и размер + + auto operator<=>(const VoxelCube_Region& other) const { + if (auto cmp = Left <=> other.Left; cmp != 0) + return cmp; + + if (auto cmp = Right <=> other.Right; cmp != 0) + return cmp; + + return Data <=> other.Data; + } + + bool operator==(const VoxelCube_Region& other) const { + return Left == other.Left && Right == other.Right && Data == other.Data; + } }; struct Node { - DefNodeId_t NodeId; - uint8_t Rotate : 6; + union { + struct { + DefNodeId_t NodeId : 24, Meta : 8; + }; + DefNodeId_t Data; + }; }; - struct AABB { Pos::Object VecMin, VecMax; @@ -96,26 +149,26 @@ struct LocalAABB { struct CollisionAABB : public AABB { enum struct EnumType { - Voxel, Node, Entity, Barrier, Portal, Another + Voxel, Node, Entity, FuncEntity, Barrier, Portal, Another } Type; union { struct { - EntityId_t Index; + RegionEntityId_t Index; } Entity; struct { - FuncEntityId_t Index; + RegionFuncEntityId_t Index; } FuncEntity; struct { + Pos::bvec4u Chunk; Pos::bvec16u Pos; } Node; struct { - Pos::bvec16u Chunk; + Pos::bvec4u Chunk; uint32_t Index; - DefVoxelId_t Id; } Voxel; struct { @@ -171,6 +224,15 @@ public: DefEntityId_t getDefId() const { return DefId; } }; +class FuncEntity { + DefFuncEntityId_t DefId; + +public: + FuncEntity(DefFuncEntityId_t defId); + + DefFuncEntityId_t getDefId() const { return DefId; } +}; + template struct VoxelCuboidsFuncs { @@ -292,7 +354,7 @@ struct VoxelCuboidsFuncs { } }; -inline void convertRegionVoxelsToChunks(const std::vector& regions, std::vector *chunks) { +inline void convertRegionVoxelsToChunks(const std::vector& regions, std::unordered_map> &chunks) { for (const auto& region : regions) { int minX = region.Left.x >> 8; int minY = region.Left.y >> 8; @@ -315,30 +377,24 @@ inline void convertRegionVoxelsToChunks(const std::vector& reg static_cast(std::min(((z+1) << 8)-1, region.Right.z) - (z << 8)) }; - int chunkIndex = z * 16 * 16 + y * 16 + x; - chunks[chunkIndex].emplace_back(region.VoxelId, left, right); + chunks[Pos::bvec4u(x, y, z)].push_back({ + region.VoxelId, region.Meta, left, right + }); } } } } } -inline void convertChunkVoxelsToRegion(const std::vector *chunks, std::vector ®ions) { - for (int x = 0; x < 16; ++x) { - for (int y = 0; y < 16; ++y) { - for (int z = 0; z < 16; ++z) { - int chunkIndex = z * 16 * 16 + y * 16 + x; - - Pos::bvec4096u left(x << 8, y << 8, z << 8); - - for (const auto& cube : chunks[chunkIndex]) { - regions.emplace_back( - Pos::bvec4096u(left.x+cube.Left.x, left.y+cube.Left.y, left.z+cube.Left.z), - Pos::bvec4096u(left.x+cube.Right.x, left.y+cube.Right.y, left.z+cube.Right.z), - cube.VoxelId - ); - } - } +inline void convertChunkVoxelsToRegion(const std::unordered_map> &chunks, std::vector ®ions) { + for(const auto& [pos, voxels] : chunks) { + Pos::bvec1024u left = pos << 8; + for (const auto& cube : voxels) { + regions.push_back({ + cube.VoxelId, cube.Meta, + Pos::bvec1024u(left.x+cube.Left.x, left.y+cube.Left.y, left.z+cube.Left.z), + Pos::bvec1024u(left.x+cube.Right.x, left.y+cube.Right.y, left.z+cube.Right.z) + }); } } diff --git a/Src/Server/ContentEventController.cpp b/Src/Server/ContentEventController.cpp index 35d29af..7149f86 100644 --- a/Src/Server/ContentEventController.cpp +++ b/Src/Server/ContentEventController.cpp @@ -13,7 +13,7 @@ ContentEventController::ContentEventController(std::unique_ptr &&r } uint16_t ContentEventController::getViewRangeActive() const { - return 16; + return 1; } uint16_t ContentEventController::getViewRangeBackground() const { @@ -34,9 +34,9 @@ void ContentEventController::checkContentViewChanges() { for(const auto &[regionPos, chunks] : regions) { size_t bitPos = chunks._Find_first(); while(bitPos != chunks.size()) { - Pos::Local16_u chunkPosLocal; - chunkPosLocal = bitPos; - Pos::GlobalChunk chunkPos = regionPos.toChunk(chunkPosLocal); + Pos::bvec4u chunkPosLocal; + chunkPosLocal.unpack(bitPos); + Pos::GlobalChunk chunkPos = (Pos::GlobalChunk(regionPos) << 2) + chunkPosLocal; Remote->prepareChunkRemove(worldId, chunkPos); bitPos = chunks._Find_next(bitPos); } @@ -59,7 +59,7 @@ void ContentEventController::onWorldUpdate(WorldId_t worldId, World *worldObj) } void ContentEventController::onChunksUpdate_Voxels(WorldId_t worldId, Pos::GlobalRegion regionPos, - const std::unordered_map*> &chunks) + const std::unordered_map*>& chunks) { auto pWorld = ContentViewState.find(worldId); if(pWorld == ContentViewState.end()) @@ -69,19 +69,19 @@ void ContentEventController::onChunksUpdate_Voxels(WorldId_t worldId, Pos::Globa if(pRegion == pWorld->second.end()) return; - const std::bitset<4096> &chunkBitset = pRegion->second; + const std::bitset<64> &chunkBitset = pRegion->second; for(auto pChunk : chunks) { - if(!chunkBitset.test(pChunk.first)) + if(!chunkBitset.test(pChunk.first.pack())) continue; - Pos::GlobalChunk chunkPos = regionPos.toChunk(pChunk.first); - Remote->prepareChunkUpdate_Voxels(worldId, chunkPos, *pChunk.second); + Pos::GlobalChunk chunkPos = (Pos::GlobalChunk(regionPos) << 2) + pChunk.first; + Remote->prepareChunkUpdate_Voxels(worldId, chunkPos, pChunk.second); } } void ContentEventController::onChunksUpdate_Nodes(WorldId_t worldId, Pos::GlobalRegion regionPos, - const std::unordered_map*> &chunks) + const std::unordered_map &chunks) { auto pWorld = ContentViewState.find(worldId); if(pWorld == ContentViewState.end()) @@ -91,41 +91,41 @@ void ContentEventController::onChunksUpdate_Nodes(WorldId_t worldId, Pos::Global if(pRegion == pWorld->second.end()) return; - const std::bitset<4096> &chunkBitset = pRegion->second; + const std::bitset<64> &chunkBitset = pRegion->second; for(auto pChunk : chunks) { - if(!chunkBitset.test(pChunk.first)) + if(!chunkBitset.test(pChunk.first.pack())) continue; - Pos::GlobalChunk chunkPos = regionPos.toChunk(pChunk.first); - Remote->prepareChunkUpdate_Nodes(worldId, chunkPos, *pChunk.second); + Pos::GlobalChunk chunkPos = (Pos::GlobalChunk(regionPos) << 2) + Pos::GlobalChunk(pChunk.first); + Remote->prepareChunkUpdate_Nodes(worldId, chunkPos, pChunk.second); } } -void ContentEventController::onChunksUpdate_LightPrism(WorldId_t worldId, Pos::GlobalRegion regionPos, - const std::unordered_map &chunks) -{ - auto pWorld = ContentViewState.find(worldId); - if(pWorld == ContentViewState.end()) - return; +// void ContentEventController::onChunksUpdate_LightPrism(WorldId_t worldId, Pos::GlobalRegion regionPos, +// const std::unordered_map &chunks) +// { +// auto pWorld = ContentViewState.find(worldId); +// if(pWorld == ContentViewState.end()) +// return; - auto pRegion = pWorld->second.find(regionPos); - if(pRegion == pWorld->second.end()) - return; +// auto pRegion = pWorld->second.find(regionPos); +// if(pRegion == pWorld->second.end()) +// return; - const std::bitset<4096> &chunkBitset = pRegion->second; +// const std::bitset<4096> &chunkBitset = pRegion->second; - for(auto pChunk : chunks) { - if(!chunkBitset.test(pChunk.first)) - continue; +// for(auto pChunk : chunks) { +// if(!chunkBitset.test(pChunk.first)) +// continue; - Pos::GlobalChunk chunkPos = regionPos.toChunk(pChunk.first); - Remote->prepareChunkUpdate_LightPrism(worldId, chunkPos, pChunk.second); - } -} +// Pos::GlobalChunk chunkPos = regionPos.toChunk(pChunk.first); +// Remote->prepareChunkUpdate_LightPrism(worldId, chunkPos, pChunk.second); +// } +// } void ContentEventController::onEntityEnterLost(WorldId_t worldId, Pos::GlobalRegion regionPos, - const std::unordered_set &enter, const std::unordered_set &lost) + const std::unordered_set &enter, const std::unordered_set &lost) { auto pWorld = Subscribed.Entities.find(worldId); if(pWorld == Subscribed.Entities.end()) { @@ -141,9 +141,9 @@ void ContentEventController::onEntityEnterLost(WorldId_t worldId, Pos::GlobalReg pRegion = pWorld->second.find(regionPos); } - std::unordered_set &entityesId = pRegion->second; + std::unordered_set &entityesId = pRegion->second; - for(LocalEntityId_t eId : lost) { + for(RegionEntityId_t eId : lost) { entityesId.erase(eId); } @@ -157,13 +157,13 @@ void ContentEventController::onEntityEnterLost(WorldId_t worldId, Pos::GlobalReg } // Сообщить Remote - for(LocalEntityId_t eId : lost) { + for(RegionEntityId_t eId : lost) { Remote->prepareEntityRemove({worldId, regionPos, eId}); } } void ContentEventController::onEntitySwap(WorldId_t lastWorldId, Pos::GlobalRegion lastRegionPos, - LocalEntityId_t lastId, WorldId_t newWorldId, Pos::GlobalRegion newRegionPos, LocalEntityId_t newId) + RegionEntityId_t lastId, WorldId_t newWorldId, Pos::GlobalRegion newRegionPos, RegionEntityId_t newId) { // Проверим отслеживается ли эта сущность нами auto lpWorld = Subscribed.Entities.find(lastWorldId); diff --git a/Src/Server/ContentEventController.hpp b/Src/Server/ContentEventController.hpp index 01dadbb..a77fe9e 100644 --- a/Src/Server/ContentEventController.hpp +++ b/Src/Server/ContentEventController.hpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -35,22 +34,22 @@ struct ContentViewCircle { int32_t Range; inline int32_t sqrDistance(Pos::GlobalRegion regionPos) const { - glm::i32vec3 vec = {Pos.x-((regionPos.X << 4) | 0b1000), Pos.y-((regionPos.Y << 4) | 0b1000), Pos.z-((regionPos.Z << 4) | 0b1000)}; + glm::i32vec3 vec = Pos-(glm::i16vec3) ((Pos::GlobalChunk(regionPos) << 2) | 0b10); return vec.x*vec.x+vec.y*vec.y+vec.z*vec.z; }; inline int32_t sqrDistance(Pos::GlobalChunk chunkPos) const { - glm::i32vec3 vec = {Pos.x-chunkPos.X, Pos.y-chunkPos.Y, Pos.z-chunkPos.Z}; + glm::i32vec3 vec = Pos-(glm::i16vec3) chunkPos; return vec.x*vec.x+vec.y*vec.y+vec.z*vec.z; }; inline int64_t sqrDistance(Pos::Object objectPos) const { - glm::i32vec3 vec = {Pos.x-(objectPos.x >> 20), Pos.y-(objectPos.y >> 20), Pos.z-(objectPos.z >> 20)}; + glm::i32vec3 vec = Pos-(glm::i16vec3) (objectPos >> 12 >> 4); return vec.x*vec.x+vec.y*vec.y+vec.z*vec.z; }; bool isIn(Pos::GlobalRegion regionPos) const { - return sqrDistance(regionPos) < Range+192; // (8×sqrt(3))^2 + return sqrDistance(regionPos) < Range+12; // (2×sqrt(3))^2 } bool isIn(Pos::GlobalChunk chunkPos) const { @@ -62,8 +61,8 @@ struct ContentViewCircle { } }; -// Регион -> чанки попавшие под обозрение Pos::Local16_u -using ContentViewWorld = std::map>; // 1 - чанк виден, 0 - не виден +// Регион -> чанки попавшие под обозрение Pos::bvec4u +using ContentViewWorld = std::map>; // 1 - чанк виден, 0 - не виден struct ContentViewGlobal_DiffInfo; @@ -99,9 +98,9 @@ inline ContentViewGlobal_DiffInfo ContentViewGlobal::calcDiffWith(const ContentV for(const auto &[regionPos, _] : newWorldView) newRegions.push_back(regionPos); } else { - const std::map> &newRegions = newWorldView; - const std::map> &oldRegions = oldWorldIter->second; - std::map> *diffRegions = nullptr; + const std::map> &newRegions = newWorldView; + const std::map> &oldRegions = oldWorldIter->second; + std::map> *diffRegions = nullptr; // Рассматриваем разницу меж регионами for(const auto &[newRegionPos, newRegionBitField] : newRegions) { @@ -113,8 +112,8 @@ inline ContentViewGlobal_DiffInfo ContentViewGlobal::calcDiffWith(const ContentV (*diffRegions)[newRegionPos] = newRegionBitField; newView.Regions[newWorldId].push_back(newRegionPos); } else { - const std::bitset<4096> &oldChunks = oldRegionIter->second; - std::bitset<4096> chunks = (~oldChunks) & newRegionBitField; // Останется поле с новыми чанками + const std::bitset<64> &oldChunks = oldRegionIter->second; + std::bitset<64> chunks = (~oldChunks) & newRegionBitField; // Останется поле с новыми чанками if(chunks._Find_first() != chunks.size()) { // Есть новые чанки if(!diffRegions) @@ -157,7 +156,8 @@ private: struct SubscribedObj { // Используется регионами std::vector Portals; - std::unordered_map>> Entities; + std::unordered_map>> Entities; + std::unordered_map>> FuncEntities; } Subscribed; public: @@ -168,6 +168,8 @@ public: // Объявленная в чанках территория точно отслеживается (активная зона) ContentViewGlobal ContentViewState; ContentViewGlobal_DiffInfo ContentView_NewView, ContentView_LostView; + // Миры добавленные в наблюдение в текущем такте + std::vector NewWorlds; // size_t CVCHash = 0; // Хэш для std::vector // std::unordered_map> SubscribedRegions; @@ -190,14 +192,18 @@ public: void onWorldUpdate(WorldId_t worldId, World *worldObj); // Нужно фильтровать неотслеживаемые чанки - void onChunksUpdate_Voxels(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_map*> &chunks); - void onChunksUpdate_Nodes(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_map*> &chunks); - void onChunksUpdate_LightPrism(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_map &chunks); + void onChunksUpdate_Voxels(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_map*> &chunks); + void onChunksUpdate_Nodes(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_map &chunks); + //void onChunksUpdate_LightPrism(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_map &chunks); - void onEntityEnterLost(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_set &enter, const std::unordered_set &lost); - void onEntitySwap(WorldId_t lastWorldId, Pos::GlobalRegion lastRegionPos, LocalEntityId_t lastId, WorldId_t newWorldId, Pos::GlobalRegion newRegionPos, LocalEntityId_t newId); + void onEntityEnterLost(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_set &enter, const std::unordered_set &lost); + void onEntitySwap(WorldId_t lastWorldId, Pos::GlobalRegion lastRegionPos, RegionEntityId_t lastId, WorldId_t newWorldId, Pos::GlobalRegion newRegionPos, RegionEntityId_t newId); void onEntityUpdates(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::vector &entities); + void onFuncEntityEnterLost(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_set &enter, const std::unordered_set &lost); + void onFuncEntitySwap(WorldId_t lastWorldId, Pos::GlobalRegion lastRegionPos, RegionEntityId_t lastId, WorldId_t newWorldId, Pos::GlobalRegion newRegionPos, RegionEntityId_t newId); + void onFuncEntityUpdates(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::vector &entities); + void onPortalEnterLost(const std::vector &enter, const std::vector &lost); void onPortalUpdates(const std::vector &portals); diff --git a/Src/Server/GameServer.cpp b/Src/Server/GameServer.cpp index cb91e5a..91eff41 100644 --- a/Src/Server/GameServer.cpp +++ b/Src/Server/GameServer.cpp @@ -110,7 +110,7 @@ void GameServer::Expanse_t::_accumulateContentViewCircles(ContentViewCircle circ ContentViewGlobal GameServer::Expanse_t::makeContentViewGlobal(const std::vector &views) { ContentViewGlobal cvg; Pos::GlobalRegion posRegion, lastPosRegion; - std::bitset<4096> *cache = nullptr; + std::bitset<64> *cache = nullptr; for(const ContentViewCircle &circle : views) { ContentViewWorld &cvw = cvg[circle.WorldId]; @@ -123,14 +123,14 @@ ContentViewGlobal GameServer::Expanse_t::makeContentViewGlobal(const std::vector continue; Pos::GlobalChunk posChunk(x+circle.Pos.x, y+circle.Pos.y, z+circle.Pos.z); - posRegion.fromChunk(posChunk); + posRegion = posChunk >> 2; if(!cache || lastPosRegion != posRegion) { lastPosRegion = posRegion; cache = &cvw[posRegion]; } - cache->_Unchecked_set(posChunk.toLocal()); + cache->_Unchecked_set(Pos::bvec4u(posChunk).pack()); } } @@ -279,17 +279,19 @@ Region* GameServer::forceGetRegion(WorldId_t worldId, Pos::GlobalRegion pos) { region->IsLoaded = true; region->load(&data); } else { - region->IsLoaded = true; - if(pos.Y == 0) { - for(int z = 0; z < 16; z++) - for(int x = 0; x < 16; x++) { - region->Voxels[x][0][z].push_back({0, {0, 0, 0}, {255, 255, 255},}); - } + if(pos.y == 0) { + for(int z = 0; z < 4; z++) + for(int y = 0; y < 4; y++) + for(int x = 0; x < 4; x++) { + Node *nodes = (Node*) ®ion->Nodes[0][0][0][z][y][x]; + for(int index = 0; index < 16*16*16; index++) + nodes[index] = {static_cast(y == 0 ? 1 : 0), 0}; + region->IsChunkChanged_Nodes |= (y == 0 ? 1 : 0) << (z*4*4+y*4+x); + } } } - std::fill(region->IsChunkChanged_Voxels, region->IsChunkChanged_Voxels+64, ~0); return region.get(); } else { return iterRegion->second.get(); @@ -403,27 +405,43 @@ void GameServer::run() { } void GameServer::stepContent() { - Content.TextureM.update(CurrentTickDuration); - if(Content.TextureM.hasPreparedInformation()) { - auto table = Content.TextureM.takePreparedInformation(); + Content.Texture.update(CurrentTickDuration); + if(Content.Texture.hasPreparedInformation()) { + auto table = Content.Texture.takePreparedInformation(); for(std::unique_ptr &cec : Game.CECs) { - cec->Remote->informateDefTexture(table); + cec->Remote->informateBinTexture(table); } } - Content.ModelM.update(CurrentTickDuration); - if(Content.ModelM.hasPreparedInformation()) { - auto table = Content.ModelM.takePreparedInformation(); + Content.Animation.update(CurrentTickDuration); + if(Content.Animation.hasPreparedInformation()) { + auto table = Content.Animation.takePreparedInformation(); for(std::unique_ptr &cec : Game.CECs) { - cec->Remote->informateDefTexture(table); + cec->Remote->informateBinAnimation(table); } } - Content.SoundM.update(CurrentTickDuration); - if(Content.SoundM.hasPreparedInformation()) { - auto table = Content.SoundM.takePreparedInformation(); + Content.Model.update(CurrentTickDuration); + if(Content.Model.hasPreparedInformation()) { + auto table = Content.Model.takePreparedInformation(); for(std::unique_ptr &cec : Game.CECs) { - cec->Remote->informateDefTexture(table); + cec->Remote->informateBinModel(table); + } + } + + Content.Sound.update(CurrentTickDuration); + if(Content.Sound.hasPreparedInformation()) { + auto table = Content.Sound.takePreparedInformation(); + for(std::unique_ptr &cec : Game.CECs) { + cec->Remote->informateBinSound(table); + } + } + + Content.Font.update(CurrentTickDuration); + if(Content.Font.hasPreparedInformation()) { + auto table = Content.Font.takePreparedInformation(); + for(std::unique_ptr &cec : Game.CECs) { + cec->Remote->informateBinFont(table); } } } @@ -502,6 +520,17 @@ void GameServer::stepWorlds() { for(auto &pair : Expanse.Worlds) pair.second->onUpdate(this, CurrentTickDuration); + // Оповещаем о новых мирах + for(const std::unique_ptr& cec : Game.CECs) { + for(WorldId_t id : cec->NewWorlds) { + auto iter = Expanse.Worlds.find(id); + assert(iter != Expanse.Worlds.end()); + cec->onWorldUpdate(id, iter->second.get()); + } + + cec->NewWorlds.clear(); + } + for(auto &pWorld : Expanse.Worlds) { World &wobj = *pWorld.second; @@ -675,10 +704,10 @@ void GameServer::stepWorlds() { if(rPos != pRegion.first || pWorld.first != entity.WorldId) { Region *toRegion = forceGetRegion(entity.WorldId, rPos); - LocalEntityId_t newId = toRegion->pushEntity(entity); + RegionEntityId_t newId = toRegion->pushEntity(entity); // toRegion->Entityes[newId].WorldId = Если мир изменился - if(newId == LocalEntityId_t(-1)) { + if(newId == RegionEntityId_t(-1)) { // В другом регионе нет места } else { entity.IsRemoved = true; @@ -692,45 +721,42 @@ void GameServer::stepWorlds() { } // Проверить необходимость перерасчёта вертикальной проходимости света - std::unordered_map ChangedLightPrism; - { - for(int big = 0; big < 64; big++) { - uint64_t bits = region.IsChunkChanged_Voxels[big] | region.IsChunkChanged_Nodes[big]; + // std::unordered_map ChangedLightPrism; + // { + // for(int big = 0; big < 64; big++) { + // uint64_t bits = region.IsChunkChanged_Voxels[big] | region.IsChunkChanged_Nodes[big]; - if(!bits) - continue; + // if(!bits) + // continue; - for(int little = 0; little < 64; little++) { - if(((bits >> little) & 1) == 0) - continue; + // for(int little = 0; little < 64; little++) { + // if(((bits >> little) & 1) == 0) + // continue; - } - } - } + // } + // } + // } // Сбор данных об изменившихся чанках - std::unordered_map*> ChangedVoxels; - std::unordered_map*> ChangedNodes; + std::unordered_map*> ChangedVoxels; + std::unordered_map ChangedNodes; { + if(!region.IsChunkChanged_Voxels && !region.IsChunkChanged_Nodes) + continue; - for(int big = 0; big < 64; big++) { - uint64_t bits_voxels = region.IsChunkChanged_Voxels[big]; - uint64_t bits_nodes = region.IsChunkChanged_Nodes[big]; + for(int index = 0; index < 64; index++) { + Pos::bvec4u pos; + pos.unpack(index); - if(!bits_voxels && !bits_nodes) - continue; + if(((region.IsChunkChanged_Voxels >> index) & 1) == 1) { + auto iter = region.Voxels.find(pos); + assert(iter != region.Voxels.end()); + ChangedVoxels[pos] = &iter->second; + } - for(int little = 0; little < 64; little++) { - Pos::Local16_u pos(little & 0xf, ((big & 0x3) << 2) | (little >> 4), big >> 2); - - if(((bits_voxels >> little) & 1) == 1) { - ChangedVoxels[pos] = ®ion.Voxels[pos.X][pos.Y][pos.Z]; - } - - if(((bits_nodes >> little) & 1) == 1) { - ChangedNodes[pos] = ®ion.Nodes[pos.X][pos.Y][pos.Z]; - } + if(((region.IsChunkChanged_Nodes >> index) & 1) == 1) { + ChangedNodes[pos] = (Node*) ®ion.Nodes[0][0][0][pos.x][pos.y][pos.z]; } } } @@ -762,11 +788,11 @@ void GameServer::stepWorlds() { continue; // Наблюдаемые чанки - const std::bitset<4096> &chunkBitset = chunkBitsetIter->second; + const std::bitset<64> &chunkBitset = chunkBitsetIter->second; // Пересылка изменений в регионе - if(!ChangedLightPrism.empty()) - cec->onChunksUpdate_LightPrism(pWorld.first, pRegion.first, ChangedLightPrism); + // if(!ChangedLightPrism.empty()) + // cec->onChunksUpdate_LightPrism(pWorld.first, pRegion.first, ChangedLightPrism); if(!ChangedVoxels.empty()) cec->onChunksUpdate_Voxels(pWorld.first, pRegion.first, ChangedVoxels); @@ -776,31 +802,31 @@ void GameServer::stepWorlds() { // Отправка полной информации о новых наблюдаемых чанках { - const std::bitset<4096> *new_chunkBitset = nullptr; + const std::bitset<64> *new_chunkBitset = nullptr; try { new_chunkBitset = &cec->ContentView_NewView.View.at(pWorld.first).at(pRegion.first); } catch(...) {} if(new_chunkBitset) { - std::unordered_map newLightPrism; - std::unordered_map*> newVoxels; - std::unordered_map*> newNodes; + //std::unordered_map newLightPrism; + std::unordered_map*> newVoxels; + std::unordered_map newNodes; - newLightPrism.reserve(new_chunkBitset->count()); + //newLightPrism.reserve(new_chunkBitset->count()); newVoxels.reserve(new_chunkBitset->count()); newNodes.reserve(new_chunkBitset->count()); size_t bitPos = new_chunkBitset->_Find_first(); while(bitPos != new_chunkBitset->size()) { - Pos::Local16_u chunkPos; + Pos::bvec4u chunkPos; chunkPos = bitPos; - newLightPrism.insert({chunkPos, ®ion.Lights[0][0][chunkPos.X][chunkPos.Y][chunkPos.Z]}); - newVoxels.insert({chunkPos, ®ion.Voxels[chunkPos.X][chunkPos.Y][chunkPos.Z]}); - newNodes.insert({chunkPos, ®ion.Nodes[chunkPos.X][chunkPos.Y][chunkPos.Z]}); + //newLightPrism.insert({chunkPos, ®ion.Lights[0][0][chunkPos.X][chunkPos.Y][chunkPos.Z]}); + newVoxels.insert({chunkPos, ®ion.Voxels[chunkPos]}); + newNodes.insert({chunkPos, ®ion.Nodes[0][0][0][chunkPos.x][chunkPos.y][chunkPos.z]}); bitPos = new_chunkBitset->_Find_next(bitPos); } - cec->onChunksUpdate_LightPrism(pWorld.first, pRegion.first, newLightPrism); + //cec->onChunksUpdate_LightPrism(pWorld.first, pRegion.first, newLightPrism); cec->onChunksUpdate_Voxels(pWorld.first, pRegion.first, newVoxels); cec->onChunksUpdate_Nodes(pWorld.first, pRegion.first, newNodes); } @@ -894,7 +920,7 @@ void GameServer::stepWorlds() { region.IsChanged = false; SB_Region data; - convertChunkVoxelsToRegion((const std::vector*) region.Voxels, data.Voxels); + convertChunkVoxelsToRegion(region.Voxels, data.Voxels); SaveBackend.World->save(worldStringId, pRegion.first, &data); } @@ -904,9 +930,8 @@ void GameServer::stepWorlds() { } // Сброс информации об изменившихся данных - - std::fill(region.IsChunkChanged_Voxels, region.IsChunkChanged_Voxels+64, 0); - std::fill(region.IsChunkChanged_Nodes, region.IsChunkChanged_Nodes+64, 0); + region.IsChunkChanged_Voxels = 0; + region.IsChunkChanged_Nodes = 0; } for(Pos::GlobalRegion regionPos : regionsToRemove) { @@ -931,7 +956,7 @@ void GameServer::stepWorlds() { // TODO: Передефайнить идентификаторы нод - convertRegionVoxelsToChunks(data.Voxels, (std::vector*) robj.Voxels); + convertRegionVoxelsToChunks(data.Voxels, robj.Voxels); } } @@ -980,6 +1005,22 @@ void GameServer::stepViewContent() { ContentViewGlobal_DiffInfo lostView = cec.ContentViewState.calcDiffWith(newCbg); if(!newView.empty() || !lostView.empty()) { lost_CVG.insert({&cec, {newView}}); + + std::vector newWorlds, lostWorlds; + + // Поиск потерянных миров + for(const auto& [key, _] : cec.ContentViewState) { + if(!newCbg.contains(key)) + lostWorlds.push_back(key); + } + + // Поиск новых увиденных миров + for(const auto& [key, _] : newCbg) { + if(!cec.ContentViewState.contains(key)) + newWorlds.push_back(key); + } + + cec.NewWorlds = std::move(newWorlds); cec.ContentViewState = std::move(newCbg); cec.ContentView_NewView = std::move(newView); cec.ContentView_LostView = std::move(lostView); @@ -1011,15 +1052,20 @@ void GameServer::stepSendPlayersPackets() { full.uniq(); - if(!full.NewTextures.empty()) - Content.TextureM.needResourceResponse(full.NewTextures); + if(!full.BinTexture.empty()) + Content.Texture.needResourceResponse(full.BinTexture); - if(!full.NewModels.empty()) - Content.ModelM.needResourceResponse(full.NewModels); + if(!full.BinAnimation.empty()) + Content.Animation.needResourceResponse(full.BinAnimation); - if(!full.NewSounds.empty()) - Content.SoundM.needResourceResponse(full.NewSounds); + if(!full.BinModel.empty()) + Content.Model.needResourceResponse(full.BinModel); + if(!full.BinSound.empty()) + Content.Sound.needResourceResponse(full.BinSound); + + if(!full.BinFont.empty()) + Content.Font.needResourceResponse(full.BinFont); } void GameServer::stepLoadRegions() { diff --git a/Src/Server/GameServer.hpp b/Src/Server/GameServer.hpp index c0e737f..0392062 100644 --- a/Src/Server/GameServer.hpp +++ b/Src/Server/GameServer.hpp @@ -19,7 +19,6 @@ #include "World.hpp" #include "SaveBackend.hpp" -#include "boost/asio/ip/address.hpp" namespace LV::Server { @@ -51,20 +50,24 @@ class GameServer : public AsyncObject { // WorldDefManager WorldDM; // VoxelDefManager VoxelDM; // NodeDefManager NodeDM; - BinaryResourceManager TextureM; - BinaryResourceManager ModelM; - BinaryResourceManager SoundM; + BinaryResourceManager Texture; + BinaryResourceManager Animation; + BinaryResourceManager Model; + BinaryResourceManager Sound; + BinaryResourceManager Font; ContentObj(asio::io_context &ioc, std::shared_ptr zeroTexture, + std::shared_ptr zeroAnimation, std::shared_ptr zeroModel, - std::shared_ptr zeroSound) - : TextureM(ioc, zeroTexture), - ModelM(ioc, zeroModel), - SoundM(ioc, zeroSound) - { - - } + std::shared_ptr zeroSound, + std::shared_ptr zeroFont) + : Texture(ioc, zeroTexture), + Animation(ioc, zeroAnimation), + Model(ioc, zeroModel), + Sound(ioc, zeroSound), + Font(ioc, zeroFont) + {} } Content; @@ -114,7 +117,7 @@ class GameServer : public AsyncObject { public: GameServer(asio::io_context &ioc, fs::path worldPath) : AsyncObject(ioc), - Content(ioc, nullptr, nullptr, nullptr) + Content(ioc, nullptr, nullptr, nullptr, nullptr, nullptr) { init(worldPath); } diff --git a/Src/Server/RemoteClient.cpp b/Src/Server/RemoteClient.cpp index 0d61d74..e851e38 100644 --- a/Src/Server/RemoteClient.cpp +++ b/Src/Server/RemoteClient.cpp @@ -1,7 +1,9 @@ #include #include "RemoteClient.hpp" +#include "Common/Abstract.hpp" #include "Common/Net.hpp" #include "Server/Abstract.hpp" +#include #include #include #include @@ -65,269 +67,298 @@ void RemoteClient::shutdown(EnumDisconnect type, const std::string reason) { LOG.info() << "Игрок '" << Username << "' отключился " << info; } - -// Может прийти событие на чанк, про который ещё ничего не знаем void RemoteClient::prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk chunkPos, - const std::vector &voxels) + const std::vector* voxels) { - WorldId_c wcId = worldId ? ResRemap.Worlds.toClient(worldId) : 0; - assert(wcId != WorldId_c(-1)); // Пока ожидается, что игрок не будет одновременно наблюдать 256 миров + /* + Обновить зависимости + Запросить недостающие + Отправить всё клиенту + */ - // Перебиндить идентификаторы вокселей - std::vector NeedVoxels; - NeedVoxels.reserve(voxels.size()); + std::vector + newTypes, /* Новые типы вокселей */ + lostTypes /* Потерянные типы вокселей */; - for(const VoxelCube &cube : voxels) { - NeedVoxels.push_back(cube.VoxelId); - } - - std::unordered_set NeedVoxelsSet(NeedVoxels.begin(), NeedVoxels.end()); - - // Собираем информацию о конвертации идентификаторов - std::unordered_map LocalRemapper; - for(DefVoxelId_t vId : NeedVoxelsSet) { - LocalRemapper[vId] = ResRemap.DefVoxels.toClient(vId); - } - - // Проверить новые и забытые определения вокселей - { - std::unordered_set &prevSet = ResUses.ChunkVoxels[{worldId, chunkPos}]; - std::unordered_set &nextSet = NeedVoxelsSet; - - std::vector newVoxels, lostVoxels; - for(DefVoxelId_t id : prevSet) { - if(!nextSet.contains(id)) { - if(--ResUses.DefVoxel[id] == 0) { - // Определение больше не используется - - ResUses.DefVoxel.erase(ResUses.DefVoxel.find(id)); - DefVoxelId_c cId = ResRemap.DefVoxels.erase(id); - // TODO: отправить пакет потери идентификатора - LOG.debug() << "Определение вокселя потеряно: " << id << " -> " << cId; - } - } + // Обновить зависимости вокселей + std::vector v; + if(voxels) { + v.reserve(voxels->size()); + for(const VoxelCube& value : *voxels) { + v.push_back(value.VoxelId); } - for(DefVoxelId_t id : nextSet) { - if(!prevSet.contains(id)) { - if(++ResUses.DefVoxel[id] == 1) { - // Определение только появилось - NextRequest.NewVoxels.push_back(id); - DefVoxelId_c cId = ResRemap.DefVoxels.toClient(id); - LOG.debug() << "Новое определение вокселя: " << id << " -> " << cId; - } - } - } + std::sort(v.begin(), v.end()); + auto last = std::unique(v.begin(), v.end()); + v.erase(last, v.end()); - prevSet = std::move(nextSet); - } - - checkPacketBorder(voxels.size()*(2+6)+16); - - 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; - } + // В v отсортированный список уникальных вокселей в чанке + + // Отметим использование этих вокселей + for(const DefVoxelId_t& id : v) { + auto iter = ResUses.DefVoxel.find(id); + if(iter == ResUses.DefVoxel.end()) { + // Новый тип + newTypes.push_back(id); + ResUses.DefVoxel[id] = 1; + } else { + // Увеличиваем счётчик + iter->second++; + } + } + } + + // Исключим зависимости предыдущей версии чанка + auto iterWorld = ResUses.RefChunk.find(worldId); + assert(iterWorld != ResUses.RefChunk.end()); + { + auto iterChunk = iterWorld->second.find(chunkPos); + if(iterChunk != iterWorld->second.end()) { + // Раньше этот чанк был, значит не новый для клиента + // Уменьшим счётчик зависимостей + for(const DefVoxelId_t& id : iterChunk->second.Voxel) { + auto iter = ResUses.DefVoxel.find(id); + assert(iter != ResUses.DefVoxel.end()); // Воксель должен быть в зависимостях + if(--iter->second == 0) { + // Вокселя больше нет в зависимостях + lostTypes.push_back(id); + ResUses.DefVoxel.erase(iter); + } + } + } + } + + iterWorld->second[chunkPos].Voxel = v; + + if(!newTypes.empty()) { + // Добавляем новые типы в запрос + NextRequest.Voxel.insert(NextRequest.Voxel.end(), newTypes.begin(), newTypes.end()); + } + + if(!lostTypes.empty()) { + for(const DefVoxelId_t& id : lostTypes) { + auto iter = ResUses.RefDefVoxel.find(id); + assert(iter != ResUses.RefDefVoxel.end()); // Должны быть описаны зависимости вокселя + decrementBinary(std::move(iter->second.Texture), {}, std::move(iter->second.Sound), {}, {}); + ResUses.RefDefVoxel.erase(iter); + } + } + + // TODO: отправить чанк } -void RemoteClient::prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::GlobalChunk chunkPos, - const std::unordered_map &nodes) -{ +void RemoteClient::prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::GlobalChunk chunkPos, const Node* nodes) { + std::vector + newTypes, /* Новые типы нод */ + lostTypes /* Потерянные типы нод */; -} + // Обновить зависимости нод + std::vector n; + { + n.reserve(16*16*16); + for(size_t iter = 0; iter < 16*16*16; iter++) { + n.push_back(nodes[iter].NodeId); + } -void RemoteClient::prepareChunkUpdate_LightPrism(WorldId_t worldId, Pos::GlobalChunk chunkPos, - const LightPrism *lights) -{ + std::sort(n.begin(), n.end()); + auto last = std::unique(n.begin(), n.end()); + n.erase(last, n.end()); + // В n отсортированный список уникальных нод в чанке + + // Отметим использование этих нод + for(const DefNodeId_t& id : n) { + auto iter = ResUses.DefNode.find(id); + if(iter == ResUses.DefNode.end()) { + // Новый тип + newTypes.push_back(id); + ResUses.DefNode[id] = 1; + } else { + // Увеличиваем счётчик + iter->second++; + LOG.debug() << "id = " << id << ' ' << iter->second; + } + } + } + + auto iterWorld = ResUses.RefChunk.find(worldId); + assert(iterWorld != ResUses.RefChunk.end()); + // Исключим зависимости предыдущей версии чанка + { + + auto iterChunk = iterWorld->second.find(chunkPos); + if(iterChunk != iterWorld->second.end()) { + // Раньше этот чанк был, значит не новый для клиента + // Уменьшим счётчик зависимостей + for(const DefNodeId_t& id : iterChunk->second.Node) { + auto iter = ResUses.DefNode.find(id); + assert(iter != ResUses.DefNode.end()); // Нода должна быть в зависимостях + if(--iter->second == 0) { + // Ноды больше нет в зависимостях + lostTypes.push_back(id); + ResUses.DefNode.erase(iter); + } + } + } + } + + iterWorld->second[chunkPos].Node = n; + + if(!newTypes.empty()) { + // Добавляем новые типы в запрос + NextRequest.Node.insert(NextRequest.Node.end(), newTypes.begin(), newTypes.end()); + } + + if(!lostTypes.empty()) { + for(const DefNodeId_t& id : lostTypes) { + auto iter = ResUses.RefDefNode.find(id); + assert(iter != ResUses.RefDefNode.end()); // Должны быть описаны зависимости ноды + decrementBinary({}, {}, std::move(iter->second.Sound), std::move(iter->second.Model), {}); + ResUses.RefDefNode.erase(iter); + } + } + + // TODO: отправить чанк + LOG.debug() << "Увидели " << chunkPos.x << ' ' << chunkPos.y << ' ' << chunkPos.z; } void RemoteClient::prepareChunkRemove(WorldId_t worldId, Pos::GlobalChunk chunkPos) { - // Понизим зависимости ресурсов - std::unordered_set &prevSet = ResUses.ChunkVoxels[{worldId, chunkPos}]; - for(DefVoxelId_t id : prevSet) { - if(--ResUses.DefVoxel[id] == 0) { - // Определение больше не используется + LOG.debug() << "Потеряли " << chunkPos.x << ' ' << chunkPos.y << ' ' << chunkPos.z; + std::vector + lostTypesV /* Потерянные типы вокселей */; + std::vector + lostTypesN /* Потерянные типы нод */; - ResUses.DefVoxel.erase(ResUses.DefVoxel.find(id)); - DefVoxelId_c cId = ResRemap.DefVoxels.erase(id); - // TODO: отправить пакет потери идентификатора - LOG.debug() << "Определение вокселя потеряно: " << id << " -> " << cId; + // Уменьшаем зависимости вокселей и нод + { + auto iterWorld = ResUses.RefChunk.find(worldId); + assert(iterWorld != ResUses.RefChunk.end()); + + auto iterChunk = iterWorld->second.find(chunkPos); + assert(iterChunk != iterWorld->second.end()); + + // Уменьшим счётчики зависимостей + for(const DefVoxelId_t& id : iterChunk->second.Voxel) { + auto iter = ResUses.DefVoxel.find(id); + assert(iter != ResUses.DefVoxel.end()); // Воксель должен быть в зависимостях + if(--iter->second == 0) { + // Ноды больше нет в зависимостях + lostTypesV.push_back(id); + ResUses.DefVoxel.erase(iter); + } + } + + for(const DefNodeId_t& id : iterChunk->second.Node) { + auto iter = ResUses.DefNode.find(id); + assert(iter != ResUses.DefNode.end()); // Нода должна быть в зависимостях + if(--iter->second == 0) { + // Ноды больше нет в зависимостях + lostTypesN.push_back(id); + ResUses.DefNode.erase(iter); + } } } - WorldId_c cwId = worldId ? ResRemap.Worlds.toClient(worldId) : worldId; + if(!lostTypesV.empty()) { + for(const DefVoxelId_t& id : lostTypesV) { + auto iter = ResUses.RefDefVoxel.find(id); + assert(iter != ResUses.RefDefVoxel.end()); // Должны быть описаны зависимости вокселя + decrementBinary(std::move(iter->second.Texture), {}, std::move(iter->second.Sound), {}, {}); + ResUses.RefDefVoxel.erase(iter); + } + } + + if(!lostTypesN.empty()) { + for(const DefNodeId_t& id : lostTypesN) { + auto iter = ResUses.RefDefNode.find(id); + assert(iter != ResUses.RefDefNode.end()); // Должны быть описаны зависимости ноды + decrementBinary({}, {}, std::move(iter->second.Sound), std::move(iter->second.Model), {}); + ResUses.RefDefNode.erase(iter); + } + } checkPacketBorder(16); NextPacket << (uint8_t) ToClient::L1::Content << (uint8_t) ToClient::L2Content::RemoveChunk - << cwId << Pos::GlobalChunk::Key(chunkPos); + << worldId << chunkPos.pack(); } -void RemoteClient::prepareWorldUpdate(WorldId_t worldId, World* world) +void RemoteClient::prepareEntityUpdate(ServerEntityId_t entityId, const Entity *entity) { - ResUsesObj::WorldResourceUse &res = ResUses.Worlds[worldId]; + // Сопоставим с идентификатором клиента + ClientEntityId_t ceId = ResRemap.Entityes.toClient(entityId); - auto iter = ResUses.Worlds.find(worldId); - if(iter == ResUses.Worlds.end()) { - // Новый мир - WorldId_c cwId = ResRemap.Worlds.toClient(worldId); - - ResUsesObj::WorldResourceUse &res = iter->second; - res.DefId = world->getDefId(); - - if(++ResUses.DefWorld[res.DefId] == 1) { - // Новое определение - NextRequest.NewWorlds.push_back(res.DefId); - DefWorldId_c cdId = ResRemap.DefWorlds.toClient(res.DefId); - - LOG.debug() << "Новое определение мира: " << res.DefId << " -> " << int(cdId); - NextPacket << (uint8_t) ToClient::L1::Definition - << (uint8_t) ToClient::L2Definition::World - << cdId; - - // incrementBinary(Textures, Sounds, Models); - } - - incrementBinary(res.Textures, res.Sounds, res.Models); - - LOG.debug() << "Новый мир: " << worldId << " -> " << int(cwId); - - } else { - if(res.DefId != world->getDefId()) { - DefWorldId_t newDef = world->getDefId(); - - if(--ResUses.DefWorld[res.DefId] == 0) { - // Определение больше не используется - ResUses.DefWorld.erase(ResUses.DefWorld.find(res.DefId)); - DefWorldId_c cdId = ResRemap.DefWorlds.erase(res.DefId); - - // TODO: отправить пакет потери идентификатора - LOG.debug() << "Определение мира потеряно: " << res.DefId << " -> " << cdId; - } - - if(++ResUses.DefWorld[newDef] == 1) { - // Новое определение мира - DefWorldId_c cdId = ResRemap.DefWorlds.toClient(newDef); - NextRequest.NewWorlds.push_back(newDef); - - // incrementBinary(Textures, Sounds, Models); - // TODO: отправить пакет о новом определении мира - LOG.debug() << "Новое определение мира: " << newDef << " -> " << cdId; - } - - res.DefId = newDef; - } - - // TODO: определить различия между переопределением поверх определений - std::unordered_set lostTextures, newTextures; - std::unordered_set lostSounds, newSounds; - std::unordered_set lostModels, newModels; - - decrementBinary(lostTextures, lostSounds, lostModels); - decrementBinary(newTextures, newSounds, newModels); - - WorldId_c cId = worldId ? ResRemap.Worlds.toClient(worldId) : worldId; - // TODO: отправить пакет об изменении мира - LOG.debug() << "Изменение мира: " << worldId << " -> " << cId; - } -} - -void RemoteClient::prepareWorldRemove(WorldId_t worldId) -{ - // Чанки уже удалены prepareChunkRemove - // Понизим зависимости ресурсов - ResUsesObj::WorldResourceUse &res = ResUses.Worlds[worldId]; - - WorldId_c cWorld = worldId ? ResUses.Worlds.erase(worldId) : worldId; - LOG.debug() << "Мир потерян: " << worldId << " -> " << cWorld; - - NextPacket << (uint8_t) ToClient::L1::Content - << (uint8_t) ToClient::L2Content::RemoveWorld - << cWorld; - - if(--ResUses.DefWorld[res.DefId] == 0) { - // Определение мира потеряно - ResUses.DefWorld.erase(ResUses.DefWorld.find(res.DefId)); - DefWorldId_c cdWorld = ResRemap.DefWorlds.erase(res.DefId); - - // TODO: отправить пакет о потере определения мира - LOG.debug() << "Определение мира потеряно: " << res.DefId << " -> " << cdWorld; + // Профиль новый + { + DefEntityId_t profile = entity->getDefId(); + auto iter = ResUses.DefEntity.find(profile); + if(iter == ResUses.DefEntity.end()) { + // Клиенту неизвестен профиль + NextRequest.Entity.push_back(profile); + ResUses.DefEntity[profile] = 1; + } else + iter->second++; } - decrementBinary(res.Textures, res.Sounds, res.Models); + // Добавление модификационных зависимостей + // incrementBinary({}, {}, {}, {}, {}); + + // Старые данные + { + auto iterEntity = ResUses.RefEntity.find(entityId); + if(iterEntity != ResUses.RefEntity.end()) { + // Убавляем зависимость к старому профилю + auto iterProfile = ResUses.DefEntity.find(iterEntity->second.Profile); + assert(iterProfile != ResUses.DefEntity.end()); // Старый профиль должен быть + if(--iterProfile->second == 0) { + // Старый профиль больше не нужен + auto iterProfileRef = ResUses.RefDefEntity.find(iterEntity->second.Profile); + decrementBinary(std::move(iterProfileRef->second.Texture), std::move(iterProfileRef->second.Animation), {}, + std::move(iterProfileRef->second.Model), {}); + ResUses.DefEntity.erase(iterProfile); + } + + // Убавляем зависимость к модификационным данным + // iterEntity->second. + // decrementBinary({}, {}, {}, {}, {}); + } + } + + // TODO: отправить клиенту } -void RemoteClient::prepareEntitySwap(GlobalEntityId_t prev, GlobalEntityId_t next) +void RemoteClient::prepareEntitySwap(ServerEntityId_t prev, ServerEntityId_t next) { ResRemap.Entityes.rebindClientKey(prev, next); - LOG.debug() << "Ребинд сущности: " << std::get<0>(prev) << " / " << std::get<1>(prev).X << ":" - << std::get<1>(prev).Y << ":" << std::get<1>(prev).Z << " / " << std::get<2>(prev) - << " -> " << std::get<0>(next) << " / " << std::get<1>(next).X << ":" - << std::get<1>(next).Y << ":" << std::get<1>(next).Z << " / " << std::get<2>(next); } -void RemoteClient::prepareEntityUpdate(GlobalEntityId_t entityId, const Entity *entity) +void RemoteClient::prepareEntityRemove(ServerEntityId_t entityId) { - // Может прийти событие на сущность, про которую ещё ничего не знаем + ClientEntityId_t cId = ResRemap.Entityes.erase(entityId); - // Сопоставим с идентификатором клиента - EntityId_c ceId = ResRemap.Entityes.toClient(entityId); + // Убавляем старые данные + { + auto iterEntity = ResUses.RefEntity.find(entityId); + assert(iterEntity != ResUses.RefEntity.end()); // Зависимости должны быть - auto iter = ResUses.Entity.find(entityId); - if(iter == ResUses.Entity.end()) { - // Новая сущность + // Убавляем модификационные заависимости + //decrementBinary(std::vector &&textures, std::vector &&animation, std::vector &&sounds, std::vector &&models, std::vector &&fonts) + + // Убавляем зависимость к профилю + auto iterProfile = ResUses.DefEntity.find(iterEntity->second.Profile); + assert(iterProfile != ResUses.DefEntity.end()); // Профиль должен быть + if(--iterProfile->second == 0) { + // Профиль больше не используется + auto iterProfileRef = ResUses.RefDefEntity.find(iterEntity->second.Profile); - // WorldId_c cwId = ResRemap.Worlds.toClient(std::get<0>(entityId)); - - ResUsesObj::EntityResourceUse &res = ResUses.Entity[entityId]; - res.DefId = entity->getDefId(); - - if(++ResUses.DefEntity[res.DefId] == 1) { - // Новое определение - NextRequest.NewEntityes.push_back(res.DefId); - DefEntityId_c cId = ResRemap.DefEntityes.toClient(res.DefId); - LOG.debug() << "Новое определение сущности: " << res.DefId << " -> " << cId; - // TODO: Отправить пакет о новом определении - - // incrementBinary(Textures, Sounds, Models); + decrementBinary(std::move(iterProfileRef->second.Texture), std::move(iterProfileRef->second.Animation), {}, std::move(iterProfileRef->second.Model), {}); + + ResUses.RefDefEntity.erase(iterProfileRef); + ResUses.DefEntity.erase(iterProfile); } - - incrementBinary(res.Textures, res.Sounds, res.Models); - - LOG.debug() << "Новая сущность: " << std::get<0>(entityId) << " / " << std::get<1>(entityId).X << ":" - << std::get<1>(entityId).Y << ":" << std::get<1>(entityId).Z << " / " << std::get<2>(entityId) - << " -> " << ceId; - - } else { - ResUsesObj::EntityResourceUse &res = iter->second; - LOG.debug() << "Обновление сущности: " << ceId; } -} - -void RemoteClient::prepareEntityRemove(GlobalEntityId_t entityId) -{ - EntityId_c cId = ResRemap.Entityes.erase(entityId); - ResUsesObj::EntityResourceUse &res = ResUses.Entity[entityId]; - - if(--ResUses.DefEntity[res.DefId] == 0) { - LOG.debug() << "Потеряли определение сущности: " << res.DefId << " -> " << cId; - ResUses.DefEntity.erase(ResUses.DefEntity.find(res.DefId)); - ResRemap.DefEntityes.erase(res.DefId); - - // decrementBinary(std::unordered_set &textures, std::unordered_set &sounds, std::unordered_set &models) - } - - LOG.debug() << "Сущность потеряна: " << cId; checkPacketBorder(16); NextPacket << (uint8_t) ToClient::L1::Content @@ -335,10 +366,167 @@ void RemoteClient::prepareEntityRemove(GlobalEntityId_t entityId) << cId; } +void RemoteClient::prepareFuncEntityUpdate(ServerFuncEntityId_t entityId, const FuncEntity *entity) +{ + // Сопоставим с идентификатором клиента + ClientFuncEntityId_t ceId = ResRemap.FuncEntityes.toClient(entityId); + + // Профиль новый + { + DefFuncEntityId_t profile = entity->getDefId(); + auto iter = ResUses.DefFuncEntity.find(profile); + if(iter == ResUses.DefFuncEntity.end()) { + // Клиенту неизвестен профиль + NextRequest.FuncEntity.push_back(profile); + ResUses.DefFuncEntity[profile] = 1; + } else + iter->second++; + } + + // Добавление модификационных зависимостей + // incrementBinary({}, {}, {}, {}, {}); + + // Старые данные + { + auto iterEntity = ResUses.RefFuncEntity.find(entityId); + if(iterEntity != ResUses.RefFuncEntity.end()) { + // Убавляем зависимость к старому профилю + auto iterProfile = ResUses.DefFuncEntity.find(iterEntity->second.Profile); + assert(iterProfile != ResUses.DefFuncEntity.end()); // Старый профиль должен быть + if(--iterProfile->second == 0) { + // Старый профиль больше не нужен + auto iterProfileRef = ResUses.RefDefFuncEntity.find(iterEntity->second.Profile); + decrementBinary(std::move(iterProfileRef->second.Texture), std::move(iterProfileRef->second.Animation), {}, + std::move(iterProfileRef->second.Model), {}); + ResUses.DefFuncEntity.erase(iterProfile); + } + + // Убавляем зависимость к модификационным данным + // iterEntity->second. + // decrementBinary({}, {}, {}, {}, {}); + } + } + + // TODO: отправить клиенту +} + +void RemoteClient::prepareFuncEntitySwap(ServerFuncEntityId_t prev, ServerFuncEntityId_t next) +{ + ResRemap.FuncEntityes.rebindClientKey(prev, next); +} + +void RemoteClient::prepareFuncEntityRemove(ServerFuncEntityId_t entityId) +{ + ClientFuncEntityId_t cId = ResRemap.FuncEntityes.erase(entityId); + + // Убавляем старые данные + { + auto iterEntity = ResUses.RefFuncEntity.find(entityId); + assert(iterEntity != ResUses.RefFuncEntity.end()); // Зависимости должны быть + + // Убавляем модификационные заависимости + //decrementBinary(std::vector &&textures, std::vector &&animation, std::vector &&sounds, std::vector &&models, std::vector &&fonts) + + // Убавляем зависимость к профилю + auto iterProfile = ResUses.DefFuncEntity.find(iterEntity->second.Profile); + assert(iterProfile != ResUses.DefFuncEntity.end()); // Профиль должен быть + if(--iterProfile->second == 0) { + // Профиль больше не используется + auto iterProfileRef = ResUses.RefDefFuncEntity.find(iterEntity->second.Profile); + + decrementBinary(std::move(iterProfileRef->second.Texture), std::move(iterProfileRef->second.Animation), {}, std::move(iterProfileRef->second.Model), {}); + + ResUses.RefDefFuncEntity.erase(iterProfileRef); + ResUses.DefFuncEntity.erase(iterProfile); + } + } + + // checkPacketBorder(16); + // NextPacket << (uint8_t) ToClient::L1::Content + // << (uint8_t) ToClient::L2Content::RemoveEntity + // << cId; +} + +void RemoteClient::prepareWorldUpdate(WorldId_t worldId, World* world) +{ + // Добавление зависимостей + ResUses.RefChunk[worldId]; + + // Профиль + { + DefWorldId_t defWorld = world->getDefId(); + auto iterWorldProf = ResUses.DefWorld.find(defWorld); + if(iterWorldProf == ResUses.DefWorld.end()) { + // Профиль мира неизвестен клиенту + ResUses.DefWorld[defWorld] = 1; + NextRequest.World.push_back(defWorld); + } else { + iterWorldProf->second++; + } + } + + // Если есть предыдущая версия мира + { + auto iterWorld = ResUses.RefWorld.find(worldId); + if(iterWorld != ResUses.RefWorld.end()) { + // Мир известен клиенту + + // Убавляем модицикационные зависимости предыдущей версии мира + // iterWorld->second. + + // Убавляем зависимости старого профиля + auto iterWorldProf = ResUses.DefWorld.find(iterWorld->second.Profile); + assert(iterWorldProf != ResUses.DefWorld.end()); // Старый профиль должен быть известен + if(--iterWorldProf->second == 0) { + // Старый профиль более ни кем не используется + ResUses.DefWorld.erase(iterWorldProf); + auto iterWorldProfRef = ResUses.RefDefWorld.find(iterWorld->second.Profile); + assert(iterWorldProfRef != ResUses.RefDefWorld.end()); // Зависимости предыдущего профиля также должны быть + decrementBinary(std::move(iterWorldProfRef->second.Texture), {}, {}, std::move(iterWorldProfRef->second.Model), {}); + ResUses.RefDefWorld.erase(iterWorldProfRef); + } + } + } + + // Указываем модификационные зависимости текущей версии мира + ResUses.RefWorld[worldId] = {world->getDefId()}; + + // TODO: отправить мир +} + +void RemoteClient::prepareWorldRemove(WorldId_t worldId) +{ + // Чанки уже удалены prepareChunkRemove + // Обновление зависимостей + auto iterWorld = ResUses.RefWorld.find(worldId); + assert(iterWorld != ResUses.RefWorld.end()); + + // Убавляем модификационные зависимости + // decrementBinary(std::move(iterWorld->second.Texture), std::move(iterWorld->second.Model), {}, {}); + + auto iterWorldProf = ResUses.DefWorld.find(iterWorld->second.Profile); + assert(iterWorldProf != ResUses.DefWorld.end()); // Профиль мира должен быть + if(--iterWorldProf->second == 0) { + // Профиль мира более не используется + ResUses.DefWorld.erase(iterWorldProf); + // Убавляем зависимости профиля + auto iterWorldProfDef = ResUses.RefDefWorld.find(iterWorld->second.Profile); + assert(iterWorldProfDef != ResUses.RefDefWorld.end()); // Зависимости профиля должны быть + decrementBinary(std::move(iterWorldProfDef->second.Texture), {}, {}, std::move(iterWorldProfDef->second.Model), {}); + ResUses.RefDefWorld.erase(iterWorldProfDef); + } + + ResUses.RefWorld.erase(iterWorld); + + auto iter = ResUses.RefChunk.find(worldId); + assert(iter->second.empty()); + ResUses.RefChunk.erase(iter); +} + void RemoteClient::preparePortalUpdate(PortalId_t portalId, void* portal) {} void RemoteClient::preparePortalRemove(PortalId_t portalId) {} -void RemoteClient::prepareCameraSetEntity(GlobalEntityId_t entityId) { +void RemoteClient::prepareCameraSetEntity(ServerEntityId_t entityId) { } @@ -354,185 +542,174 @@ ResourceRequest RemoteClient::pushPreparedPackets() { return std::move(NextRequest); } -void RemoteClient::informateDefTexture(const std::unordered_map> &textures) +void RemoteClient::informateBin(ToClient::L2Resource type, ResourceId_t id, const std::shared_ptr& data) { + checkPacketBorder(0); + NextPacket << (uint8_t) ToClient::L1::Resource // Оповещение + << (uint8_t) type << id; + for(auto part : data->Hash) + NextPacket << part; + + NextPacket << (uint8_t) ToClient::L1::Resource // Принудительная полная отправка + << (uint8_t) ToClient::L2Resource::InitResSend + << uint8_t(0) << uint8_t(0) << id + << uint32_t(data->Data.size()); + for(auto part : data->Hash) + NextPacket << part; + + NextPacket << uint8_t(0) << uint32_t(data->Data.size()); + + size_t pos = 0; + while(pos < data->Data.size()) { + checkPacketBorder(0); + size_t need = std::min(data->Data.size()-pos, std::min(NextPacket.size(), 64000)); + NextPacket.write((const std::byte*) data->Data.data()+pos, need); + pos += need; + } +} + +void RemoteClient::informateBinTexture(const std::unordered_map> &textures) { for(auto pair : textures) { - BinTextureId_t sId = pair.first; - if(!ResUses.BinTexture.contains(sId)) - continue; + BinTextureId_t id = pair.first; + if(!ResUses.BinTexture.contains(id)) + continue; // Клиент не наблюдает за этим объектом - TextureId_c cId = ResRemap.BinTextures.toClient(sId); - - checkPacketBorder(0); - NextPacket << (uint8_t) ToClient::L1::Resource // Оповещение - << (uint8_t) ToClient::L2Resource::Texture << cId; - for(auto part : pair.second->Hash) - NextPacket << part; - - NextPacket << (uint8_t) ToClient::L1::Resource // Принудительная отправка - << (uint8_t) ToClient::L2Resource::InitResSend - << uint8_t(0) << uint8_t(0) << cId - << uint32_t(pair.second->Data.size()); - for(auto part : pair.second->Hash) - NextPacket << part; - - NextPacket << uint8_t(0) << uint32_t(pair.second->Data.size()); - - size_t pos = 0; - while(pos < pair.second->Data.size()) { - 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; - } + informateBin(ToClient::L2Resource::Texture, id, pair.second); } } -void RemoteClient::informateDefSound(const std::unordered_map> &sounds) +void RemoteClient::informateBinAnimation(const std::unordered_map> &textures) { - for(auto pair : sounds) { - BinSoundId_t sId = pair.first; - if(!ResUses.BinSound.contains(sId)) - continue; + for(auto pair : textures) { + BinTextureId_t id = pair.first; + if(!ResUses.BinTexture.contains(id)) + continue; // Клиент не наблюдает за этим объектом - SoundId_c cId = ResRemap.BinSounds.toClient(sId); - - checkPacketBorder(0); - NextPacket << (uint8_t) ToClient::L1::Resource // Оповещение - << (uint8_t) ToClient::L2Resource::Sound << cId; - for(auto part : pair.second->Hash) - NextPacket << part; - - NextPacket << (uint8_t) ToClient::L1::Resource // Принудительная отправка - << (uint8_t) ToClient::L2Resource::InitResSend - << uint8_t(0) << uint8_t(1) << cId - << uint32_t(pair.second->Data.size()); - for(auto part : pair.second->Hash) - NextPacket << part; - - NextPacket << uint8_t(0) << uint32_t(pair.second->Data.size()); - - size_t pos = 0; - while(pos < pair.second->Data.size()) { - if(NextPacket.size() >= 64000) { - SimplePackets.push_back(std::move(NextPacket)); - } - - 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; - } + informateBin(ToClient::L2Resource::Animation, id, pair.second); } } -void RemoteClient::informateDefModel(const std::unordered_map> &models) +void RemoteClient::informateBinModel(const std::unordered_map> &textures) { - for(auto pair : models) { - BinModelId_t sId = pair.first; - if(!ResUses.BinModel.contains(sId)) - continue; + for(auto pair : textures) { + BinTextureId_t id = pair.first; + if(!ResUses.BinTexture.contains(id)) + continue; // Клиент не наблюдает за этим объектом - ModelId_c cId = ResRemap.BinModels.toClient(sId); - - NextPacket << (uint8_t) ToClient::L1::Resource // Оповещение - << (uint8_t) ToClient::L2Resource::Model << cId; - for(auto part : pair.second->Hash) - NextPacket << part; - - NextPacket << (uint8_t) ToClient::L1::Resource // Принудительная отправка - << (uint8_t) ToClient::L2Resource::InitResSend - << uint8_t(0) << uint8_t(2) << cId - << uint32_t(pair.second->Data.size()); - for(auto part : pair.second->Hash) - NextPacket << part; - - NextPacket << uint8_t(0) << uint32_t(pair.second->Data.size()); - - size_t pos = 0; - while(pos < pair.second->Data.size()) { - if(NextPacket.size() >= 64000) { - SimplePackets.push_back(std::move(NextPacket)); - } - - 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; - } + informateBin(ToClient::L2Resource::Model, id, pair.second); } } -void RemoteClient::informateDefWorld(const std::unordered_map &worlds) +void RemoteClient::informateBinSound(const std::unordered_map> &textures) { - for(auto pair : worlds) { - DefWorldId_t sId = pair.first; - if(!ResUses.DefWorld.contains(sId)) - continue; + for(auto pair : textures) { + BinTextureId_t id = pair.first; + if(!ResUses.BinTexture.contains(id)) + continue; // Клиент не наблюдает за этим объектом - DefWorldId_c cId = ResRemap.DefWorlds.toClient(sId); + informateBin(ToClient::L2Resource::Sound, id, pair.second); + } +} - NextPacket << (uint8_t) ToClient::L1::Definition - << (uint8_t) ToClient::L2Definition::World - << cId; +void RemoteClient::informateBinFont(const std::unordered_map> &textures) +{ + for(auto pair : textures) { + BinTextureId_t id = pair.first; + if(!ResUses.BinTexture.contains(id)) + continue; // Клиент не наблюдает за этим объектом + + informateBin(ToClient::L2Resource::Font, id, pair.second); } } void RemoteClient::informateDefVoxel(const std::unordered_map &voxels) { for(auto pair : voxels) { - DefVoxelId_t sId = pair.first; - if(!ResUses.DefWorld.contains(sId)) + DefVoxelId_t id = pair.first; + if(!ResUses.DefVoxel.contains(id)) continue; - DefVoxelId_c cId = ResRemap.DefVoxels.toClient(sId); - NextPacket << (uint8_t) ToClient::L1::Definition << (uint8_t) ToClient::L2Definition::Voxel - << cId; + << id; } } void RemoteClient::informateDefNode(const std::unordered_map &nodes) { for(auto pair : nodes) { - DefNodeId_t sId = pair.first; - if(!ResUses.DefNode.contains(sId)) + DefNodeId_t id = pair.first; + if(!ResUses.DefNode.contains(id)) continue; - DefNodeId_c cId = ResRemap.DefNodes.toClient(sId); - NextPacket << (uint8_t) ToClient::L1::Definition << (uint8_t) ToClient::L2Definition::Node - << cId; + << id; } } -void RemoteClient::informateDefEntityes(const std::unordered_map &entityes) +void RemoteClient::informateDefWorld(const std::unordered_map &worlds) { - for(auto pair : entityes) { - DefEntityId_t sId = pair.first; - if(!ResUses.DefNode.contains(sId)) + for(auto pair : worlds) { + DefWorldId_t id = pair.first; + if(!ResUses.DefWorld.contains(id)) continue; - DefEntityId_c cId = ResRemap.DefEntityes.toClient(sId); - NextPacket << (uint8_t) ToClient::L1::Definition - << (uint8_t) ToClient::L2Definition::Entity - << cId; + << (uint8_t) ToClient::L2Definition::World + << id; } } -void RemoteClient::informateDefPortals(const std::unordered_map &portals) +void RemoteClient::informateDefPortal(const std::unordered_map &portals) { for(auto pair : portals) { - DefPortalId_t sId = pair.first; - if(!ResUses.DefNode.contains(sId)) + DefPortalId_t id = pair.first; + if(!ResUses.DefPortal.contains(id)) continue; - DefPortalId_c cId = ResRemap.DefPortals.toClient(sId); - NextPacket << (uint8_t) ToClient::L1::Definition << (uint8_t) ToClient::L2Definition::Portal - << cId; + << id; + } +} + +void RemoteClient::informateDefEntity(const std::unordered_map &entityes) +{ + for(auto pair : entityes) { + DefEntityId_t id = pair.first; + if(!ResUses.DefEntity.contains(id)) + continue; + + NextPacket << (uint8_t) ToClient::L1::Definition + << (uint8_t) ToClient::L2Definition::Entity + << id; + } +} + +void RemoteClient::informateDefFuncEntity(const std::unordered_map &entityes) +{ + for(auto pair : entityes) { + DefFuncEntityId_t id = pair.first; + if(!ResUses.DefFuncEntity.contains(id)) + continue; + + NextPacket << (uint8_t) ToClient::L1::Definition + << (uint8_t) ToClient::L2Definition::FuncEntity + << id; + } +} + +void RemoteClient::informateDefItem(const std::unordered_map &items) +{ + for(auto pair : items) { + DefItemId_t id = pair.first; + if(!ResUses.DefNode.contains(id)) + continue; + + NextPacket << (uint8_t) ToClient::L1::Definition + << (uint8_t) ToClient::L2Definition::FuncEntity + << id; } } @@ -593,73 +770,104 @@ coro<> RemoteClient::rP_System(Net::AsyncSocket &sock) { } } -void RemoteClient::incrementBinary(std::unordered_set &textures, std::unordered_set &sounds, - std::unordered_set &models) -{ +void RemoteClient::incrementBinary(const std::vector& textures, const std::vector& animation, + const std::vector& sounds, const std::vector& models, + const std::vector& fonts +) { for(BinTextureId_t id : textures) { if(++ResUses.BinTexture[id] == 1) { - TextureId_c cId = ResRemap.BinTextures.toClient(id); - NextRequest.NewTextures.push_back(id); - LOG.debug() << "Новое определение текстуры: " << id << " -> " << cId; + NextRequest.BinTexture.push_back(id); + LOG.debug() << "Новое определение текстуры: " << id; + } + } + + for(BinAnimationId_t id : animation) { + if(++ResUses.BinAnimation[id] == 1) { + NextRequest.BinAnimation.push_back(id); + LOG.debug() << "Новое определение анимации: " << id; } } for(BinSoundId_t id : sounds) { if(++ResUses.BinSound[id] == 1) { - SoundId_c cId = ResRemap.BinSounds.toClient(id); - NextRequest.NewSounds.push_back(id); - LOG.debug() << "Новое определение звука: " << id << " -> " << cId; + NextRequest.BinSound.push_back(id); + LOG.debug() << "Новое определение звука: " << id; } } - for(BinModelId_t id : sounds) { + for(BinModelId_t id : models) { if(++ResUses.BinModel[id] == 1) { - ModelId_c cId = ResRemap.BinModels.toClient(id); - NextRequest.NewModels.push_back(id); - LOG.debug() << "Новое определение модели: " << id << " -> " << cId; + NextRequest.BinModel.push_back(id); + LOG.debug() << "Новое определение модели: " << id; + } + } + + for(BinFontId_t id : fonts) { + if(++ResUses.BinFont[id] == 1) { + NextRequest.BinFont.push_back(id); + LOG.debug() << "Новое определение шрифта: " << id; } } } -void RemoteClient::decrementBinary(std::unordered_set &textures, std::unordered_set &sounds, - std::unordered_set &models) -{ +void RemoteClient::decrementBinary(std::vector&& textures, std::vector&& animation, + std::vector&& sounds, std::vector&& models, + std::vector&& fonts +) { for(BinTextureId_t id : textures) { if(--ResUses.BinTexture[id] == 0) { ResUses.BinTexture.erase(ResUses.BinTexture.find(id)); - TextureId_c cId = ResRemap.BinTextures.erase(id); - LOG.debug() << "Потеряно определение текстуры: " << id << " -> " << cId; + LOG.debug() << "Потеряно определение текстуры: " << id; NextPacket << (uint8_t) ToClient::L1::Resource << (uint8_t) ToClient::L2Resource::FreeTexture - << cId; + << id; + } + } + + for(BinAnimationId_t id : animation) { + if(--ResUses.BinAnimation[id] == 0) { + ResUses.BinAnimation.erase(ResUses.BinAnimation.find(id)); + LOG.debug() << "Потеряно определение анимации: " << id; + + NextPacket << (uint8_t) ToClient::L1::Resource + << (uint8_t) ToClient::L2Resource::FreeAnimation + << id; } } for(BinSoundId_t id : sounds) { if(--ResUses.BinSound[id] == 0) { ResUses.BinSound.erase(ResUses.BinSound.find(id)); - SoundId_c cId = ResRemap.BinSounds.erase(id); - LOG.debug() << "Потеряно определение звука: " << id << " -> " << cId; + LOG.debug() << "Потеряно определение звука: " << id; NextPacket << (uint8_t) ToClient::L1::Resource << (uint8_t) ToClient::L2Resource::FreeSound - << cId; + << id; } } - for(BinModelId_t id : sounds) { + for(BinModelId_t id : models) { if(--ResUses.BinModel[id] == 0) { ResUses.BinModel.erase(ResUses.BinModel.find(id)); - ModelId_c cId = ResRemap.BinModels.erase(id); - LOG.debug() << "Потеряно определение модели: " << id << " -> " << cId; + LOG.debug() << "Потеряно определение модели: " << id; NextPacket << (uint8_t) ToClient::L1::Resource << (uint8_t) ToClient::L2Resource::FreeModel - << cId; + << id; + } + } + + for(BinFontId_t id : fonts) { + if(--ResUses.BinFont[id] == 0) { + ResUses.BinFont.erase(ResUses.BinFont.find(id)); + LOG.debug() << "Потеряно определение шрифта: " << id; + + NextPacket << (uint8_t) ToClient::L1::Resource + << (uint8_t) ToClient::L2Resource::FreeFont + << id; } } } - } \ No newline at end of file diff --git a/Src/Server/RemoteClient.hpp b/Src/Server/RemoteClient.hpp index a7e9239..2d6f27d 100644 --- a/Src/Server/RemoteClient.hpp +++ b/Src/Server/RemoteClient.hpp @@ -102,7 +102,7 @@ public: // Соотнести идентификатор на стороне клиента с идентификатором на стороне сервера ServerKey toServer(ClientKey ckey) { return CSmapper.toServer(ckey); - } + } // Удаляет серверный идентификатор, освобождая идентификатор клиента ClientKey erase(ServerKey skey) { @@ -138,30 +138,43 @@ public: этих ресурсов и переотправлять их клиенту */ struct ResourceRequest { - std::vector NewTextures; - std::vector NewModels; - std::vector NewSounds; + std::vector BinTexture; + std::vector BinAnimation; + std::vector BinModel; + std::vector BinSound; + std::vector BinFont; - std::vector NewWorlds; - std::vector NewVoxels; - std::vector NewNodes; - std::vector NewPortals; - std::vector NewEntityes; + std::vector Voxel; + std::vector Node; + std::vector World; + std::vector Portal; + std::vector Entity; + std::vector FuncEntity; + std::vector Item; void insert(const ResourceRequest &obj) { - NewTextures.insert(NewTextures.end(), obj.NewTextures.begin(), obj.NewTextures.end()); - NewModels.insert(NewModels.end(), obj.NewModels.begin(), obj.NewModels.end()); - NewSounds.insert(NewSounds.end(), obj.NewSounds.begin(), obj.NewSounds.end()); + BinTexture.insert(BinTexture.end(), obj.BinTexture.begin(), obj.BinTexture.end()); + BinAnimation.insert(BinAnimation.end(), obj.BinAnimation.begin(), obj.BinAnimation.end()); + BinModel.insert(BinModel.end(), obj.BinModel.begin(), obj.BinModel.end()); + BinSound.insert(BinSound.end(), obj.BinSound.begin(), obj.BinSound.end()); + BinFont.insert(BinFont.end(), obj.BinFont.begin(), obj.BinFont.end()); - NewWorlds.insert(NewWorlds.end(), obj.NewWorlds.begin(), obj.NewWorlds.end()); - NewVoxels.insert(NewVoxels.end(), obj.NewVoxels.begin(), obj.NewVoxels.end()); - NewNodes.insert(NewNodes.end(), obj.NewNodes.begin(), obj.NewNodes.end()); - NewPortals.insert(NewPortals.end(), obj.NewPortals.begin(), obj.NewPortals.end()); - NewEntityes.insert(NewEntityes.end(), obj.NewEntityes.begin(), obj.NewEntityes.end()); + Voxel.insert(Voxel.end(), obj.Voxel.begin(), obj.Voxel.end()); + Node.insert(Node.end(), obj.Node.begin(), obj.Node.end()); + World.insert(World.end(), obj.World.begin(), obj.World.end()); + Portal.insert(Portal.end(), obj.Portal.begin(), obj.Portal.end()); + Entity.insert(Entity.end(), obj.Entity.begin(), obj.Entity.end()); + FuncEntity.insert(FuncEntity.end(), obj.FuncEntity.begin(), obj.FuncEntity.end()); + Item.insert(Item.end(), obj.Item.begin(), obj.Item.end()); } void uniq() { - for(std::vector *vec : {&NewTextures, &NewModels, &NewSounds, &NewWorlds, &NewVoxels, &NewNodes, &NewPortals, &NewEntityes}) { + for(std::vector *vec : { + &BinTexture, &BinAnimation, &BinModel, &BinSound, + &BinFont, &Voxel, &Node, &World, + &Portal, &Entity, &FuncEntity, &Item + }) + { std::sort(vec->begin(), vec->end()); auto last = std::unique(vec->begin(), vec->end()); vec->erase(last, vec->end()); @@ -169,7 +182,7 @@ struct ResourceRequest { } }; -using EntityKey = std::tuple; +// using EntityKey = std::tuple; @@ -186,85 +199,109 @@ class RemoteClient { DestroyLock UseLock; Net::AsyncSocket Socket; bool IsConnected = true, IsGoingShutdown = false; - std::vector ClientCache; + std::vector ClientBinaryCache; + + /* + При обнаружении нового контента составляется запрос (ResourceRequest) + на полное описание ресурса. Это описание отправляется клиенту и используется + чтобы выстроить зависимость какие базовые ресурсы использует контент. + Если базовые ресурсы не известны, то они также запрашиваются. + */ struct ResUsesObj { - // Счётчики использования базовых ресурсов высшими объектами - std::map BinTexture; - std::map BinSound; + // Счётчики использования двоичных кэшируемых ресурсов + std::map BinTexture; + std::map BinAnimation; + std::map BinModel; + std::map BinSound; + std::map BinFont; - // Может использовать текстуры - std::map BinModel; + // Счётчики использование профилей контента + std::map DefVoxel; // Один чанк, одно использование + std::map DefNode; + std::map DefWorld; + std::map DefPortal; + std::map DefEntity; + std::map DefFuncEntity; + std::map DefItem; // При передаче инвентарей? - // Будут использовать в своих определениях текстуры, звуки, модели - std::map DefWorld; - std::map DefVoxel; - std::map DefNode; - std::map DefPortal; - std::map DefEntity; - - - // Переписываемый контент - - // Сущности используют текстуры, звуки, модели - struct EntityResourceUse { - DefEntityId_t DefId; - - std::unordered_set Textures; - std::unordered_set Sounds; - std::unordered_set Models; + // Зависимость профилей контента от профилей ресурсов + // Нужно чтобы пересчитать зависимости к профилям ресурсов + struct RefDefVoxel_t { + std::vector Texture; + std::vector Sound; }; - - std::map Entity; - - // Чанки используют воксели, ноды - std::map, std::unordered_set> ChunkVoxels; - std::map, std::unordered_set> ChunkNodes; - - // Миры - struct WorldResourceUse { - DefWorldId_t DefId; - - std::unordered_set Textures; - std::unordered_set Sounds; - std::unordered_set Models; + std::map RefDefVoxel; + struct RefDefNode_t { + std::vector Model; + std::vector Sound; }; - - std::map Worlds; - - - // Порталы - struct PortalResourceUse { - DefPortalId_t DefId; - - std::unordered_set Textures; - std::unordered_set Sounds; - std::unordered_set Models; + std::map RefDefNode; + struct RefDefWorld_t { + std::vector Texture; + std::vector Model; }; + std::map RefDefWorld; + struct RefDefPortal_t { + std::vector Texture; + std::vector Animation; + std::vector Model; + }; + std::map RefDefPortal; + struct RefDefEntity_t { + std::vector Texture; + std::vector Animation; + std::vector Model; + }; + std::map RefDefEntity; + struct RefDefFuncEntity_t { + std::vector Texture; + std::vector Animation; + std::vector Model; + }; + std::map RefDefFuncEntity; + struct RefDefItem_t { + std::vector Texture; + std::vector Animation; + std::vector Model; + }; + std::map RefDefItem; + + // Модификационные зависимости экземпляров профилей контента + struct ChunkRef { + // Отсортированные списки уникальных вокселей + std::vector Voxel; + std::vector Node; + }; + std::map> RefChunk; + struct RefWorld_t { + DefWorldId_t Profile; + }; + std::map RefWorld; + struct RefPortal_t { + DefPortalId_t Profile; + }; + std::map RefPortal; + struct RefEntity_t { + DefEntityId_t Profile; + }; + std::map RefEntity; + struct RefFuncEntity_t { + DefFuncEntityId_t Profile; + }; + std::map RefFuncEntity; - std::map Portals; - } ResUses; + // Смена идентификаторов сервера на клиентские struct { - SCSKeyRemapper BinTextures; - SCSKeyRemapper BinSounds; - SCSKeyRemapper BinModels; - - SCSKeyRemapper DefWorlds; - SCSKeyRemapper DefVoxels; - SCSKeyRemapper DefNodes; - SCSKeyRemapper DefPortals; - SCSKeyRemapper DefEntityes; - - SCSKeyRemapper Worlds; - SCSKeyRemapper Portals; - SCSKeyRemapper Entityes; + SCSKeyRemapper Entityes; + SCSKeyRemapper FuncEntityes; } ResRemap; Net::Packet NextPacket; - ResourceRequest NextRequest; std::vector SimplePackets; + ResourceRequest NextRequest; public: const std::string Username; @@ -273,7 +310,7 @@ public: public: RemoteClient(asio::io_context &ioc, tcp::socket socket, const std::string username, std::vector &&client_cache) - : LOG("RemoteClient " + username), Socket(ioc, std::move(socket)), Username(username), ClientCache(std::move(client_cache)) + : LOG("RemoteClient " + username), Socket(ioc, std::move(socket)), Username(username), ClientBinaryCache(std::move(client_cache)) { } @@ -291,27 +328,40 @@ public: } // Функции подготавливают пакеты к отправке + // Отслеживаемое игроком использование контента - // Maybe? - // Текущий список вокселей, определения нод, которые больше не используются в чанке, и определения нод, которые теперь используются - //void prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::vector &voxels, const std::vector &noLongerInUseDefs, const std::vector &nowUsed); - void prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::vector &voxels); - void prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::unordered_map &nodes); - void prepareChunkUpdate_LightPrism(WorldId_t worldId, Pos::GlobalChunk chunkPos, const LightPrism *lights); + // В зоне видимости добавился чанк или изменились его воксели + void prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::vector* voxels); + // В зоне видимости добавился чанк или изменились его ноды + void prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::GlobalChunk chunkPos, const Node* nodes); + void prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::unordered_map &nodes); + //void prepareChunkUpdate_LightPrism(WorldId_t worldId, Pos::GlobalChunk chunkPos, const LightPrism *lights); + // Чанк удалён из зоны видимости void prepareChunkRemove(WorldId_t worldId, Pos::GlobalChunk chunkPos); - void prepareEntitySwap(GlobalEntityId_t prevEntityId, GlobalEntityId_t nextEntityId); - void prepareEntityUpdate(GlobalEntityId_t entityId, const Entity *entity); - void prepareEntityRemove(GlobalEntityId_t entityId); + // В зоне видимости добавилась новая сущность или она изменилась + void prepareEntityUpdate(ServerEntityId_t entityId, const Entity *entity); + // Наблюдаемая сущность пересекла границы региона, у неё изменился серверный идентификатор + void prepareEntitySwap(ServerEntityId_t prevEntityId, ServerEntityId_t nextEntityId); + // Клиент перестал наблюдать за сущностью + void prepareEntityRemove(ServerEntityId_t entityId); + void prepareFuncEntitySwap(ServerEntityId_t prevEntityId, ServerEntityId_t nextEntityId); + void prepareFuncEntityUpdate(ServerEntityId_t entityId, const FuncEntity *funcRntity); + void prepareFuncEntityRemove(ServerEntityId_t entityId); + + // В зоне видимости добавился мир или он изменился void prepareWorldUpdate(WorldId_t worldId, World* world); + // Клиент перестал наблюдать за миром void prepareWorldRemove(WorldId_t worldId); + // В зоне видимости добавился порта или он изменился void preparePortalUpdate(PortalId_t portalId, void* portal); + // Клиент перестал наблюдать за порталом void preparePortalRemove(PortalId_t portalId); // Прочие моменты - void prepareCameraSetEntity(GlobalEntityId_t entityId); + void prepareCameraSetEntity(ServerEntityId_t entityId); // Отправка подготовленных пакетов ResourceRequest pushPreparedPackets(); @@ -321,16 +371,20 @@ public: // Глобально их можно запросить в выдаче pushPreparedPackets() // Двоичные файлы - void informateDefTexture(const std::unordered_map> &textures); - void informateDefSound(const std::unordered_map> &sounds); - void informateDefModel(const std::unordered_map> &models); + void informateBinTexture(const std::unordered_map> &textures); + void informateBinAnimation(const std::unordered_map> &animations); + void informateBinModel(const std::unordered_map> &models); + void informateBinSound(const std::unordered_map> &sounds); + void informateBinFont(const std::unordered_map> &fonts); // Игровые определения - void informateDefWorld(const std::unordered_map &worlds); void informateDefVoxel(const std::unordered_map &voxels); void informateDefNode(const std::unordered_map &nodes); - void informateDefEntityes(const std::unordered_map &entityes); - void informateDefPortals(const std::unordered_map &portals); + void informateDefWorld(const std::unordered_map &worlds); + void informateDefPortal(const std::unordered_map &portals); + void informateDefEntity(const std::unordered_map &entityes); + void informateDefFuncEntity(const std::unordered_map &funcEntityes); + void informateDefItem(const std::unordered_map &items); private: void checkPacketBorder(uint16_t size); @@ -338,10 +392,24 @@ private: coro<> readPacket(Net::AsyncSocket &sock); coro<> rP_System(Net::AsyncSocket &sock); - void incrementBinary(std::unordered_set &textures, std::unordered_set &sounds, - std::unordered_set &models); - void decrementBinary(std::unordered_set &textures, std::unordered_set &sounds, - std::unordered_set &models); + void incrementBinary(const std::vector &textures, const std::vector &animation, + const std::vector &sounds, const std::vector &models, + const std::vector &fonts + ); + void decrementBinary(std::vector&& textures, std::vector&& animation, + std::vector&& sounds, std::vector&& models, + std::vector&& fonts + ); + void informateBin(ToClient::L2Resource type, ResourceId_t id, const std::shared_ptr& pair); + + // void incrementProfile(const std::vector &textures, const std::vector &model, + // const std::vector &sounds, const std::vector &font + // ); + // void decrementProfile(std::vector &&textures, std::vector &&model, + // std::vector &&sounds, std::vector &&font + // ); + + }; diff --git a/Src/Server/SaveBackend.hpp b/Src/Server/SaveBackend.hpp index b110d6d..48a48b2 100644 --- a/Src/Server/SaveBackend.hpp +++ b/Src/Server/SaveBackend.hpp @@ -13,7 +13,7 @@ namespace LV::Server { struct SB_Region { std::vector Voxels; std::unordered_map VoxelsMap; - std::unordered_map Nodes; + std::unordered_map Nodes; std::unordered_map NodeMap; std::vector Entityes; std::unordered_map EntityMap; diff --git a/Src/Server/SaveBackends/Filesystem.cpp b/Src/Server/SaveBackends/Filesystem.cpp index bc641aa..7458462 100644 --- a/Src/Server/SaveBackends/Filesystem.cpp +++ b/Src/Server/SaveBackends/Filesystem.cpp @@ -30,7 +30,7 @@ public: } fs::path getPath(std::string worldId, Pos::GlobalRegion regionPos) { - return Dir / worldId / std::to_string(regionPos.X) / std::to_string(regionPos.Y) / std::to_string(regionPos.Z); + return Dir / worldId / std::to_string(regionPos.x) / std::to_string(regionPos.y) / std::to_string(regionPos.z); } virtual bool isAsync() { return false; }; @@ -48,13 +48,13 @@ public: for(js::value &jvVoxel : jaVoxels) { js::object &joVoxel = jvVoxel.as_object(); VoxelCube_Region cube; - cube.VoxelId = joVoxel.at("Material").as_uint64(); - cube.Left.X = joVoxel.at("LeftX").as_uint64(); - cube.Left.Y = joVoxel.at("LeftY").as_uint64(); - cube.Left.Z = joVoxel.at("LeftZ").as_uint64(); - cube.Right.X = joVoxel.at("RightX").as_uint64(); - cube.Right.Y = joVoxel.at("RightY").as_uint64(); - cube.Right.Z = joVoxel.at("RightZ").as_uint64(); + cube.Data = joVoxel.at("Data").as_uint64(); + cube.Left.x = joVoxel.at("LeftX").as_uint64(); + cube.Left.y = joVoxel.at("LeftY").as_uint64(); + cube.Left.z = joVoxel.at("LeftZ").as_uint64(); + cube.Right.x = joVoxel.at("RightX").as_uint64(); + cube.Right.y = joVoxel.at("RightY").as_uint64(); + cube.Right.z = joVoxel.at("RightZ").as_uint64(); data->Voxels.push_back(cube); } } @@ -74,13 +74,13 @@ public: js::array jaVoxels; for(const VoxelCube_Region &cube : data->Voxels) { js::object joVoxel; - joVoxel["Material"] = cube.VoxelId; - joVoxel["LeftX"] = cube.Left.X; - joVoxel["LeftY"] = cube.Left.Y; - joVoxel["LeftZ"] = cube.Left.Z; - joVoxel["RightX"] = cube.Right.X; - joVoxel["RightY"] = cube.Right.Y; - joVoxel["RightZ"] = cube.Right.Z; + joVoxel["Data"] = cube.Data; + joVoxel["LeftX"] = cube.Left.x; + joVoxel["LeftY"] = cube.Left.y; + joVoxel["LeftZ"] = cube.Left.z; + joVoxel["RightX"] = cube.Right.x; + joVoxel["RightY"] = cube.Right.y; + joVoxel["RightZ"] = cube.Right.z; jaVoxels.push_back(std::move(joVoxel)); } diff --git a/Src/Server/World.hpp b/Src/Server/World.hpp index 41664c8..de8c130 100644 --- a/Src/Server/World.hpp +++ b/Src/Server/World.hpp @@ -15,16 +15,17 @@ class GameServer; class Region { public: - uint64_t IsChunkChanged_Voxels[64] = {0}; - uint64_t IsChunkChanged_Nodes[64] = {0}; + uint64_t IsChunkChanged_Voxels = 0; + uint64_t IsChunkChanged_Nodes = 0; bool IsChanged = false; // Изменён ли был регион, относительно последнего сохранения - // cx cy cz - std::vector Voxels[16][16][16]; + std::unordered_map> Voxels; // x y cx cy cz - LightPrism Lights[16][16][16][16][16]; - std::unordered_map Nodes[16][16][16]; + //LightPrism Lights[16][16][4][4][4]; + + Node Nodes[16][16][16][4][4][4]; std::vector Entityes; + std::vector FuncEntityes; std::vector CECs; // Используется для прорежения количества проверок на наблюдаемые чанки и сущности // В одно обновление региона - проверка одного наблюдателя @@ -35,11 +36,10 @@ public: void getCollideBoxes(Pos::GlobalRegion rPos, AABB aabb, std::vector &boxes) { // Абсолютная позиция начала региона - Pos::Object raPos(rPos.X, rPos.Y, rPos.Z); - raPos <<= Pos::Object_t::BS_Bit; + Pos::Object raPos = Pos::Object(rPos) << Pos::Object_t::BS_Bit; // Бокс региона - AABB regionAABB(raPos, raPos+Pos::Object(Pos::Object_t::BS*256)); + AABB regionAABB(raPos, raPos+Pos::Object(Pos::Object_t::BS*64)); // Если регион не загружен, то он весь непроходим if(!IsLoaded) { @@ -65,46 +65,48 @@ public: // Собираем коробки вокселей if(aabb.isCollideWith(regionAABB)) { + // Определяем с какими чанками есть пересечения glm::ivec3 beg, end; for(int axis = 0; axis < 3; axis++) - beg[axis] = std::max(aabb.VecMin[axis], regionAABB.VecMin[axis]) >> 16; + beg[axis] = std::max(aabb.VecMin[axis], regionAABB.VecMin[axis]) >> 12 >> 4; for(int axis = 0; axis < 3; axis++) - end[axis] = (std::min(aabb.VecMax[axis], regionAABB.VecMax[axis])+0xffff) >> 16; + end[axis] = (std::min(aabb.VecMax[axis], regionAABB.VecMax[axis])+0xffff) >> 12 >> 4; for(; beg.z <= end.z; beg.z++) for(; beg.y <= end.y; beg.y++) for(; beg.x <= end.x; beg.x++) { - std::vector &voxels = Voxels[beg.x][beg.y][beg.z]; + auto iterVoxels = Voxels.find(Pos::bvec4u(beg)); - if(voxels.empty()) + if(iterVoxels == Voxels.end() && iterVoxels->second.empty()) continue; + auto &voxels = iterVoxels->second; + CollisionAABB aabbInfo = CollisionAABB(regionAABB); for(int axis = 0; axis < 3; axis++) - aabbInfo.VecMin[axis] |= beg[axis] << 16; + aabbInfo.VecMin.set(axis, aabbInfo.VecMin[axis] | beg[axis] << 16); for(size_t iter = 0; iter < voxels.size(); iter++) { VoxelCube &cube = voxels[iter]; for(int axis = 0; axis < 3; axis++) - aabbInfo.VecMin[axis] &= ~0xff00; + aabbInfo.VecMin.set(axis, aabbInfo.VecMin[axis] & ~0xff00); aabbInfo.VecMax = aabbInfo.VecMin; - aabbInfo.VecMin.x |= int(cube.Left.X) << 8; - aabbInfo.VecMin.y |= int(cube.Left.Y) << 8; - aabbInfo.VecMin.z |= int(cube.Left.Z) << 8; + aabbInfo.VecMin.x |= int(cube.Left.x) << 8; + aabbInfo.VecMin.y |= int(cube.Left.y) << 8; + aabbInfo.VecMin.z |= int(cube.Left.z) << 8; - aabbInfo.VecMax.x |= int(cube.Right.X) << 8; - aabbInfo.VecMax.y |= int(cube.Right.Y) << 8; - aabbInfo.VecMax.z |= int(cube.Right.Z) << 8; + aabbInfo.VecMax.x |= int(cube.Right.x) << 8; + aabbInfo.VecMax.y |= int(cube.Right.y) << 8; + aabbInfo.VecMax.z |= int(cube.Right.z) << 8; if(aabb.isCollideWith(aabbInfo)) { aabbInfo = { .Type = CollisionAABB::EnumType::Voxel, .Voxel = { - .Chunk = Pos::Local16_u(beg.x, beg.y, beg.z), + .Chunk = Pos::bvec4u(beg.x, beg.y, beg.z), .Index = static_cast(iter), - .Id = cube.VoxelId } }; @@ -118,7 +120,7 @@ public: } - LocalEntityId_t pushEntity(Entity &entity) { + RegionEntityId_t pushEntity(Entity &entity) { for(size_t iter = 0; iter < Entityes.size(); iter++) { Entity &obj = Entityes[iter]; @@ -135,16 +137,17 @@ public: return Entityes.size()-1; } - return LocalEntityId_t(-1); + // В регионе не осталось места + return RegionEntityId_t(-1); } void load(SB_Region *data) { - convertRegionVoxelsToChunks(data->Voxels, (std::vector*) Voxels); + convertRegionVoxelsToChunks(data->Voxels, Voxels); } void save(SB_Region *data) { data->Voxels.clear(); - convertChunkVoxelsToRegion((const std::vector*) Voxels, data->Voxels); + convertChunkVoxelsToRegion(Voxels, data->Voxels); } };