From e21394c4f12f0573b06112b84d9d98dc24627dec Mon Sep 17 00:00:00 2001 From: DrSocalkwe3n Date: Fri, 15 Aug 2025 17:35:13 +0600 Subject: [PATCH] =?UTF-8?q?=D0=AD=D1=82=D0=B0=20=D0=B2=D0=B5=D1=80=D1=81?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=B8=D0=BB=D0=B8=D1=82?= =?UTF-8?q?=D1=81=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Src/Client/Abstract.hpp | 20 +- Src/Client/ServerSession.cpp | 34 +- Src/Client/Vulkan/VulkanRenderSession.cpp | 8 +- Src/Client/Vulkan/VulkanRenderSession.hpp | 16 +- Src/Common/Abstract.cpp | 53 +- Src/Server/AssetsManager.cpp | 24 +- Src/Server/AssetsManager.hpp | 26 +- ...roller.cpp => ContentEventController.cpp_} | 0 Src/Server/ContentManager.cpp | 72 ++- Src/Server/ContentManager.hpp | 101 +++- Src/Server/GameServer.cpp | 352 ++++++------- Src/Server/GameServer.hpp | 2 +- Src/Server/RemoteClient.cpp | 494 +++++++++--------- Src/Server/RemoteClient.hpp | 88 +++- Src/Server/SaveBackend.hpp | 6 +- Src/Server/World.cpp | 12 +- Src/Server/World.hpp | 16 +- Src/TOSLib.hpp | 4 + 18 files changed, 745 insertions(+), 583 deletions(-) rename Src/Server/{ContentEventController.cpp => ContentEventController.cpp_} (100%) diff --git a/Src/Client/Abstract.hpp b/Src/Client/Abstract.hpp index a2f7a36..0ecba78 100644 --- a/Src/Client/Abstract.hpp +++ b/Src/Client/Abstract.hpp @@ -48,7 +48,7 @@ class Entity { public: // PosQuat WorldId_t WorldId; - PortalId_t LastUsedPortal; + // PortalId LastUsedPortal; Pos::Object Pos; glm::quat Quat; static constexpr uint16_t HP_BS = 4096, HP_BS_Bit = 12; @@ -66,8 +66,8 @@ public: // Подгрузка двоичных ресурсов virtual void onBinaryResourceAdd(std::vector) = 0; - virtual void onContentDefinesAdd(std::unordered_map>) = 0; - virtual void onContentDefinesLost(std::unordered_map>) = 0; + virtual void onContentDefinesAdd(std::unordered_map>) = 0; + virtual void onContentDefinesLost(std::unordered_map>) = 0; // Сообщаем об изменившихся чанках virtual void onChunksChange(WorldId_t worldId, const std::unordered_set &changeOrAddList, const std::unordered_set &remove) = 0; @@ -149,17 +149,17 @@ public: } Binary; struct { - std::unordered_map DefVoxel; - std::unordered_map DefNode; - std::unordered_map DefWorld; - std::unordered_map DefPortal; - std::unordered_map DefEntity; - std::unordered_map DefItem; + std::unordered_map DefVoxel; + std::unordered_map DefNode; + std::unordered_map DefWorld; + std::unordered_map DefPortal; + std::unordered_map DefEntity; + std::unordered_map DefItem; } Registry; struct { std::unordered_map Worlds; - std::unordered_map Portals; + // std::unordered_map Portals; std::unordered_map Entityes; } Data; diff --git a/Src/Client/ServerSession.cpp b/Src/Client/ServerSession.cpp index 24320a0..a2c3931 100644 --- a/Src/Client/ServerSession.cpp +++ b/Src/Client/ServerSession.cpp @@ -51,38 +51,38 @@ struct PP_Content_RegionRemove : public ParsedPacket { }; struct PP_Definition_Voxel : public ParsedPacket { - DefVoxelId_t Id; + DefVoxelId Id; DefVoxel_t Def; - PP_Definition_Voxel(DefVoxelId_t id, DefVoxel_t def) + PP_Definition_Voxel(DefVoxelId id, DefVoxel_t def) : ParsedPacket(ToClient::L1::Definition, (uint8_t) ToClient::L2Definition::Voxel), Id(id), Def(def) {} }; struct PP_Definition_FreeVoxel : public ParsedPacket { - DefVoxelId_t Id; + DefVoxelId Id; - PP_Definition_FreeVoxel(DefVoxelId_t id) + PP_Definition_FreeVoxel(DefVoxelId id) : ParsedPacket(ToClient::L1::Definition, (uint8_t) ToClient::L2Definition::FreeVoxel), Id(id) {} }; struct PP_Definition_Node : public ParsedPacket { - DefNodeId_t Id; + DefNodeId Id; DefNode_t Def; - PP_Definition_Node(DefNodeId_t id, DefNode_t def) + PP_Definition_Node(DefNodeId id, DefNode_t def) : ParsedPacket(ToClient::L1::Definition, (uint8_t) ToClient::L2Definition::Node), Id(id), Def(def) {} }; struct PP_Definition_FreeNode : public ParsedPacket { - DefNodeId_t Id; + DefNodeId Id; - PP_Definition_FreeNode(DefNodeId_t id) + PP_Definition_FreeNode(DefNodeId id) : ParsedPacket(ToClient::L1::Definition, (uint8_t) ToClient::L2Definition::FreeNode), Id(id) {} @@ -331,8 +331,8 @@ void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) { { std::unordered_map, std::unordered_set>> changeOrAddList_removeList; - std::unordered_map> onContentDefinesAdd; - std::unordered_map> onContentDefinesLost; + std::unordered_map> onContentDefinesAdd; + std::unordered_map> onContentDefinesLost; // Пакеты ParsedPacket *pack; @@ -601,30 +601,30 @@ coro<> ServerSession::rP_Definition(Net::AsyncSocket &sock) { switch((ToClient::L2Definition) second) { case ToClient::L2Definition::World: { - DefWorldId_t cdId = co_await sock.read(); + DefWorldId cdId = co_await sock.read(); co_return; } case ToClient::L2Definition::FreeWorld: { - DefWorldId_t cdId = co_await sock.read(); + DefWorldId cdId = co_await sock.read(); co_return; } case ToClient::L2Definition::Voxel: { - DefVoxelId_t cdId = co_await sock.read(); + DefVoxelId cdId = co_await sock.read(); co_return; } case ToClient::L2Definition::FreeVoxel: { - DefVoxelId_t cdId = co_await sock.read(); + DefVoxelId cdId = co_await sock.read(); co_return; } case ToClient::L2Definition::Node: { - DefNodeId_t id; + DefNodeId id; DefNode_t def; - id = co_await sock.read(); + id = co_await sock.read(); def.DrawType = (DefNode_t::EnumDrawType) co_await sock.read(); for(int iter = 0; iter < 6; iter++) { auto &pl = def.Texs[iter].Pipeline; @@ -643,7 +643,7 @@ coro<> ServerSession::rP_Definition(Net::AsyncSocket &sock) { } case ToClient::L2Definition::FreeNode: { - DefNodeId_t id = co_await sock.read(); + DefNodeId id = co_await sock.read(); PP_Definition_FreeNode *packet = new PP_Definition_FreeNode( id diff --git a/Src/Client/Vulkan/VulkanRenderSession.cpp b/Src/Client/Vulkan/VulkanRenderSession.cpp index a687f54..07300ad 100644 --- a/Src/Client/Vulkan/VulkanRenderSession.cpp +++ b/Src/Client/Vulkan/VulkanRenderSession.cpp @@ -24,8 +24,8 @@ void VulkanRenderSession::ThreadVertexObj_t::run() { LOG.debug() << "Старт потока подготовки чанков к рендеру"; // Контейнеры событий - std::vector changedDefines_Voxel; - std::vector changedDefines_Node; + std::vector changedDefines_Voxel; + std::vector changedDefines_Node; std::unordered_map> changedContent_Chunk; std::unordered_map> changedContent_RegionRemove; @@ -991,11 +991,11 @@ void VulkanRenderSession::onBinaryResourceAdd(std::vector) { } -void VulkanRenderSession::onContentDefinesAdd(std::unordered_map>) { +void VulkanRenderSession::onContentDefinesAdd(std::unordered_map>) { } -void VulkanRenderSession::onContentDefinesLost(std::unordered_map>) { +void VulkanRenderSession::onContentDefinesLost(std::unordered_map>) { } diff --git a/Src/Client/Vulkan/VulkanRenderSession.hpp b/Src/Client/Vulkan/VulkanRenderSession.hpp index 8b1a759..a8336da 100644 --- a/Src/Client/Vulkan/VulkanRenderSession.hpp +++ b/Src/Client/Vulkan/VulkanRenderSession.hpp @@ -96,9 +96,9 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent { struct ChunkObj_t { // Сортированный список уникальных значений - std::vector VoxelDefines; + std::vector VoxelDefines; VertexPool::Pointer VoxelPointer; - std::vector NodeDefines; + std::vector NodeDefines; VertexPool::Pointer NodePointer; }; @@ -129,7 +129,7 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent { // Сюда входят добавленные/изменённые/удалённые определения нод и вокселей // Чтобы перерисовать чанки, связанные с ними - void onContentDefinesChange(const std::vector& voxels, const std::vector& nodes) { + void onContentDefinesChange(const std::vector& voxels, const std::vector& nodes) { ChangedDefines_Voxel.insert(ChangedDefines_Voxel.end(), voxels.begin(), voxels.end()); ChangedDefines_Node.insert(ChangedDefines_Node.end(), nodes.begin(), nodes.end()); } @@ -239,8 +239,8 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent { VertexPool VertexPool_Voxels; VertexPool VertexPool_Nodes; // Списки изменённых определений - std::vector ChangedDefines_Voxel; - std::vector ChangedDefines_Node; + std::vector ChangedDefines_Voxel; + std::vector ChangedDefines_Node; // Список чанков на перерисовку std::unordered_map> ChangedContent_Chunk; std::unordered_map> ChangedContent_RegionRemove; @@ -315,7 +315,7 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent { NodeStaticOpaquePipeline = VK_NULL_HANDLE, NodeStaticTransparentPipeline = VK_NULL_HANDLE; - std::map ServerToAtlas; + std::map ServerToAtlas; struct { } External; @@ -338,8 +338,8 @@ public: } virtual void onBinaryResourceAdd(std::vector) override; - virtual void onContentDefinesAdd(std::unordered_map>) override; - virtual void onContentDefinesLost(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; diff --git a/Src/Common/Abstract.cpp b/Src/Common/Abstract.cpp index 99b5c73..9fdcaa8 100644 --- a/Src/Common/Abstract.cpp +++ b/Src/Common/Abstract.cpp @@ -12,8 +12,8 @@ namespace LV { CompressedVoxels compressVoxels_byte(const std::vector& voxels) { std::u8string compressed; - std::vector defines; - DefVoxelId_t maxValue = 0; + std::vector defines; + DefVoxelId maxValue = 0; defines.reserve(voxels.size()); compressed.push_back(1); @@ -55,7 +55,7 @@ CompressedVoxels compressVoxels_byte(const std::vector& voxels) { compressed.push_back((defines.size() >> 8) & 0xff); // Таблица - for(DefVoxelId_t id : defines) { + for(DefVoxelId id : defines) { compressed.push_back(id & 0xff); if(bytes_raw > 1) compressed.push_back((id >> 8) & 0xff); @@ -107,11 +107,11 @@ CompressedVoxels compressVoxels_byte(const std::vector& voxels) { } CompressedVoxels compressVoxels_bit(const std::vector& voxels) { - std::vector profile; - std::vector one_byte[7]; + std::vector profile; + std::vector one_byte[7]; - DefVoxelId_t maxValueProfile = 0; - DefVoxelId_t maxValues[7] = {0}; + DefVoxelId maxValueProfile = 0; + DefVoxelId maxValues[7] = {0}; profile.reserve(voxels.size()); for(int iter = 0; iter < 7; iter++) @@ -195,7 +195,7 @@ CompressedVoxels compressVoxels_bit(const std::vector& voxels) { write(bits_raw_profile, 5); write(bits_index_profile, 4); - for(DefNodeId_t id : profile) + for(DefNodeId id : profile) write(id, bits_raw_profile); } else { write(bits_raw_profile, 5); @@ -274,11 +274,11 @@ std::vector unCompressVoxels_byte(const std::u8string& compressed) { uint8_t bytes_per_define = (cmd >> 1) & 0x1; uint8_t bytes_raw = (cmd >> 2) & 0x3; - std::vector defines; + std::vector defines; defines.resize(read() | (read() << 8)); for(size_t iter = 0; iter < defines.size(); iter++) { - DefVoxelId_t id = read(); + DefVoxelId id = read(); if(bytes_raw > 1) id |= read() << 8; if(bytes_raw > 2) @@ -357,8 +357,8 @@ std::vector unCompressVoxels_bit(const std::u8string& compressed) { for(int iter = 0; iter < 7; iter++) indices[iter] = read(1); - std::vector profile; - std::vector one_byte[7]; + std::vector profile; + std::vector one_byte[7]; uint8_t bits_raw_profile; uint8_t bits_index_profile; size_t bits_raw[7]; @@ -435,13 +435,13 @@ std::vector unCompressVoxels(const std::u8string& compressed) { CompressedNodes compressNodes_byte(const Node* nodes) { std::u8string compressed; - std::vector profiles; + std::vector profiles; profiles.reserve(16*16*16); compressed.push_back(1); - DefNodeId_t maxValueProfile = 0; + DefNodeId maxValueProfile = 0; for(size_t iter = 0; iter < 16*16*16; iter++) { const Node &node = nodes[iter]; @@ -477,7 +477,7 @@ CompressedNodes compressNodes_byte(const Node* nodes) { compressed.push_back((profiles.size() >> 8) & 0xff); compressed.push_back((profiles.size() >> 16) & 0xff); - for(DefNodeId_t id : profiles) { + for(DefNodeId id : profiles) { if(bytes_raw_profile > 0) compressed.push_back(id & 0xff); if(bytes_raw_profile > 1) @@ -521,15 +521,15 @@ CompressedNodes compressNodes_byte(const Node* nodes) { CompressedNodes compressNodes_bit(const Node* nodes) { std::u8string compressed; - std::vector profiles; - std::vector meta; + std::vector profiles; + std::vector meta; profiles.reserve(16*16*16); meta.reserve(16*16*16); compressed.push_back(1); - DefNodeId_t maxValueProfile = 0, + DefNodeId maxValueProfile = 0, maxValueMeta = 0; for(size_t iter = 0; iter < 16*16*16; iter++) { @@ -599,7 +599,7 @@ CompressedNodes compressNodes_bit(const Node* nodes) { if(indices_profile) { write(profiles.size(), 12); - for(DefNodeId_t id : profiles) { + for(DefNodeId id : profiles) { write(id, bits_raw_profile); } } @@ -608,7 +608,7 @@ CompressedNodes compressNodes_bit(const Node* nodes) { if(indices_meta) { write(meta.size(), 8); - for(DefNodeId_t id : meta) { + for(DefNodeId id : meta) { write(id, bits_raw_meta); } } @@ -636,13 +636,12 @@ CompressedNodes compressNodes_bit(const Node* nodes) { return {compressLinear(compressed), profiles}; } - CompressedNodes compressNodes(const Node* nodes, bool fast) { std::u8string data(16*16*16*sizeof(Node), '\0'); const char8_t *ptr = (const char8_t*) nodes; std::copy(ptr, ptr+16*16*16*4, data.data()); - std::vector node(16*16*16); + std::vector node(16*16*16); for(int iter = 0; iter < 16*16*16; iter++) { node[iter] = nodes[iter].NodeId; } @@ -677,11 +676,11 @@ void unCompressNodes_byte(const std::u8string& compressed, Node* ptr) { bool indices_profile = value & 0x1; if(indices_profile) { - std::vector profiles; + std::vector profiles; profiles.resize(read() | (read() << 8) | (read() << 16)); for(size_t iter = 0; iter < profiles.size(); iter++) { - DefNodeId_t id = 0; + DefNodeId id = 0; if(bytes_raw_profile > 0) id = read(); @@ -694,7 +693,7 @@ void unCompressNodes_byte(const std::u8string& compressed, Node* ptr) { for(size_t iter = 0; iter < 16*16*16; iter++) { Node &node = ptr[iter]; - DefNodeId_t index = read(); + DefNodeId index = read(); if(bytes_indices_profile > 1) index |= read() << 8; @@ -733,7 +732,7 @@ void unCompressNodes_bit(const std::u8string& compressed, Node* ptr) { return out; }; - std::vector meta; + std::vector meta; bool indices_profile = read(1); @@ -744,7 +743,7 @@ void unCompressNodes_bit(const std::u8string& compressed, Node* ptr) { uint8_t bits_raw_meta = read(3); uint8_t bits_indices_meta = read(3); - std::vector profiles; + std::vector profiles; // Таблицы if(indices_profile) { diff --git a/Src/Server/AssetsManager.cpp b/Src/Server/AssetsManager.cpp index f9706c2..523d302 100644 --- a/Src/Server/AssetsManager.cpp +++ b/Src/Server/AssetsManager.cpp @@ -144,6 +144,9 @@ AssetsManager::Out_recheckResources AssetsManager::recheckResources(const Assets } for(const fs::path& path : info.Assets) { + if(!fs::exists(path)) + continue; + for(auto begin = fs::directory_iterator(path), end = fs::directory_iterator(); begin != end; begin++) { if(!begin->is_directory()) continue; @@ -264,12 +267,15 @@ AssetsManager::Out_applyResourceChange AssetsManager::applyResourceChange(const result.NewOrChange[type].push_back({id, resource}); keyToIdDomain[key] = id; - data->emplace(lwt, resource); + data->emplace(lwt, resource, domain, key); } } // Удалённые идентификаторы не считаются удалёнными, если были изменены - std::unordered_set noc(result.NewOrChange[type].begin(), result.NewOrChange[type].end()); + std::unordered_set noc; + for(auto& [id, _] : result.NewOrChange[type]) + noc.insert(id); + std::unordered_set l(result.Lost[type].begin(), result.Lost[type].end()); result.Lost[type].clear(); std::set_difference(l.begin(), l.end(), noc.begin(), noc.end(), std::back_inserter(result.Lost[type])); @@ -278,18 +284,4 @@ AssetsManager::Out_applyResourceChange AssetsManager::applyResourceChange(const return result; } -ResourceId AssetsManager::getId(EnumAssets type, const std::string& domain, const std::string& key) { - auto lock = LocalObj.lock(); - auto& keyToId = lock->KeyToId[(int) type]; - if(auto iterKTI = keyToId.find(domain); iterKTI != keyToId.end()) { - if(auto iterKey = iterKTI->second.find(key); iterKey != iterKTI->second.end()) { - return iterKey->second; - } - } - - auto [id, entry] = lock->nextId(type); - keyToId[domain][key] = id; - return id; -} - } \ No newline at end of file diff --git a/Src/Server/AssetsManager.hpp b/Src/Server/AssetsManager.hpp index f5ca891..baa5ccc 100644 --- a/Src/Server/AssetsManager.hpp +++ b/Src/Server/AssetsManager.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -61,6 +62,7 @@ private: // Время последнего изменения файла fs::file_time_type FileChangeTime; Resource Res; + std::string Domain, Key; }; struct TableEntry { @@ -143,7 +145,29 @@ public: Выдаёт идентификатор ресурса, даже если он не существует или был удалён. resource должен содержать домен и путь */ - ResourceId getId(EnumAssets type, const std::string& domain, const std::string& key); + ResourceId getId(EnumAssets type, const std::string& domain, const std::string& key) { + auto lock = LocalObj.lock(); + auto& keyToId = lock->KeyToId[(int) type]; + if(auto iterKTI = keyToId.find(domain); iterKTI != keyToId.end()) { + if(auto iterKey = iterKTI->second.find(key); iterKey != iterKTI->second.end()) { + return iterKey->second; + } + } + + auto [id, entry] = lock->nextId(type); + keyToId[domain][key] = id; + return id; + } + + std::optional> getResource(EnumAssets type, ResourceId id) { + auto lock = LocalObj.lock(); + assert(id < lock->Table[(int) type].size()*TableEntry::ChunkSize); + auto& value = lock->Table[(int) type][id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; + if(value) + return {{value->Res, value->Domain, value->Key}}; + else + return std::nullopt; + } }; } \ No newline at end of file diff --git a/Src/Server/ContentEventController.cpp b/Src/Server/ContentEventController.cpp_ similarity index 100% rename from Src/Server/ContentEventController.cpp rename to Src/Server/ContentEventController.cpp_ diff --git a/Src/Server/ContentManager.cpp b/Src/Server/ContentManager.cpp index f702c87..d1996cd 100644 --- a/Src/Server/ContentManager.cpp +++ b/Src/Server/ContentManager.cpp @@ -18,56 +18,64 @@ void ContentManager::registerBase_Node(ResourceId id, const sol::table& profile) DefNode& def = *node; { - std::variant parent = profile["parent"]; - if(const sol::table* table = std::get_if(&parent)) { - // result = createNodeProfileByLua(*table); - } else if(const std::string* key = std::get_if(&parent)) { - auto regResult = TOS::Str::match(*key, "(?:([\\w\\d_]+):)?([\\w\\d_]+)"); - if(!regResult) - MAKE_ERROR("Недействительный ключ в определении parent"); + std::optional> parent = profile.get>>("parent"); + if(parent) { + if(const sol::table* table = std::get_if(&*parent)) { + // result = createNodeProfileByLua(*table); + } else if(const std::string* key = std::get_if(&*parent)) { + auto regResult = TOS::Str::match(*key, "(?:([\\w\\d_]+):)?([\\w\\d_]+)"); + if(!regResult) + MAKE_ERROR("Недействительный ключ в определении parent"); - std::string realKey; + std::string realKey; - if(regResult->at(1)) { - realKey = *key; - } else { - realKey = "core:" + *regResult->at(2); + if(regResult->at(1)) { + realKey = *key; + } else { + realKey = "core:" + *regResult->at(2); + } + + DefNodeId parentId; + + // { + // auto& list = Content.ContentKeyToId[(int) EnumDefContent::Node]; + // auto iter = list.find(realKey); + // if(iter == list.end()) + // MAKE_ERROR("Идентификатор parent не найден"); + + // parentId = iter->second; + // } + + // result = Content.ContentIdToDef_Node.at(parentId); } - - DefNodeId_t parentId; - - // { - // auto& list = Content.ContentKeyToId[(int) EnumDefContent::Node]; - // auto iter = list.find(realKey); - // if(iter == list.end()) - // MAKE_ERROR("Идентификатор parent не найден"); - - // parentId = iter->second; - // } - - // result = Content.ContentIdToDef_Node.at(parentId); } } { - std::optional nodestate = profile["nodestate"]; + std::optional nodestate = profile.get>("nodestate"); } { - std::optional render = profile["render"]; + std::optional render = profile.get>("render"); } { - std::optional collision = profile["collision"]; + std::optional collision = profile.get>("collision"); } { - std::optional events = profile["events"]; + std::optional events = profile.get>("events"); } // result.NodeAdvancementFactory = profile["node_advancement_factory"]; } +void ContentManager::registerBase_World(ResourceId id, const sol::table& profile) { + std::optional& world = getEntry_World(id); + if(!world) + world.emplace(); +} + void ContentManager::registerBase(EnumDefContent type, const std::string& domain, const std::string& key, const sol::table& profile) { ResourceId id = getId(type, domain, key); @@ -75,6 +83,8 @@ void ContentManager::registerBase(EnumDefContent type, const std::string& domain if(type == EnumDefContent::Node) registerBase_Node(id, profile); + else if(type == EnumDefContent::World) + registerBase_World(id, profile); else MAKE_ERROR("Не реализовано"); } @@ -107,6 +117,10 @@ ContentManager::Out_buildEndProfiles ContentManager::buildEndProfiles() { keys.erase(iterErase, keys.end()); } + for(ResourceId id : ProfileChanges[(int) EnumDefContent::Voxel]) { + + } + return result; } diff --git a/Src/Server/ContentManager.hpp b/Src/Server/ContentManager.hpp index a2572c9..463ff7c 100644 --- a/Src/Server/ContentManager.hpp +++ b/Src/Server/ContentManager.hpp @@ -24,12 +24,16 @@ struct DefPortal_Mod { }; struct DefEntity_Mod { }; struct DefItem_Mod { }; -struct DefVoxel { }; -struct DefNode { }; -struct DefWorld { }; -struct DefPortal { }; -struct DefEntity { }; -struct DefItem { }; +struct ResourceBase { + std::string Domain, Key; +}; + +struct DefVoxel : public ResourceBase { }; +struct DefNode : public ResourceBase { }; +struct DefWorld : public ResourceBase { }; +struct DefPortal : public ResourceBase { }; +struct DefEntity : public ResourceBase { }; +struct DefItem : public ResourceBase { }; class ContentManager { template @@ -89,10 +93,41 @@ class ContentManager { ResourceId resId = NextId[(int) type]++; ContentKeyToId[(int) type][domain][key] = resId; + + switch(type) { + case EnumDefContent::Voxel: + if(resId >= Profiles_Voxel.size()*TableEntry::ChunkSize) + Profiles_Voxel.push_back(std::make_unique>()); + break; + case EnumDefContent::Node: + if(resId >= Profiles_Node.size()*TableEntry::ChunkSize) + Profiles_Node.push_back(std::make_unique>()); + break; + case EnumDefContent::World: + if(resId >= Profiles_World.size()*TableEntry::ChunkSize) + Profiles_World.push_back(std::make_unique>()); + break; + case EnumDefContent::Portal: + if(resId >= Profiles_Portal.size()*TableEntry::ChunkSize) + Profiles_Portal.push_back(std::make_unique>()); + break; + case EnumDefContent::Entity: + if(resId >= Profiles_Entity.size()*TableEntry::ChunkSize) + Profiles_Entity.push_back(std::make_unique>()); + break; + case EnumDefContent::Item: + if(resId >= Profiles_Item.size()*TableEntry::ChunkSize) + Profiles_Item.push_back(std::make_unique>()); + break; + default: + assert(false); + } + return resId; } void registerBase_Node(ResourceId id, const sol::table& profile); + void registerBase_World(ResourceId id, const sol::table& profile); public: ContentManager(asio::io_context& ioc); @@ -110,6 +145,60 @@ public: }; Out_buildEndProfiles buildEndProfiles(); + + std::optional getProfile_Voxel(ResourceId id) { + assert(id < Profiles_Voxel.size()*TableEntry::ChunkSize); + auto& value = Profiles_Voxel[id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; + if(value) + return {&*value}; + else + return std::nullopt; + } + + std::optional getProfile_Node(ResourceId id) { + assert(id < Profiles_Node.size()*TableEntry::ChunkSize); + auto& value = Profiles_Node[id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; + if(value) + return {&*value}; + else + return std::nullopt; + } + + std::optional getProfile_World(ResourceId id) { + assert(id < Profiles_World.size()*TableEntry::ChunkSize); + auto& value = Profiles_World[id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; + if(value) + return {&*value}; + else + return std::nullopt; + } + + std::optional getProfile_Portal(ResourceId id) { + assert(id < Profiles_Portal.size()*TableEntry::ChunkSize); + auto& value = Profiles_Portal[id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; + if(value) + return {&*value}; + else + return std::nullopt; + } + + std::optional getProfile_Entity(ResourceId id) { + assert(id < Profiles_Entity.size()*TableEntry::ChunkSize); + auto& value = Profiles_Entity[id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; + if(value) + return {&*value}; + else + return std::nullopt; + } + + std::optional getProfile_Item(ResourceId id) { + assert(id < Profiles_Item.size()*TableEntry::ChunkSize); + auto& value = Profiles_Item[id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; + if(value) + return {&*value}; + else + return std::nullopt; + } }; } \ No newline at end of file diff --git a/Src/Server/GameServer.cpp b/Src/Server/GameServer.cpp index 38f5a93..06a6f8b 100644 --- a/Src/Server/GameServer.cpp +++ b/Src/Server/GameServer.cpp @@ -4,6 +4,7 @@ #include "Common/Packets.hpp" #include "Server/Abstract.hpp" #include "Server/AssetsManager.hpp" +#include "Server/ContentManager.hpp" #include "Server/RemoteClient.hpp" #include #include @@ -546,14 +547,14 @@ void GameServer::BackingChunkPressure_t::run(int id) { Dump dumpRegion; - dumpRegion.CECs = regionObj.CECs; + dumpRegion.CECs = regionObj.RMs; dumpRegion.IsChunkChanged_Voxels = regionObj.IsChunkChanged_Voxels; regionObj.IsChunkChanged_Voxels = 0; dumpRegion.IsChunkChanged_Nodes = regionObj.IsChunkChanged_Nodes; regionObj.IsChunkChanged_Nodes = 0; - if(!regionObj.NewCECs.empty()) { - dumpRegion.NewCECs = std::move(regionObj.NewCECs); + if(!regionObj.NewRMs.empty()) { + dumpRegion.NewCECs = std::move(regionObj.NewRMs); dumpRegion.Voxels = regionObj.Voxels; for(int z = 0; z < 4; z++) @@ -640,7 +641,7 @@ void GameServer::BackingChunkPressure_t::run(int id) { Pos::GlobalChunk chunkPosR = (Pos::GlobalChunk(regionPos) << 2) + chunkPos; for(auto& ptr : region.NewCECs) { - bool accepted = ptr->Remote->maybe_prepareChunkUpdate_Voxels(worldId, + bool accepted = ptr->maybe_prepareChunkUpdate_Voxels(worldId, chunkPosR, cmp.Compressed, cmp.Defines); if(!accepted) { cecs.push_back(ptr.get()); @@ -660,7 +661,7 @@ void GameServer::BackingChunkPressure_t::run(int id) { if(skip) continue; - bool accepted = ptr->Remote->maybe_prepareChunkUpdate_Voxels(worldId, + bool accepted = ptr->maybe_prepareChunkUpdate_Voxels(worldId, chunkPosR, cmp.Compressed, cmp.Defines); if(!accepted) { cecs.push_back(ptr.get()); @@ -679,7 +680,7 @@ void GameServer::BackingChunkPressure_t::run(int id) { Pos::GlobalChunk chunkPosR = (Pos::GlobalChunk(regionPos) << 2) + chunkPos; for(auto& ptr : region.NewCECs) { - bool accepted = ptr->Remote->maybe_prepareChunkUpdate_Nodes(worldId, + bool accepted = ptr->maybe_prepareChunkUpdate_Nodes(worldId, chunkPosR, cmp.Compressed, cmp.Defines); if(!accepted) { cecs.push_back(ptr.get()); @@ -699,7 +700,7 @@ void GameServer::BackingChunkPressure_t::run(int id) { if(skip) continue; - bool accepted = ptr->Remote->maybe_prepareChunkUpdate_Nodes(worldId, + bool accepted = ptr->maybe_prepareChunkUpdate_Nodes(worldId, chunkPosR, cmp.Compressed, cmp.Defines); if(!accepted) { cecs.push_back(ptr.get()); @@ -721,7 +722,7 @@ void GameServer::BackingChunkPressure_t::run(int id) { while(begin != end) { auto& [worldId, chunkPos, cmp] = begin->first; for(RemoteClient* cec : begin->second) { - bool accepted = cec->Remote->maybe_prepareChunkUpdate_Voxels(worldId, chunkPos, cmp.Compressed, cmp.Defines); + bool accepted = cec->maybe_prepareChunkUpdate_Voxels(worldId, chunkPos, cmp.Compressed, cmp.Defines); if(!accepted) cecs.push_back(cec); } @@ -741,7 +742,7 @@ void GameServer::BackingChunkPressure_t::run(int id) { while(begin != end) { auto& [worldId, chunkPos, cmp] = begin->first; for(RemoteClient* cec : begin->second) { - bool accepted = cec->Remote->maybe_prepareChunkUpdate_Nodes(worldId, chunkPos, cmp.Compressed, cmp.Defines); + bool accepted = cec->maybe_prepareChunkUpdate_Nodes(worldId, chunkPos, cmp.Compressed, cmp.Defines); if(!accepted) cecs.push_back(cec); } @@ -855,7 +856,7 @@ void GameServer::BackingAsyncLua_t::run(int id) { for(int z = 0; z < 64; z++) for(int y = 0; y < 64; y++) for(int x = 0; x < 64; x++, ptr++) { - DefVoxelId_t id = std::clamp(*ptr, 0.f, 1.f) * 3; //> 0.9 ? 1 : 0; + DefVoxelId id = std::clamp(*ptr, 0.f, 1.f) * 3; //> 0.9 ? 1 : 0; Pos::bvec64u nodePos(x, y, z); auto &node = out.Nodes[Pos::bvec4u(nodePos >> 4).pack()][Pos::bvec16u(nodePos & 0xf).pack()]; node.NodeId = id; @@ -1441,18 +1442,32 @@ void GameServer::init(fs::path worldPath) { initLuaAssets(); pushEvent("initAssets"); - for(ssize_t index = mlt.LoadChain.size(); index >= 0; index--) { + for(ssize_t index = mlt.LoadChain.size()-1; index >= 0; index--) { AssetsInit.Assets.push_back(mlt.LoadChain[index].Path / "assets"); } Content.AM.applyResourceChange(Content.AM.recheckResources(AssetsInit)); LOG.info() << "Пре Инициализация"; + + { + sol::table t = LuaMainState.create_table(); + Content.CM.registerBase(EnumDefContent::Node, "core", "test0", t); + Content.CM.registerBase(EnumDefContent::Node, "core", "test1", t); + Content.CM.registerBase(EnumDefContent::Node, "core", "test2", t); + Content.CM.registerBase(EnumDefContent::Node, "core", "test3", t); + Content.CM.registerBase(EnumDefContent::Node, "core", "test4", t); + Content.CM.registerBase(EnumDefContent::Node, "core", "test5", t); + Content.CM.registerBase(EnumDefContent::World, "core", "devel_world", t); + } + initLuaPre(); pushEvent("lowPreInit"); // TODO: регистрация контента из mod/content/* + Content.CM.buildEndProfiles(); + pushEvent("preInit"); pushEvent("highPreInit"); @@ -1513,15 +1528,15 @@ void GameServer::run() { if(IsGoingShutdown) { // Отключить игроков - for(std::shared_ptr &cec : Game.CECs) { - cec->Remote->shutdown(EnumDisconnect::ByInterface, ShutdownReason); + for(std::shared_ptr &remoteClient : Game.RemoteClients) { + remoteClient->shutdown(EnumDisconnect::ByInterface, ShutdownReason); } { // Отключить вновь подключившихся auto lock = External.NewConnectedPlayers.lock_write(); - for(std::unique_ptr &client : *lock) { + for(std::shared_ptr &client : *lock) { client->shutdown(EnumDisconnect::ByInterface, ShutdownReason); } @@ -1578,7 +1593,7 @@ void GameServer::run() { void GameServer::initLuaAssets() { auto &lua = LuaMainState; - std::optional core = lua["core"]; + std::optional core = lua.get>("core"); if(!core) core = lua.create_named_table("core"); @@ -1598,13 +1613,13 @@ void GameServer::initLuaAssets() { AssetsInit.Custom[(int) type][CurrentModId][*result[2]] = nullptr; }; - core->set_function("register_nodestate", std::bind(reg, EnumAssets::Nodestate, std::placeholders::_1, std::placeholders::_2)); - core->set_function("register_particle", std::bind(reg, EnumAssets::Patricle, std::placeholders::_1, std::placeholders::_2)); - core->set_function("register_animation", std::bind(reg, EnumAssets::Animation, std::placeholders::_1, std::placeholders::_2)); - core->set_function("register_model", std::bind(reg, EnumAssets::Model, std::placeholders::_1, std::placeholders::_2)); - core->set_function("register_texture", std::bind(reg, EnumAssets::Texture, std::placeholders::_1, std::placeholders::_2)); - core->set_function("register_sound", std::bind(reg, EnumAssets::Sound, std::placeholders::_1, std::placeholders::_2)); - core->set_function("register_font", std::bind(reg, EnumAssets::Font, std::placeholders::_1, std::placeholders::_2)); + core->set_function("register_nodestate", [&](const std::string& key, const sol::table& profile) { reg(EnumAssets::Nodestate, key, profile); }); + core->set_function("register_particle", [&](const std::string& key, const sol::table& profile) { reg(EnumAssets::Patricle, key, profile); }); + core->set_function("register_animation", [&](const std::string& key, const sol::table& profile) { reg(EnumAssets::Animation, key, profile); }); + core->set_function("register_model", [&](const std::string& key, const sol::table& profile) { reg(EnumAssets::Model, key, profile); }); + core->set_function("register_texture", [&](const std::string& key, const sol::table& profile) { reg(EnumAssets::Texture, key, profile); }); + core->set_function("register_sound", [&](const std::string& key, const sol::table& profile) { reg(EnumAssets::Sound, key, profile); }); + core->set_function("register_font", [&](const std::string& key, const sol::table& profile) { reg(EnumAssets::Font, key, profile); }); } void GameServer::initLuaPre() { @@ -1635,12 +1650,12 @@ void GameServer::initLuaPre() { Content.CM.registerBase(type, CurrentModId, *result[2], profile); }; - core.set_function("register_voxel", std::bind(reg, EnumDefContent::Voxel, std::placeholders::_1, std::placeholders::_2)); - core.set_function("register_node", std::bind(reg, EnumDefContent::Node, std::placeholders::_1, std::placeholders::_2)); - core.set_function("register_world", std::bind(reg, EnumDefContent::World, std::placeholders::_1, std::placeholders::_2)); - core.set_function("register_portal", std::bind(reg, EnumDefContent::Portal, std::placeholders::_1, std::placeholders::_2)); - core.set_function("register_entity", std::bind(reg, EnumDefContent::Entity, std::placeholders::_1, std::placeholders::_2)); - core.set_function("register_item", std::bind(reg, EnumDefContent::Item, std::placeholders::_1, std::placeholders::_2)); + core.set_function("register_voxel", [&](const std::string& key, const sol::table& profile) { reg(EnumDefContent::Voxel, key, profile); }); + core.set_function("register_node", [&](const std::string& key, const sol::table& profile) { reg(EnumDefContent::Node, key, profile); }); + core.set_function("register_world", [&](const std::string& key, const sol::table& profile) { reg(EnumDefContent::World, key, profile); }); + core.set_function("register_portal", [&](const std::string& key, const sol::table& profile) { reg(EnumDefContent::Portal, key, profile); }); + core.set_function("register_entity", [&](const std::string& key, const sol::table& profile) { reg(EnumDefContent::Entity, key, profile); }); + core.set_function("register_item", [&](const std::string& key, const sol::table& profile) { reg(EnumDefContent::Item, key, profile); }); } void GameServer::initLua() { @@ -1667,9 +1682,9 @@ void GameServer::stepConnections() { if(!External.NewConnectedPlayers.no_lock_readable().empty()) { auto lock = External.NewConnectedPlayers.lock_write(); - for(std::unique_ptr& client : *lock) { + for(std::shared_ptr& client : *lock) { co_spawn(client->run()); - Game.CECs.push_back(std::make_unique(std::move(client))); + Game.RemoteClients.push_back(client); } lock->clear(); @@ -1678,28 +1693,28 @@ void GameServer::stepConnections() { BackingChunkPressure.endCollectChanges(); // Отключение игроков - for(std::shared_ptr& cec : Game.CECs) { + for(std::shared_ptr& cec : Game.RemoteClients) { // Убрать отключившихся - if(!cec->Remote->isConnected()) { + if(!cec->isConnected()) { // Отписываем наблюдателя от миров for(auto wPair : cec->ContentViewState.Regions) { auto wIter = Expanse.Worlds.find(wPair.first); assert(wIter != Expanse.Worlds.end()); - wIter->second->onCEC_RegionsLost(cec, wPair.second); + wIter->second->onRemoteClient_RegionsLost(cec, wPair.second); } - std::string username = cec->Remote->Username; + std::string username = cec->Username; External.ConnectedPlayersSet.lock_write()->erase(username); - cec.reset(); + cec = nullptr; } } // Вычистить невалидные ссылки на игроков - Game.CECs.erase(std::remove_if(Game.CECs.begin(), Game.CECs.end(), + Game.RemoteClients.erase(std::remove_if(Game.RemoteClients.begin(), Game.RemoteClients.end(), [](const std::shared_ptr& ptr) { return !ptr; }), - Game.CECs.end()); + Game.RemoteClients.end()); } void GameServer::stepModInitializations() { @@ -1709,44 +1724,56 @@ void GameServer::stepModInitializations() { IWorldSaveBackend::TickSyncInfo_Out GameServer::stepDatabaseSync() { IWorldSaveBackend::TickSyncInfo_In toDB; - for(std::shared_ptr& cec : Game.CECs) { - assert(cec); + for(std::shared_ptr& remoteClient : Game.RemoteClients) { + assert(remoteClient); // Пересчитать зоны наблюдения - if(cec->CrossedBorder) { - cec->CrossedBorder = false; + if(remoteClient->CrossedRegion) { + remoteClient->CrossedRegion = false; // Пересчёт зон наблюдения - ServerObjectPos oPos = cec->getPos(); + std::vector newCVCs; - ContentViewCircle cvc; - cvc.WorldId = oPos.WorldId; - cvc.Pos = Pos::Object_t::asRegionsPos(oPos.ObjectPos); - cvc.Range = 2; + { + std::vector> points = remoteClient->getViewPoints(); + for(auto& [wId, pos, radius] : points) { + assert(radius < 5); + ContentViewCircle cvc; + cvc.WorldId = wId; + cvc.Pos = Pos::Object_t::asRegionsPos(pos); + cvc.Range = radius*radius; + + std::vector list = Expanse.accumulateContentViewCircles(cvc); + newCVCs.insert(newCVCs.end(), list.begin(), list.end()); + } + } - std::vector newCVCs = Expanse.accumulateContentViewCircles(cvc); ContentViewInfo newCbg = Expanse_t::makeContentViewInfo(newCVCs); - ContentViewInfo_Diff diff = newCbg.diffWith(cec->ContentViewState); + ContentViewInfo_Diff diff = newCbg.diffWith(remoteClient->ContentViewState); if(!diff.WorldsNew.empty()) { // Сообщить о новых мирах for(const WorldId_t id : diff.WorldsNew) { auto iter = Expanse.Worlds.find(id); assert(iter != Expanse.Worlds.end()); - cec->onWorldUpdate(id, iter->second.get()); + remoteClient->prepareWorldUpdate(id, iter->second.get()); } } - cec->ContentViewState = newCbg; + remoteClient->ContentViewState = newCbg; // Вычистка не наблюдаемых регионов - cec->removeUnobservable(diff); + for(const auto& [worldId, regions] : diff.RegionsLost) + remoteClient->prepareRegionsRemove(worldId, regions); + // и миров + for(const WorldId_t worldId : diff.WorldsLost) + remoteClient->prepareWorldRemove(worldId); // Подписываем игрока на наблюдение за регионами for(const auto& [worldId, regions] : diff.RegionsNew) { auto iterWorld = Expanse.Worlds.find(worldId); assert(iterWorld != Expanse.Worlds.end()); - std::vector notLoaded = iterWorld->second->onCEC_RegionsEnter(cec, regions); + std::vector notLoaded = iterWorld->second->onRemoteClient_RegionsEnter(remoteClient, regions); if(!notLoaded.empty()) { // Добавляем к списку на загрузку std::vector &tl = toDB.Load[worldId]; @@ -1759,7 +1786,7 @@ IWorldSaveBackend::TickSyncInfo_Out GameServer::stepDatabaseSync() { auto iterWorld = Expanse.Worlds.find(worldId); assert(iterWorld != Expanse.Worlds.end()); - iterWorld->second->onCEC_RegionsLost(cec, regions); + iterWorld->second->onRemoteClient_RegionsLost(remoteClient, regions); } } } @@ -1855,20 +1882,20 @@ void GameServer::stepGeneratorAndLuaAsync(IWorldSaveBackend::TickSyncInfo_Out db std::unordered_map, std::vector> toSubscribe; - for(auto& cec : Game.CECs) { - auto iterViewWorld = cec->ContentViewState.Regions.find(worldId); - if(iterViewWorld == cec->ContentViewState.Regions.end()) + for(auto& remoteClient : Game.RemoteClients) { + auto iterViewWorld = remoteClient->ContentViewState.Regions.find(worldId); + if(iterViewWorld == remoteClient->ContentViewState.Regions.end()) continue; for(auto& pos : iterViewWorld->second) { if(std::binary_search(newRegions.begin(), newRegions.end(), pos)) - toSubscribe[cec].push_back(pos); + toSubscribe[remoteClient].push_back(pos); } } iterWorld->second->pushRegions(std::move(regions)); for(auto& [cec, poses] : toSubscribe) { - iterWorld->second->onCEC_RegionsEnter(cec, poses); + iterWorld->second->onRemoteClient_RegionsEnter(cec, poses); } } } @@ -2324,158 +2351,125 @@ void GameServer::stepGlobalStep() { } void GameServer::stepSyncContent() { - for(std::shared_ptr& cec : Game.CECs) { - cec->onUpdate(); + for(std::shared_ptr& remoteClient : Game.RemoteClients) { + remoteClient->onUpdate(); // Это для пробы строительства и ломания нод - while(!cec->Build.empty()) { - Pos::GlobalNode node = cec->Build.front(); - cec->Build.pop(); + // while(!cec->Build.empty()) { + // Pos::GlobalNode node = cec->Build.front(); + // cec->Build.pop(); - Pos::GlobalRegion rPos = node >> 6; - Pos::bvec4u cPos = (node >> 4) & 0x3; - Pos::bvec16u nPos = node & 0xf; + // Pos::GlobalRegion rPos = node >> 6; + // Pos::bvec4u cPos = (node >> 4) & 0x3; + // Pos::bvec16u nPos = node & 0xf; - auto ®ion = Expanse.Worlds[0]->Regions[rPos]; - region->Nodes[cPos.pack()][nPos.pack()].NodeId = 4; - region->IsChunkChanged_Nodes |= 1ull << cPos.pack(); - } + // auto ®ion = Expanse.Worlds[0]->Regions[rPos]; + // region->Nodes[cPos.pack()][nPos.pack()].NodeId = 4; + // region->IsChunkChanged_Nodes |= 1ull << cPos.pack(); + // } - while(!cec->Break.empty()) { - Pos::GlobalNode node = cec->Break.front(); - cec->Break.pop(); + // while(!cec->Break.empty()) { + // Pos::GlobalNode node = cec->Break.front(); + // cec->Break.pop(); - Pos::GlobalRegion rPos = node >> 6; - Pos::bvec4u cPos = (node >> 4) & 0x3; - Pos::bvec16u nPos = node & 0xf; + // Pos::GlobalRegion rPos = node >> 6; + // Pos::bvec4u cPos = (node >> 4) & 0x3; + // Pos::bvec16u nPos = node & 0xf; - auto ®ion = Expanse.Worlds[0]->Regions[rPos]; - region->Nodes[cPos.pack()][nPos.pack()].NodeId = 0; - region->IsChunkChanged_Nodes |= 1ull << cPos.pack(); - } + // auto ®ion = Expanse.Worlds[0]->Regions[rPos]; + // region->Nodes[cPos.pack()][nPos.pack()].NodeId = 0; + // region->IsChunkChanged_Nodes |= 1ull << cPos.pack(); + // } } // Сбор запросов на ресурсы и профили + отправка пакетов игрокам ResourceRequest full = std::move(Content.OnContentChanges); - for(std::shared_ptr& cec : Game.CECs) { - full.insert(cec->Remote->pushPreparedPackets()); + for(std::shared_ptr& cec : Game.RemoteClients) { + full.insert(cec->pushPreparedPackets()); } - full.uniq(); - // Запрашиваем двоичные ресурсы - // Content.BRM.needResourceResponse(full); - // Content.BRM.update(CurrentTickDuration); - // Получаем готовую информацию - // { - // BinaryResourceManager::OutObj_t out = Content.BRM.takePreparedInformation(); - // bool hasData = false; - // for(int iter = 0; iter < (int) EnumBinResource::MAX_ENUM; iter++) - // hasData |= !out.BinToHash[iter].empty(); - // if(hasData) { - // for(std::shared_ptr& cec : Game.CECs) { - // cec->Remote->informateIdToHash(out.BinToHash); - // } - // } + // Информируем о запрошенных ассетах + std::vector> resources; + for(int type = 0; type < (int) EnumAssets::MAX_ENUM; type++) { + for(ResourceId resId : full.AssetsInfo[type]) { + std::optional> result = Content.AM.getResource((EnumAssets) type, resId); + if(!result) + continue; - // if(!out.HashToResource.empty()) - // for(std::shared_ptr& cec : Game.CECs) { - // cec->Remote->informateBinary(out.HashToResource); - // } - // } + auto& [resource, domain, key] = *result; + resources.emplace_back((EnumAssets) type, resId, domain, key, resource); + } + + } - // Оповещаем об игровых профилях - // if(!full.Voxel.empty()) { - // std::unordered_map defines; + // Информируем о запрошенных профилях + std::vector> voxels; + for(DefVoxelId id : full.Voxel) { + auto value = Content.CM.getProfile_Voxel(id); + if(!value) + continue; - // for(DefVoxelId_t id : full.Node) { - // auto iter = Content.ContentIdToDef_Voxel.find(id); - // if(iter != Content.ContentIdToDef_Voxel.end()) { - // defines[id] = &iter->second; - // } - // } + voxels.emplace_back(id, *value); + } - // for(std::shared_ptr& cec : Game.CECs) { - // cec->Remote->informateDefVoxel(defines); - // } - // } + std::vector> nodes; + for(DefNodeId id : full.Node) { + auto value = Content.CM.getProfile_Node(id); + if(!value) + continue; - // if(!full.Node.empty()) { - // std::unordered_map defines; + nodes.emplace_back(id, *value); + } - // for(DefNodeId_t id : full.Node) { - // auto iter = Content.ContentIdToDef_Node.find(id); - // if(iter != Content.ContentIdToDef_Node.end()) { - // defines[id] = &iter->second; - // } - // } + std::vector> worlds; + for(DefWorldId id : full.World) { + auto value = Content.CM.getProfile_World(id); + if(!value) + continue; - // for(std::shared_ptr& cec : Game.CECs) { - // cec->Remote->informateDefNode(defines); - // } - // } + worlds.emplace_back(id, *value); + } - // if(!full.World.empty()) { - // std::unordered_map defines; + std::vector> portals; + for(DefPortalId id : full.Portal) { + auto value = Content.CM.getProfile_Portal(id); + if(!value) + continue; - // for(DefWorldId_t id : full.Node) { - // auto iter = Content.ContentIdToDef_World.find(id); - // if(iter != Content.ContentIdToDef_World.end()) { - // defines[id] = &iter->second; - // } - // } + portals.emplace_back(id, *value); + } - // for(std::shared_ptr& cec : Game.CECs) { - // cec->Remote->informateDefWorld(defines); - // } - // } + std::vector> entities; + for(DefEntityId id : full.Entity) { + auto value = Content.CM.getProfile_Entity(id); + if(!value) + continue; - // if(!full.Portal.empty()) { - // std::unordered_map defines; + entities.emplace_back(id, *value); + } - // for(DefPortalId_t id : full.Node) { - // auto iter = Content.ContentIdToDef_Portal.find(id); - // if(iter != Content.ContentIdToDef_Portal.end()) { - // defines[id] = &iter->second; - // } - // } + std::vector> items; + for(DefItemId id : full.Item) { + auto value = Content.CM.getProfile_Item(id); + if(!value) + continue; - // for(std::shared_ptr& cec : Game.CECs) { - // cec->Remote->informateDefPortal(defines); - // } - // } + items.emplace_back(id, *value); + } - // if(!full.Entity.empty()) { - // std::unordered_map defines; + for(std::shared_ptr& remoteClient : Game.RemoteClients) { + remoteClient->informateAssets(resources); + remoteClient->informateDefVoxel(voxels); + remoteClient->informateDefNode(nodes); + remoteClient->informateDefWorld(worlds); + remoteClient->informateDefPortal(portals); + remoteClient->informateDefEntity(entities); + remoteClient->informateDefItem(items); + } - // for(DefEntityId_t id : full.Node) { - // auto iter = Content.ContentIdToDef_Entity.find(id); - // if(iter != Content.ContentIdToDef_Entity.end()) { - // defines[id] = &iter->second; - // } - // } - - // for(std::shared_ptr& cec : Game.CECs) { - // cec->Remote->informateDefEntity(defines); - // } - // } - - // if(!full.Item.empty()) { - // std::unordered_map defines; - - // for(DefItemId_t id : full.Node) { - // auto iter = Content.ContentIdToDef_Item.find(id); - // if(iter != Content.ContentIdToDef_Item.end()) { - // defines[id] = &iter->second; - // } - // } - - // for(std::shared_ptr& cec : Game.CECs) { - // cec->Remote->informateDefItem(defines); - // } - // } BackingChunkPressure.startCollectChanges(); } diff --git a/Src/Server/GameServer.hpp b/Src/Server/GameServer.hpp index 26a5e75..0748d67 100644 --- a/Src/Server/GameServer.hpp +++ b/Src/Server/GameServer.hpp @@ -67,7 +67,7 @@ class GameServer : public AsyncObject { struct { Lockable> ConnectedPlayersSet; - Lockable>> NewConnectedPlayers; + Lockable>> NewConnectedPlayers; } External; struct ContentObj { diff --git a/Src/Server/RemoteClient.cpp b/Src/Server/RemoteClient.cpp index bf41eee..ae5da9d 100644 --- a/Src/Server/RemoteClient.cpp +++ b/Src/Server/RemoteClient.cpp @@ -3,6 +3,7 @@ #include "Common/Abstract.hpp" #include "Common/Net.hpp" #include "Server/Abstract.hpp" +#include "Server/World.hpp" #include #include #include @@ -49,7 +50,8 @@ void RemoteClient::shutdown(EnumDisconnect type, const std::string reason) { IsGoingShutdown = true; - NextPacket << (uint8_t) ToClient::L1::System + Net::Packet packet; + packet << (uint8_t) ToClient::L1::System << (uint8_t) ToClient::L2System::Disconnect << (uint8_t) type << reason; @@ -61,10 +63,12 @@ void RemoteClient::shutdown(EnumDisconnect type, const std::string reason) { else if(type == EnumDisconnect::ProtocolError) info = "ошибка протокола (сервер) " + reason; + Socket.pushPacket(std::move(packet)); + LOG.info() << "Игрок '" << Username << "' отключился " << info; } -void RemoteClient::murky_prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::u8string& compressed_voxels, +void RemoteClient::NetworkAndResource_t::prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::u8string& compressed_voxels, const std::vector& uniq_sorted_defines) { Pos::bvec4u localChunk = chunkPos & 0x3; @@ -129,7 +133,7 @@ void RemoteClient::murky_prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::Globa for(const DefVoxelId& id : lostTypes) { auto iter = ResUses.RefDefVoxel.find(id); assert(iter != ResUses.RefDefVoxel.end()); // Должны быть описаны зависимости вокселя - decrementBinary(std::move(iter->second)); + decrementAssets(std::move(iter->second)); ResUses.RefDefVoxel.erase(iter); checkPacketBorder(16); @@ -139,14 +143,14 @@ void RemoteClient::murky_prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::Globa } } - murkyCheckPacketBorder(4+4+8+2+4+compressed_voxels.size()); - MurkyNextPacket << (uint8_t) ToClient::L1::Content + checkPacketBorder(4+4+8+2+4+compressed_voxels.size()); + NextPacket << (uint8_t) ToClient::L1::Content << (uint8_t) ToClient::L2Content::ChunkVoxels << worldId << chunkPos.pack() << uint32_t(compressed_voxels.size()); - MurkyNextPacket.write((const std::byte*) compressed_voxels.data(), compressed_voxels.size()); + NextPacket.write((const std::byte*) compressed_voxels.data(), compressed_voxels.size()); } -void RemoteClient::maybe_prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::u8string& compressed_nodes, +void RemoteClient::NetworkAndResource_t::prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::u8string& compressed_nodes, const std::vector& uniq_sorted_defines) { Pos::bvec4u localChunk = chunkPos & 0x3; @@ -205,29 +209,31 @@ void RemoteClient::maybe_prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::Global for(const DefNodeId& id : lostTypes) { auto iter = ResUses.RefDefNode.find(id); assert(iter != ResUses.RefDefNode.end()); // Должны быть описаны зависимости ноды - decrementBinary(std::move(iter->second)); + decrementAssets(std::move(iter->second)); ResUses.RefDefNode.erase(iter); checkPacketBorder(16); - MurkyNextPacket << (uint8_t) ToClient::L1::Definition + NextPacket << (uint8_t) ToClient::L1::Definition << (uint8_t) ToClient::L2Definition::FreeNode << id; } } checkPacketBorder(4+4+8+4+compressed_nodes.size()); - MurkyNextPacket << (uint8_t) ToClient::L1::Content + NextPacket << (uint8_t) ToClient::L1::Content << (uint8_t) ToClient::L2Content::ChunkNodes << worldId << chunkPos.pack() << uint32_t(compressed_nodes.size()); - MurkyNextPacket.write((const std::byte*) compressed_nodes.data(), compressed_nodes.size()); + NextPacket.write((const std::byte*) compressed_nodes.data(), compressed_nodes.size()); } -void RemoteClient::prepareRegionRemove(WorldId_t worldId, Pos::GlobalRegion regionPos) { +void RemoteClient::NetworkAndResource_t::prepareRegionsRemove(WorldId_t worldId, std::vector regionPoses) +{ std::vector lostTypesV /* Потерянные типы вокселей */; std::vector lostTypesN /* Потерянные типы нод */; + for(Pos::GlobalRegion regionPos : regionPoses) // Уменьшаем зависимости вокселей и нод { auto iterWorld = ResUses.RefChunk.find(worldId); @@ -267,7 +273,7 @@ void RemoteClient::prepareRegionRemove(WorldId_t worldId, Pos::GlobalRegion regi for(const DefVoxelId& id : lostTypesV) { auto iter = ResUses.RefDefVoxel.find(id); assert(iter != ResUses.RefDefVoxel.end()); // Должны быть описаны зависимости вокселя - decrementBinary(std::move(iter->second)); + decrementAssets(std::move(iter->second)); ResUses.RefDefVoxel.erase(iter); checkPacketBorder(16); @@ -281,7 +287,7 @@ void RemoteClient::prepareRegionRemove(WorldId_t worldId, Pos::GlobalRegion regi for(const DefNodeId& id : lostTypesN) { auto iter = ResUses.RefDefNode.find(id); assert(iter != ResUses.RefDefNode.end()); // Должны быть описаны зависимости ноды - decrementBinary(std::move(iter->second)); + decrementAssets(std::move(iter->second)); ResUses.RefDefNode.erase(iter); checkPacketBorder(16); @@ -291,100 +297,107 @@ void RemoteClient::prepareRegionRemove(WorldId_t worldId, Pos::GlobalRegion regi } } - checkPacketBorder(16); - NextPacket << (uint8_t) ToClient::L1::Content - << (uint8_t) ToClient::L2Content::RemoveRegion - << worldId << regionPos.pack(); + + for(Pos::GlobalRegion regionPos : regionPoses) { + checkPacketBorder(16); + NextPacket << (uint8_t) ToClient::L1::Content + << (uint8_t) ToClient::L2Content::RemoveRegion + << worldId << regionPos.pack(); + } } -void RemoteClient::prepareEntityUpdate(ServerEntityId_t entityId, const Entity *entity) +void RemoteClient::NetworkAndResource_t::prepareEntitiesUpdate(const std::vector>& entities) { - // Сопоставим с идентификатором клиента - ClientEntityId_t ceId = ResRemap.Entityes.toClient(entityId); + for(auto& [entityId, entity] : entities) { + // Сопоставим с идентификатором клиента + ClientEntityId_t ceId = ReMapEntities.toClient(entityId); - // Профиль новый - { - 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++; + // Профиль новый + { + DefEntityId 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++; + } + + // Добавление модификационных зависимостей + // 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); + decrementAssets(std::move(iterProfileRef->second)); + ResUses.DefEntity.erase(iterProfile); + } + + // Убавляем зависимость к модификационным данным + // iterEntity->second. + // decrementBinary({}, {}, {}, {}, {}); + } + } + + // TODO: отправить клиенту } +} - // Добавление модификационных зависимостей - // incrementBinary({}, {}, {}, {}, {}); +void RemoteClient::NetworkAndResource_t::prepareEntitySwap(ServerEntityId_t prev, ServerEntityId_t next) +{ + ReMapEntities.rebindClientKey(prev, next); +} - // Старые данные - { - auto iterEntity = ResUses.RefEntity.find(entityId); - if(iterEntity != ResUses.RefEntity.end()) { - // Убавляем зависимость к старому профилю +void RemoteClient::NetworkAndResource_t::prepareEntitiesRemove(const std::vector& entityIds) +{ + for(ServerEntityId_t entityId : entityIds) { + ClientEntityId_t cId = ReMapEntities.erase(entityId); + + // Убавляем старые данные + { + auto iterEntity = ResUses.RefEntity.find(entityId); + assert(iterEntity != ResUses.RefEntity.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()); // Старый профиль должен быть + assert(iterProfile != ResUses.DefEntity.end()); // Профиль должен быть if(--iterProfile->second == 0) { - // Старый профиль больше не нужен + // Профиль больше не используется auto iterProfileRef = ResUses.RefDefEntity.find(iterEntity->second.Profile); - decrementBinary(std::move(iterProfileRef->second)); + + decrementAssets(std::move(iterProfileRef->second)); + + ResUses.RefDefEntity.erase(iterProfileRef); ResUses.DefEntity.erase(iterProfile); } - - // Убавляем зависимость к модификационным данным - // iterEntity->second. - // decrementBinary({}, {}, {}, {}, {}); } + + checkPacketBorder(16); + NextPacket << (uint8_t) ToClient::L1::Content + << (uint8_t) ToClient::L2Content::RemoveEntity + << cId; } - - // TODO: отправить клиенту } -void RemoteClient::prepareEntitySwap(ServerEntityId_t prev, ServerEntityId_t next) -{ - ResRemap.Entityes.rebindClientKey(prev, next); -} - -void RemoteClient::prepareEntityRemove(ServerEntityId_t entityId) -{ - ClientEntityId_t cId = ResRemap.Entityes.erase(entityId); - - // Убавляем старые данные - { - auto iterEntity = ResUses.RefEntity.find(entityId); - assert(iterEntity != ResUses.RefEntity.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); - - decrementBinary(std::move(iterProfileRef->second)); - - ResUses.RefDefEntity.erase(iterProfileRef); - ResUses.DefEntity.erase(iterProfile); - } - } - - checkPacketBorder(16); - NextPacket << (uint8_t) ToClient::L1::Content - << (uint8_t) ToClient::L2Content::RemoveEntity - << cId; -} - -void RemoteClient::prepareWorldUpdate(WorldId_t worldId, World* world) +void RemoteClient::NetworkAndResource_t::prepareWorldUpdate(WorldId_t worldId, World* world) { // Добавление зависимостей ResUses.RefChunk[worldId]; // Профиль { - DefWorldId_t defWorld = world->getDefId(); + DefWorldId defWorld = world->getDefId(); auto iterWorldProf = ResUses.DefWorld.find(defWorld); if(iterWorldProf == ResUses.DefWorld.end()) { // Профиль мира неизвестен клиенту @@ -412,7 +425,7 @@ void RemoteClient::prepareWorldUpdate(WorldId_t worldId, World* world) ResUses.DefWorld.erase(iterWorldProf); auto iterWorldProfRef = ResUses.RefDefWorld.find(iterWorld->second.Profile); assert(iterWorldProfRef != ResUses.RefDefWorld.end()); // Зависимости предыдущего профиля также должны быть - decrementBinary(std::move(iterWorldProfRef->second)); + decrementAssets(std::move(iterWorldProfRef->second)); ResUses.RefDefWorld.erase(iterWorldProfRef); } } @@ -424,7 +437,7 @@ void RemoteClient::prepareWorldUpdate(WorldId_t worldId, World* world) // TODO: отправить мир } -void RemoteClient::prepareWorldRemove(WorldId_t worldId) +void RemoteClient::NetworkAndResource_t::prepareWorldRemove(WorldId_t worldId) { // Чанки уже удалены prepareChunkRemove // Обновление зависимостей @@ -442,7 +455,7 @@ void RemoteClient::prepareWorldRemove(WorldId_t worldId) // Убавляем зависимости профиля auto iterWorldProfDef = ResUses.RefDefWorld.find(iterWorld->second.Profile); assert(iterWorldProfDef != ResUses.RefDefWorld.end()); // Зависимости профиля должны быть - decrementBinary(std::move(iterWorldProfDef->second)); + decrementAssets(std::move(iterWorldProfDef->second)); ResUses.RefDefWorld.erase(iterWorldProfDef); } @@ -453,80 +466,67 @@ void RemoteClient::prepareWorldRemove(WorldId_t worldId) ResUses.RefChunk.erase(iter); } -void RemoteClient::preparePortalUpdate(PortalId_t portalId, void* portal) {} -void RemoteClient::preparePortalRemove(PortalId_t portalId) {} +// void RemoteClient::NetworkAndResource_t::preparePortalUpdate(PortalId portalId, void* portal) {} +// void RemoteClient::NetworkAndResource_t::preparePortalRemove(PortalId portalId) {} void RemoteClient::prepareCameraSetEntity(ServerEntityId_t entityId) { } ResourceRequest RemoteClient::pushPreparedPackets() { - if(NextPacket.size()) - SimplePackets.push_back(std::move(NextPacket)); + std::vector toSend; + ResourceRequest nextRequest; - Socket.pushPackets(&SimplePackets); - SimplePackets.clear(); + { + auto lock = NetworkAndResource.lock(); - NextRequest.uniq(); + if(lock->NextPacket.size()) + lock->SimplePackets.push_back(std::move(lock->NextPacket)); - return std::move(NextRequest); -} - -void RemoteClient::informateBinary(const std::vector>& resources) { - for(auto& resource : resources) { - auto &hash = resource->Hash; - - auto iter = std::find(NeedToSend.begin(), NeedToSend.end(), hash); - if(iter == NeedToSend.end()) - continue; // Клиенту не требуется этот ресурс - - { - auto it = std::lower_bound(ClientBinaryCache.begin(), ClientBinaryCache.end(), hash); - - if(it == ClientBinaryCache.end() || *it != hash) - ClientBinaryCache.insert(it, hash); - } - - // Полная отправка ресурса - checkPacketBorder(2+4+32+4); - NextPacket << (uint8_t) ToClient::L1::Resource // Принудительная полная отправка - << (uint8_t) ToClient::L2Resource::InitResSend - << uint32_t(resource->Data.size()); - NextPacket.write((const std::byte*) hash.data(), hash.size()); - - NextPacket << uint32_t(resource->Data.size()); - - size_t pos = 0; - while(pos < resource->Data.size()) { - checkPacketBorder(0); - size_t need = std::min(resource->Data.size()-pos, std::min(NextPacket.size(), 64000)); - NextPacket.write((const std::byte*) resource->Data.data()+pos, need); - pos += need; - } - + toSend = std::move(lock->SimplePackets); + nextRequest = std::move(lock->NextRequest); } + + Socket.pushPackets(&toSend); + toSend.clear(); + + nextRequest.uniq(); + + return std::move(nextRequest); } -void RemoteClient::informateIdToHash(const std::unordered_map* resourcesLink) { - std::vector> newForClient; +void RemoteClient::informateAssets(const std::vector>& resources) +{ + std::vector> newForClient; - for(int type = 0; type < (int) EnumBinResource::MAX_ENUM; type++) { - for(auto& [id, hash] : resourcesLink[type]) { + for(auto& [type, resId, domain, key, resource] : resources) { + auto hash = resource.hash(); + + // Проверка запрашиваемых клиентом ресурсов + { + auto iter = std::find(AssetsInWork.ClientRequested.begin(), AssetsInWork.ClientRequested.end(), hash); + if(iter != AssetsInWork.ClientRequested.end()) + { + auto it = std::lower_bound(AssetsInWork.OnClient.begin(), AssetsInWork.OnClient.end(), hash); + + if(it == AssetsInWork.OnClient.end() || *it != hash) + AssetsInWork.OnClient.insert(it, hash); + + AssetsInWork.ToSend.emplace_back(type, domain, key, resId, resource, 0); + } + } + + auto lock = NetworkAndResource.lock(); + // Информирование клиента о привязках ресурсов к идентификатору + { // Посмотрим что известно клиенту - auto iter = ResUses.BinUse[uint8_t(type)].find(id); - if(iter != ResUses.BinUse[uint8_t(type)].end()) { - if(std::get<1>(iter->second) != hash) { - // Требуется перепривязать идентификатор к новому хешу - newForClient.push_back({(EnumBinResource) type, id, hash}); - std::get<1>(iter->second) = hash; - // Проверить есть ли хеш на стороне клиента - if(!std::binary_search(ClientBinaryCache.begin(), ClientBinaryCache.end(), hash)) { - NeedToSend.push_back(hash); - NextRequest.Hashes.push_back(hash); - } - } - } else { - // Ресурс не отслеживается клиентом + if(auto iter = lock->ResUses.AssetsUse[(int) type].find(resId); + iter != lock->ResUses.AssetsUse[(int) type].end() + && std::get(iter->second) != hash + ) { + // Требуется перепривязать идентификатор к новому хешу + newForClient.push_back({(EnumAssets) type, resId, domain, key, hash}); + std::get(iter->second) = hash; } } } @@ -534,19 +534,21 @@ void RemoteClient::informateIdToHash(const std::unordered_mapcheckPacketBorder(2+4+newForClient.size()*(1+4+32)); + lock->NextPacket << (uint8_t) ToClient::L1::Resource // Оповещение << ((uint8_t) ToClient::L2Resource::Bind) << uint32_t(newForClient.size()); - for(auto& [type, id, hash] : newForClient) { - NextPacket << uint8_t(type) << uint32_t(id); - NextPacket.write((const std::byte*) hash.data(), hash.size()); + for(auto& [type, resId, domain, key, hash] : newForClient) { + // TODO: может внести ограничение на длину домена и ключа? + lock->NextPacket << uint8_t(type) << uint32_t(resId) << domain << key; + lock->NextPacket.write((const std::byte*) hash.data(), hash.size()); } } } -void RemoteClient::informateDefVoxel(const std::unordered_map &voxels) +void RemoteClient::NetworkAndResource_t::informateDefVoxel(const std::vector>& voxels) { for(auto pair : voxels) { DefVoxelId id = pair.first; @@ -559,110 +561,104 @@ void RemoteClient::informateDefVoxel(const std::unordered_map &nodes) +void RemoteClient::NetworkAndResource_t::informateDefNode(const std::vector>& nodes) { - for(auto& [id, def] : nodes) { - if(!ResUses.DefNode.contains(id)) - continue; + // for(auto& [id, def] : nodes) { + // if(!ResUses.DefNode.contains(id)) + // continue; - size_t reserve = 0; - for(int iter = 0; iter < 6; iter++) - reserve += def->Texs[iter].Pipeline.size(); + // size_t reserve = 0; + // for(int iter = 0; iter < 6; iter++) + // reserve += def->Texs[iter].Pipeline.size(); - checkPacketBorder(1+1+4+1+2*6+reserve); - NextPacket << (uint8_t) ToClient::L1::Definition - << (uint8_t) ToClient::L2Definition::Node - << id << (uint8_t) def->DrawType; + // checkPacketBorder(1+1+4+1+2*6+reserve); + // NextPacket << (uint8_t) ToClient::L1::Definition + // << (uint8_t) ToClient::L2Definition::Node + // << id << (uint8_t) def->DrawType; - for(int iter = 0; iter < 6; iter++) { - NextPacket << (uint16_t) def->Texs[iter].Pipeline.size(); - NextPacket.write((const std::byte*) def->Texs[iter].Pipeline.data(), def->Texs[iter].Pipeline.size()); - } + // for(int iter = 0; iter < 6; iter++) { + // NextPacket << (uint16_t) def->Texs[iter].Pipeline.size(); + // NextPacket.write((const std::byte*) def->Texs[iter].Pipeline.data(), def->Texs[iter].Pipeline.size()); + // } - ResUsesObj::RefDefBin_t refs; - { - auto &array = refs.Resources[(uint8_t) EnumBinResource::Texture]; - for(int iter = 0; iter < 6; iter++) { - array.insert(array.end(), def->Texs[iter].BinTextures.begin(), def->Texs[iter].BinTextures.end()); - } + // ResUsesObj::RefDefBin_t refs; + // { + // auto &array = refs.Resources[(uint8_t) EnumBinResource::Texture]; + // for(int iter = 0; iter < 6; iter++) { + // array.insert(array.end(), def->Texs[iter].BinTextures.begin(), def->Texs[iter].BinTextures.end()); + // } - std::sort(array.begin(), array.end()); - auto eraseLast = std::unique(array.begin(), array.end()); - array.erase(eraseLast, array.end()); + // std::sort(array.begin(), array.end()); + // auto eraseLast = std::unique(array.begin(), array.end()); + // array.erase(eraseLast, array.end()); - incrementBinary(refs); - } + // incrementBinary(refs); + // } - { - auto iterDefRef = ResUses.RefDefNode.find(id); - if(iterDefRef != ResUses.RefDefNode.end()) { - decrementBinary(std::move(iterDefRef->second)); - iterDefRef->second = std::move(refs); - } else { - ResUses.RefDefNode[id] = std::move(refs); - } - } + // { + // auto iterDefRef = ResUses.RefDefNode.find(id); + // if(iterDefRef != ResUses.RefDefNode.end()) { + // decrementBinary(std::move(iterDefRef->second)); + // iterDefRef->second = std::move(refs); + // } else { + // ResUses.RefDefNode[id] = std::move(refs); + // } + // } - } + // } } -void RemoteClient::informateDefWorld(const std::unordered_map &worlds) +void RemoteClient::NetworkAndResource_t::informateDefWorld(const std::vector>& worlds) { - for(auto pair : worlds) { - DefWorldId_t id = pair.first; - if(!ResUses.DefWorld.contains(id)) - continue; + // for(auto pair : worlds) { + // DefWorldId_t id = pair.first; + // if(!ResUses.DefWorld.contains(id)) + // continue; - NextPacket << (uint8_t) ToClient::L1::Definition - << (uint8_t) ToClient::L2Definition::World - << id; - } + // NextPacket << (uint8_t) ToClient::L1::Definition + // << (uint8_t) ToClient::L2Definition::World + // << id; + // } } -void RemoteClient::informateDefPortal(const std::unordered_map &portals) +void RemoteClient::NetworkAndResource_t::informateDefPortal(const std::vector>& portals) { - for(auto pair : portals) { - DefPortalId_t id = pair.first; - if(!ResUses.DefPortal.contains(id)) - continue; + // for(auto pair : portals) { + // DefPortalId_t id = pair.first; + // if(!ResUses.DefPortal.contains(id)) + // continue; - NextPacket << (uint8_t) ToClient::L1::Definition - << (uint8_t) ToClient::L2Definition::Portal - << id; - } + // NextPacket << (uint8_t) ToClient::L1::Definition + // << (uint8_t) ToClient::L2Definition::Portal + // << id; + // } } -void RemoteClient::informateDefEntity(const std::unordered_map &entityes) +void RemoteClient::NetworkAndResource_t::informateDefEntity(const std::vector>& entityes) { - for(auto pair : entityes) { - DefEntityId_t id = pair.first; - if(!ResUses.DefEntity.contains(id)) - continue; + // 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; - } + // NextPacket << (uint8_t) ToClient::L1::Definition + // << (uint8_t) ToClient::L2Definition::Entity + // << id; + // } } -void RemoteClient::informateDefItem(const std::unordered_map &items) +void RemoteClient::NetworkAndResource_t::informateDefItem(const std::vector>& items) { - for(auto pair : items) { - DefItemId_t id = pair.first; - if(!ResUses.DefNode.contains(id)) - continue; + // 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; - } -} - -void RemoteClient::checkPacketBorder(uint16_t size) { - if(64000-NextPacket.size() < size || (NextPacket.size() != 0 && size == 0)) { - SimplePackets.push_back(std::move(NextPacket)); - } + // NextPacket << (uint8_t) ToClient::L1::Definition + // << (uint8_t) ToClient::L2Definition::FuncEntity + // << id; + // } } void RemoteClient::protocolError() { @@ -725,31 +721,31 @@ coro<> RemoteClient::rP_System(Net::AsyncSocket &sock) { } } -void RemoteClient::incrementBinary(const ResUsesObj::RefDefBin_t& bin) { +void RemoteClient::NetworkAndResource_t::incrementAssets(const ResUses_t::RefAssets_t& bin) { for(int iter = 0; iter < 5; iter++) { - auto &use = ResUses.BinUse[iter]; + auto &use = ResUses.AssetsUse[iter]; - for(ResourceId_t id : bin.Resources[iter]) { + for(ResourceId id : bin.Resources[iter]) { if(++std::get<0>(use[id]) == 1) { - NextRequest.BinToHash[iter].push_back(id); - LOG.debug() << "Новое определение (тип " << iter << ") -> " << id; + NextRequest.AssetsInfo[iter].push_back(id); + // LOG.debug() << "Новое определение (тип " << iter << ") -> " << id; } } } } -void RemoteClient::decrementBinary(ResUsesObj::RefDefBin_t&& bin) { - std::vector> lost; +void RemoteClient::NetworkAndResource_t::decrementAssets(ResUses_t::RefAssets_t&& bin) { + std::vector> lost; - for(int iter = 0; iter < 5; iter++) { - auto &use = ResUses.BinUse[iter]; + for(int iter = 0; iter < (int) EnumAssets::MAX_ENUM; iter++) { + auto &use = ResUses.AssetsUse[iter]; - for(ResourceId_t id : bin.Resources[iter]) { + for(ResourceId id : bin.Resources[iter]) { if(--std::get<0>(use[id]) == 0) { use.erase(use.find(id)); - lost.push_back({(EnumBinResource) iter, id}); - LOG.debug() << "Потеряно определение (тип " << iter << ") -> " << id; + lost.push_back({(EnumAssets) iter, id}); + // LOG.debug() << "Потеряно определение (тип " << iter << ") -> " << id; } } } @@ -767,4 +763,12 @@ void RemoteClient::decrementBinary(ResUsesObj::RefDefBin_t&& bin) { } } +void RemoteClient::onUpdate() { + +} + +std::vector> RemoteClient::getViewPoints() { + return {{0, CameraPos, 2}}; +} + } \ No newline at end of file diff --git a/Src/Server/RemoteClient.hpp b/Src/Server/RemoteClient.hpp index 026de0b..2a0d3a5 100644 --- a/Src/Server/RemoteClient.hpp +++ b/Src/Server/RemoteClient.hpp @@ -210,7 +210,8 @@ class RemoteClient { struct NetworkAndResource_t { struct ResUses_t { // Счётчики использования двоичных кэшируемых ресурсов + хэш привязанный к идентификатору - std::map AssetsUse[(int) EnumAssets::MAX_ENUM]; + // Хэш используется для того, чтобы исключить повторные объявления неизменившихся ресурсов + std::map> AssetsUse[(int) EnumAssets::MAX_ENUM]; // Зависимость профилей контента от профилей ресурсов // Нужно чтобы пересчитать зависимости к профилям ресурсов @@ -260,9 +261,6 @@ class RemoteClient { RefAssets_t Assets; }; std::map RefEntity; - - void incrementBinary(const RefAssets_t& bin); - void decrementBinary(RefAssets_t&& bin); } ResUses; // Смена идентификаторов сервера на клиентские @@ -271,8 +269,34 @@ class RemoteClient { // Запрос информации об ассетах и профилях контента ResourceRequest NextRequest; + void incrementAssets(const ResUses_t::RefAssets_t& bin); + void decrementAssets(ResUses_t::RefAssets_t&& bin); + Net::Packet NextPacket; std::vector SimplePackets; + void checkPacketBorder(uint16_t size) { + if(64000-NextPacket.size() < size || (NextPacket.size() != 0 && size == 0)) { + SimplePackets.push_back(std::move(NextPacket)); + } + } + + void prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::u8string& compressed_voxels, + const std::vector& uniq_sorted_defines); + void prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::u8string& compressed_nodes, + const std::vector& uniq_sorted_defines); + void prepareEntitiesRemove(const std::vector& entityId); + void prepareRegionsRemove(WorldId_t worldId, std::vector regionPoses); + void prepareWorldRemove(WorldId_t worldId); + void prepareEntitiesUpdate(const std::vector>& entities); + void prepareEntitiesUpdate_Dynamic(const std::vector>& entities); + void prepareEntitySwap(ServerEntityId_t prevEntityId, ServerEntityId_t nextEntityId); + void prepareWorldUpdate(WorldId_t worldId, World* world); + void informateDefVoxel(const std::vector>& voxels); + void informateDefNode(const std::vector>& nodes); + void informateDefWorld(const std::vector>& worlds); + void informateDefPortal(const std::vector>& portals); + void informateDefEntity(const std::vector>& entityes); + void informateDefItem(const std::vector>& items); }; struct { @@ -284,9 +308,11 @@ class RemoteClient { */ // Ресурсы, отправленные на клиент в этой сессии и запрошенные клиентом + /// TODO: ClientRequested здесь может быть засор std::vector OnClient, ClientRequested; - // Отправляемые на клиент ресурсы (в конце текущее смещение по отправке) - std::vector> ToSend; + // Отправляемые на клиент ресурсы + // Тип, домен, ключ, идентификатор, ресурс, количество отправленных байт + std::vector> ToSend; } AssetsInWork; TOS::SpinlockObject NetworkAndResource; @@ -335,26 +361,43 @@ public: // В зоне видимости добавился чанк или изменились его воксели bool maybe_prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::u8string& compressed_voxels, - const std::vector& uniq_sorted_defines); + const std::vector& uniq_sorted_defines) + { + auto lock = NetworkAndResource.tryLock(); + if(!lock) + return false; + + lock->prepareChunkUpdate_Voxels(worldId, chunkPos, compressed_voxels, uniq_sorted_defines); + return true; + } + // В зоне видимости добавился чанк или изменились его ноды bool maybe_prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::u8string& compressed_nodes, - const std::vector& uniq_sorted_defines); + const std::vector& uniq_sorted_defines) + { + auto lock = NetworkAndResource.tryLock(); + if(!lock) + return false; + + lock->prepareChunkUpdate_Nodes(worldId, chunkPos, compressed_nodes, uniq_sorted_defines); + return true; + } // void prepareChunkUpdate_LightPrism(WorldId_t worldId, Pos::GlobalChunk chunkPos, const LightPrism *lights); // Клиент перестал наблюдать за сущностью - void prepareEntitiesRemove(const std::vector& entityId); + void prepareEntitiesRemove(const std::vector& entityId) { NetworkAndResource.lock()->prepareEntitiesRemove(entityId); } // Регион удалён из зоны видимости - void prepareRegionRemove(WorldId_t worldId, std::vector regionPoses); + void prepareRegionsRemove(WorldId_t worldId, std::vector regionPoses) { NetworkAndResource.lock()->prepareRegionsRemove(worldId, regionPoses); } // Мир удалён из зоны видимости - void prepareWorldRemove(WorldId_t worldId); + void prepareWorldRemove(WorldId_t worldId) { NetworkAndResource.lock()->prepareWorldRemove(worldId); } // В зоне видимости добавилась новая сущность или она изменилась - void prepareEntityUpdate(const std::vector>& entities); - void prepareEntityUpdate_Dynamic(const std::vector>& entities); + void prepareEntitiesUpdate(const std::vector>& entities) { NetworkAndResource.lock()->prepareEntitiesUpdate(entities); } + void prepareEntitiesUpdate_Dynamic(const std::vector>& entities) { NetworkAndResource.lock()->prepareEntitiesUpdate_Dynamic(entities); } // Наблюдаемая сущность пересекла границы региона, у неё изменился серверный идентификатор - void prepareEntitySwap(ServerEntityId_t prevEntityId, ServerEntityId_t nextEntityId); + void prepareEntitySwap(ServerEntityId_t prevEntityId, ServerEntityId_t nextEntityId) { NetworkAndResource.lock()->prepareEntitySwap(prevEntityId, nextEntityId); } // Мир появился в зоне видимости или изменился - void prepareWorldUpdate(WorldId_t worldId, World* world); + void prepareWorldUpdate(WorldId_t worldId, World* world) { NetworkAndResource.lock()->prepareWorldUpdate(worldId, world); } // В зоне видимости добавился порта или он изменился // void preparePortalUpdate(PortalId_t portalId, void* portal); @@ -375,15 +418,16 @@ public: void informateAssets(const std::vector>& resources); // Игровые определения - void informateDefVoxel(const std::unordered_map &voxels); - void informateDefNode(const std::unordered_map &nodes); - void informateDefWorld(const std::unordered_map &worlds); - void informateDefPortal(const std::unordered_map &portals); - void informateDefEntity(const std::unordered_map &entityes); - void informateDefItem(const std::unordered_map &items); + void informateDefVoxel(const std::vector>& voxels) { NetworkAndResource.lock()->informateDefVoxel(voxels); } + void informateDefNode(const std::vector>& nodes) { NetworkAndResource.lock()->informateDefNode(nodes); } + void informateDefWorld(const std::vector>& worlds) { NetworkAndResource.lock()->informateDefWorld(worlds); } + void informateDefPortal(const std::vector>& portals) { NetworkAndResource.lock()->informateDefPortal(portals); } + void informateDefEntity(const std::vector>& entityes) { NetworkAndResource.lock()->informateDefEntity(entityes); } + void informateDefItem(const std::vector>& items) { NetworkAndResource.lock()->informateDefItem(items); } + + void onUpdate(); private: - void checkPacketBorder(uint16_t size); void protocolError(); coro<> readPacket(Net::AsyncSocket &sock); coro<> rP_System(Net::AsyncSocket &sock); diff --git a/Src/Server/SaveBackend.hpp b/Src/Server/SaveBackend.hpp index 7282cac..114eeb2 100644 --- a/Src/Server/SaveBackend.hpp +++ b/Src/Server/SaveBackend.hpp @@ -18,15 +18,15 @@ struct SB_Region_In { // Список вокселей всех чанков std::unordered_map Voxels; // Привязка вокселей к ключу профиля - std::vector> VoxelsMap; + std::vector> VoxelsMap; // Ноды всех чанков std::array, 4*4*4> Nodes; // Привязка нод к ключу профиля - std::vector> NodeMap; + std::vector> NodeMap; // Сущности std::vector Entityes; // Привязка идентификатора к ключу профиля - std::vector> EntityMap; + std::vector> EntityMap; }; struct DB_Region_Out { diff --git a/Src/Server/World.cpp b/Src/Server/World.cpp index c674bd9..fe09ee7 100644 --- a/Src/Server/World.cpp +++ b/Src/Server/World.cpp @@ -6,7 +6,7 @@ namespace LV::Server { -World::World(DefWorldId_t defId) +World::World(DefWorldId defId) : DefId(defId) { @@ -16,7 +16,7 @@ World::~World() { } -std::vector World::onCEC_RegionsEnter(std::shared_ptr cec, const std::vector& enter) { +std::vector World::onRemoteClient_RegionsEnter(std::shared_ptr cec, const std::vector& enter) { std::vector out; for(const Pos::GlobalRegion &pos : enter) { @@ -27,8 +27,8 @@ std::vector World::onCEC_RegionsEnter(std::shared_ptrsecond; - region.CECs.push_back(cec); - region.NewCECs.push_back(cec); + region.RMs.push_back(cec); + region.NewRMs.push_back(cec); // Отправить клиенту информацию о чанках и сущностях std::unordered_map*> voxels; std::unordered_map nodes; @@ -49,13 +49,13 @@ std::vector World::onCEC_RegionsEnter(std::shared_ptr cec, const std::vector &lost) { +void World::onRemoteClient_RegionsLost(std::shared_ptr cec, const std::vector &lost) { for(const Pos::GlobalRegion &pos : lost) { auto region = Regions.find(pos); if(region == Regions.end()) continue; - std::vector> &CECs = region->second->CECs; + std::vector> &CECs = region->second->RMs; for(size_t iter = 0; iter < CECs.size(); iter++) { if(CECs[iter] == cec) { CECs.erase(CECs.begin()+iter); diff --git a/Src/Server/World.hpp b/Src/Server/World.hpp index 04ea712..26bb496 100644 --- a/Src/Server/World.hpp +++ b/Src/Server/World.hpp @@ -2,6 +2,7 @@ #include "Common/Abstract.hpp" #include "Server/Abstract.hpp" +#include "Server/RemoteClient.hpp" #include "Server/SaveBackend.hpp" #include #include @@ -24,10 +25,7 @@ public: std::array, 4*4*4> Nodes; std::vector Entityes; - std::vector> CECs, NewCECs; - // Используется для прорежения количества проверок на наблюдаемые чанки и сущности - // В одно обновление региона - проверка одного наблюдателя - uint16_t CEC_NextChunkAndEntityesViewCheck = 0; + std::vector> RMs, NewRMs; float LastSaveTime = 0; @@ -134,13 +132,13 @@ public: }; class World { - DefWorldId_t DefId; + DefWorldId DefId; public: std::unordered_map> Regions; public: - World(DefWorldId_t defId); + World(DefWorldId defId); ~World(); /* @@ -148,8 +146,8 @@ public: Возвращает список не загруженных регионов, на которые соответственно игрока не получилось подписать При подписи происходит отправка всех чанков и сущностей региона */ - std::vector onCEC_RegionsEnter(std::shared_ptr cec, const std::vector &enter); - void onCEC_RegionsLost(std::shared_ptr cec, const std::vector& lost); + std::vector onRemoteClient_RegionsEnter(std::shared_ptr cec, const std::vector &enter); + void onRemoteClient_RegionsLost(std::shared_ptr cec, const std::vector& lost); struct SaveUnloadInfo { std::vector ToUnload; std::vector> ToSave; @@ -173,7 +171,7 @@ public: */ - DefWorldId_t getDefId() const { return DefId; } + DefWorldId getDefId() const { return DefId; } }; diff --git a/Src/TOSLib.hpp b/Src/TOSLib.hpp index b4828e0..e0c2b97 100644 --- a/Src/TOSLib.hpp +++ b/Src/TOSLib.hpp @@ -149,6 +149,10 @@ public: T* operator->() const { assert(Obj); return &Obj->Value; } T& operator*() const { assert(Obj); return Obj->Value; } + operator bool() const { + return Obj; + } + void unlock() { assert(Obj); Obj = nullptr; Flag->clear(std::memory_order_release);} private: