diff --git a/Src/Server/Abstract.hpp b/Src/Server/Abstract.hpp index 2cc1248..5253a34 100644 --- a/Src/Server/Abstract.hpp +++ b/Src/Server/Abstract.hpp @@ -18,9 +18,10 @@ using ModelId_c = uint16_t; using ResourceId_t = uint32_t; -using VoxelId_t = ResourceId_t; -using NodeId_t = ResourceId_t; -using WorldId_t = ResourceId_t; +using DefVoxelId_t = ResourceId_t; +using DefNodeId_t = ResourceId_t; +using DefWorldId_t = ResourceId_t; +using DefEntityId_t = ResourceId_t; using PortalId_t = uint16_t; // В одном регионе может быть максимум 2^16 сущностей. Клиенту адресуются сущности в формате <позиция региона>+ // И если сущность перешла из одного региона в другой адресация сохраняется @@ -59,20 +60,20 @@ struct ServerTime { struct VoxelCube { Pos::Local256_u Left, Right; - VoxelId_t Material; + DefVoxelId_t VoxelId; auto operator<=>(const VoxelCube&) const = default; }; struct VoxelCube_Region { Pos::Local4096_u Left, Right; - VoxelId_t Material; + DefVoxelId_t VoxelId; auto operator<=>(const VoxelCube_Region&) const = default; }; struct Node { - NodeId_t NodeId; + DefNodeId_t NodeId; uint8_t Rotate : 6; }; @@ -125,7 +126,7 @@ struct CollisionAABB : public AABB { struct { Pos::Local16_u Chunk; uint32_t Index; - VoxelId_t Id; + DefVoxelId_t Id; } Voxel; struct { @@ -150,7 +151,7 @@ public: LocalAABB ABBOX; // PosQuat - WorldId_t WorldId; + DefWorldId_t WorldId; Pos::Object Pos, Speed, Acceleration; glm::quat Quat; static constexpr uint16_t HP_BS = 4096, HP_BS_Bit = 12; @@ -183,7 +184,7 @@ struct VoxelCuboidsFuncs { // Кубы должны быть отсортированы static bool canMerge(const Vec& a, const Vec& b) { - if (a.Material != b.Material) return false; + if (a.VoxelId != b.VoxelId) return false; // Проверяем, что кубы смежны по одной из осей bool xAdjacent = (a.Right.X == b.Left.X) && (a.Left.Y == b.Left.Y) && (a.Right.Y == b.Right.Y) && (a.Left.Z == b.Left.Z) && (a.Right.Z == b.Right.Z); @@ -195,7 +196,7 @@ struct VoxelCuboidsFuncs { static Vec mergeCubes(const Vec& a, const Vec& b) { Vec merged; - merged.Material = a.Material; + merged.VoxelId = a.VoxelId; // Объединяем кубы по минимальным и максимальным координатам merged.Left.X = std::min(a.Left.X, b.Left.X); @@ -322,7 +323,7 @@ inline void convertRegionVoxelsToChunks(const std::vector& reg }; int chunkIndex = z * 16 * 16 + y * 16 + x; - chunks[chunkIndex].emplace_back(left, right, region.Material); + chunks[chunkIndex].emplace_back(left, right, region.VoxelId); } } } @@ -341,7 +342,7 @@ inline void convertChunkVoxelsToRegion(const std::vector *chunks, std regions.emplace_back( Pos::Local4096_u(left.X+cube.Left.X, left.Y+cube.Left.Y, left.Z+cube.Left.Z), Pos::Local4096_u(left.X+cube.Right.X, left.Y+cube.Right.Y, left.Z+cube.Right.Z), - cube.Material + cube.VoxelId ); } } diff --git a/Src/Server/RemoteClient.hpp b/Src/Server/RemoteClient.hpp index f44a83b..4ccdd66 100644 --- a/Src/Server/RemoteClient.hpp +++ b/Src/Server/RemoteClient.hpp @@ -13,31 +13,23 @@ namespace LV::Server { -/* - Введение в распознавание образов - Распознавание символов - -*/ - template && std::is_integral_v && sizeof(ServerKey) >= sizeof(ClientKey), int> = 0> class CSChunkedMapper { std::unordered_map, std::array>> Chunks; public: - ServerKey remap(ClientKey cKey) { + ServerKey toServer(ClientKey cKey) { int chunkIndex = cKey >> 6; int subIndex = cKey & 0x3f; auto iChunk = Chunks.find(chunkIndex); - if(iChunk == Chunks.end()) - MAKE_ERROR("Идентификатор не привязан"); + assert(iChunk != Chunks.end() && "Идентификатор уже занят"); std::bitset<64> &bits = std::get<0>(iChunk.second); std::array &keys = std::get<1>(iChunk.second); - if(!bits.test(subIndex)) - MAKE_ERROR("Идентификатор не привязан"); + assert(bits.test(subIndex) && "Идентификатор уже занят"); return keys[subIndex]; } @@ -53,13 +45,12 @@ public: std::bitset<64> &bits = std::get<0>(iChunk.second); std::array &keys = std::get<1>(iChunk.second); - if(!bits.test(subIndex)) - MAKE_ERROR("Идентификатор не привязан"); + assert(bits.test(subIndex) && "Идентификатор уже занят"); bits.reset(subIndex); } - void map(ClientKey cKey, ServerKey sKey) { + void link(ClientKey cKey, ServerKey sKey) { int chunkIndex = cKey >> 6; int subIndex = cKey & 0x3f; @@ -67,45 +58,63 @@ public: std::bitset<64> &bits = std::get<0>(chunk); std::array &keys = std::get<1>(chunk); - if(bits.test(subIndex)) { - MAKE_ERROR("Идентификатор уже занят"); - } + assert(!bits.test(subIndex) && "Идентификатор уже занят"); bits.set(subIndex); keys[subIndex] = sKey; } }; -template -class SortedChunkedMap { - -struct Chunk { - uint8_t bitset = 0; - std::array, sizeof(bitset)> Data; -}; - -public: - -}; - template && std::is_integral_v && sizeof(ServerKey) >= sizeof(ClientKey), int> = 0> -class SCMapper { - +class SCSKeyRemapper { + std::bitset FreeClientKeys; + std::map Map; + CSChunkedMapper CSmapper; public: + SCSKeyRemapper() { + FreeClientKeys.set(); + } -}; + // Соотнести идентификатор на стороне сервера с идентификатором на стороне клиента + ClientKey toClient(ServerKey skey) { + if(skey == ServerKey(0)) + return ClientKey(0); -template && std::is_integral_v, int> = 0> -class SCKeyRemapper { - std::bitset<(1 << sizeof(ClientKey)*8) - 1> UsedIdC; // 1 - идентификатор свободен, 0 - занят - std::map SCTable; + auto iter = Map.find(skey); + if(iter == Map.end()) { + // Идентификатор отсутствует, нужно его занять + // Ищет позицию ближайшего бита 1 + size_t pos = FreeClientKeys._Find_first(); + if(pos == FreeClientKeys.size()) + return ClientKey(0); // Свободные идентификаторы отсутствуют -public: - // Если аллоцировать идентификатор не получится, будет возвращено ClientKey(0) - ClientKey toClient(ServerKey sKey) { + ClientKey ckey = ClientKey(pos+1); + Map[skey] = ckey; + CSmapper.link(ckey, ckey); + return ClientKey(pos); + } - }; + return iter.second; + } + + // Соотнести идентификатор на стороне клиента с идентификатором на стороне сервера + ServerKey toServer(ClientKey ckey) { + return CSmapper.toServer(ckey); + } + + // Удаляет серверный идентификатор, освобождая идентификатор клиента + ClientKey erase(ServerKey skey) { + auto iter = Map.find(skey); + + assert(iter != Map.end() && "Идентификатор не существует"); + + ClientKey ckey = iter.second; + CSmapper.erase(ckey); + Map.erase(iter); + + return ckey; + } }; /* @@ -115,9 +124,11 @@ public: этих ресурсов и переотправлять их клиенту */ struct ResourceRequest { - std::vector NewWorlds; - std::vector NewVoxels; - std::vector NewNodes; + std::vector NewWorlds; + std::vector NewVoxels; + std::vector NewNodes; + std::vector NewEntityes; + std::vector NewTextures; std::vector NewModels; std::vector NewSounds; @@ -126,13 +137,14 @@ struct ResourceRequest { 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()); + NewEntityes.insert(NewEntityes.end(), obj.NewEntityes.begin(), obj.NewEntityes.end()); 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()); } void uniq() { - for(std::vector *vec : {&NewWorlds, &NewVoxels, &NewNodes, &NewTextures, &NewModels, &NewSounds}) { + for(std::vector *vec : {&NewWorlds, &NewVoxels, &NewNodes, &NewEntityes, &NewTextures, &NewModels, &NewSounds}) { std::sort(vec->begin(), vec->end()); auto last = std::unique(vec->begin(), vec->end()); vec->erase(last, vec->end()); @@ -140,6 +152,8 @@ struct ResourceRequest { } }; +using EntityKey = std::tuple; + /* Обработчик сокета клиента. Подписывает клиента на отслеживание необходимых ресурсов @@ -152,8 +166,13 @@ class RemoteClient { struct { std::bitset<(1 << sizeof(EntityId_c)*8) - 1> UsedEntityIdC; // 1 - идентификатор свободен, 0 - занят - std::unordered_map> CTS_Entityes; - std::unordered_map>> STC_Entityes; + std::map TextureUses; + std::map ModelUses; + std::map SoundUses; + + std::map VoxelDefUses; + std::map NodeDefUses; + std::map EntityDefUses; std::unordered_map STC_Textures; std::unordered_map STC_Models;