From 3fb06080dbab6c2b9b4ea206453a80934552840f Mon Sep 17 00:00:00 2001 From: DrSocalkwe3n Date: Sat, 17 Jan 2026 18:59:36 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=B8=D0=BD=D1=85=D1=80=D0=BE=D0=BD?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BF=D1=80=D0=BE=D1=84?= =?UTF-8?q?=D0=B8=D0=BB=D0=B5=D0=B9=20=D0=BA=D0=BE=D0=BD=D1=82=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Src/Client/Abstract.hpp | 94 +++-- Src/Client/AssetsManager.hpp | 16 +- Src/Client/ServerSession.cpp | 420 ++++++++++++++++++---- Src/Client/ServerSession.hpp | 13 +- Src/Client/Vulkan/VulkanRenderSession.cpp | 215 ++++------- Src/Client/Vulkan/VulkanRenderSession.hpp | 27 +- Src/Common/IdProvider.hpp | 6 +- Src/Common/Packets.hpp | 1 + Src/Server/AssetsManager.hpp | 24 +- Src/Server/ContentManager.cpp | 213 ++++++++++- Src/Server/ContentManager.hpp | 194 ++++++++-- Src/Server/GameServer.cpp | 7 +- Src/Server/RemoteClient.cpp | 231 +++++++++--- Src/Server/RemoteClient.hpp | 26 +- 14 files changed, 1120 insertions(+), 367 deletions(-) diff --git a/Src/Client/Abstract.hpp b/Src/Client/Abstract.hpp index d206aa5..29de0f7 100644 --- a/Src/Client/Abstract.hpp +++ b/Src/Client/Abstract.hpp @@ -1,9 +1,13 @@ #pragma once +#include "Common/Net.hpp" #include +#include #include +#include #include #include +#include #include #include @@ -149,14 +153,6 @@ struct WorldInfo { std::unordered_map Regions; }; -struct VoxelInfo { - -}; - -struct NodeInfo { - -}; - struct PortalInfo { }; @@ -168,19 +164,77 @@ struct EntityInfo { glm::quat Quat = glm::quat(1.f, 0.f, 0.f, 0.f); }; -struct FuncEntityInfo { +/* + Конструируются с серверными идентификаторами +*/ +struct DefVoxel { + DefVoxel() = default; + DefVoxel(const std::u8string_view view) { + + } + + void reBind(const std::function& am) { + + } }; -struct DefItemInfo { +struct DefNode { + std::variant RenderStates; + DefNode() = default; + DefNode(const std::u8string_view view) { + Net::LinearReader lr(view); + RenderStates = lr.read(); + } + + void reBind(const std::function& am) { + RenderStates = am(EnumAssets::Nodestate, std::get(RenderStates)); + } }; -struct DefVoxel_t {}; -struct DefNode_t { - AssetsNodestate NodestateId = 0; - AssetsTexture TexId = 0; +struct DefWorld { + DefWorld() = default; + DefWorld(const std::u8string_view view) { + + } + void reBind(const std::function& am) { + + } +}; + +struct DefPortal { + DefPortal() = default; + DefPortal(const std::u8string_view view) { + + } + + void reBind(const std::function& am) { + + } +}; + +struct DefEntity { + DefEntity() = default; + DefEntity(const std::u8string_view view) { + + } + + void reBind(const std::function& am) { + + } +}; + +struct DefItem { + DefItem() = default; + DefItem(const std::u8string_view view) { + + } + + void reBind(const std::function& am) { + + } }; struct AssetEntry { @@ -217,12 +271,12 @@ public: // Используемые профили контента 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 DefVoxels; + std::unordered_map DefNodes; + std::unordered_map DefWorlds; + std::unordered_map DefPortals; + std::unordered_map DefEntitys; + std::unordered_map DefItems; } Profiles; // Видимый контент diff --git a/Src/Client/AssetsManager.hpp b/Src/Client/AssetsManager.hpp index 91d5fc9..7c1b0c8 100644 --- a/Src/Client/AssetsManager.hpp +++ b/Src/Client/AssetsManager.hpp @@ -46,7 +46,11 @@ public: public: AssetsManager(asio::io_context& ioc, fs::path cachePath) - : Cache(AssetsCacheManager::Create(ioc, cachePath)) { + : Cache(AssetsCacheManager::Create(ioc, cachePath)) + { + for(size_t type = 0; type < static_cast(EnumAssets::MAX_ENUM); type++) { + ServerToClientMap[type].push_back(0); + } } // Ручные обновления @@ -179,9 +183,13 @@ public: ) { LOG.debug() << "BindDK domains=" << domains.size(); for(size_t type = 0; type < static_cast(EnumAssets::MAX_ENUM); ++type) { + LOG.info() << type; for(size_t forDomainIter = 0; forDomainIter < keys[type].size(); ++forDomainIter) { + LOG.info() << "\t" << domains[forDomainIter]; for(const std::string& key : keys[type][forDomainIter]) { - ServerToClientMap[type].push_back(getId((EnumAssets) type, domains[forDomainIter], key)); + uint32_t id = getId((EnumAssets) type, domains[forDomainIter], key); + LOG.info() << "\t\t" << key << " -> " << id; + ServerToClientMap[type].push_back(id); } } } @@ -299,6 +307,10 @@ public: return std::move(RU); } + ResourceId reBind(EnumAssets type, ResourceId server) { + return ServerToClientMap[static_cast(type)].at(server); + } + void tick() { // Проверим кеш std::vector>> resources = Cache->pullReads(); diff --git a/Src/Client/ServerSession.cpp b/Src/Client/ServerSession.cpp index f0ffe56..1d2df59 100644 --- a/Src/Client/ServerSession.cpp +++ b/Src/Client/ServerSession.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -65,12 +66,6 @@ ServerSession::ServerSession(asio::io_context &ioc, std::unique_ptr profile_Voxel_AddOrChange; + std::unordered_map profile_Voxel_AddOrChange; std::vector profile_Voxel_Lost; - std::unordered_map profile_Node_AddOrChange; + std::unordered_map profile_Node_AddOrChange; std::vector profile_Node_Lost; - std::unordered_map profile_World_AddOrChange; + std::unordered_map profile_World_AddOrChange; std::vector profile_World_Lost; - std::unordered_map profile_Portal_AddOrChange; + std::unordered_map profile_Portal_AddOrChange; std::vector profile_Portal_Lost; - std::unordered_map profile_Entity_AddOrChange; + std::unordered_map profile_Entity_AddOrChange; std::vector profile_Entity_Lost; - std::unordered_map profile_Item_AddOrChange; + std::unordered_map profile_Item_AddOrChange; std::vector profile_Item_Lost; + std::unordered_map entity_AddOrChange; std::vector entity_Lost; @@ -382,6 +378,12 @@ void ServerSession::update(GlobalTime gTime, float dTime) { if(iter != profile_Voxel_Lost.end() && *iter == id) profile_Voxel_Lost.erase(iter); + profile.reBind( + [&](EnumAssets type, ResourceId server) { + return AM.reBind(type, server); + } + ); + profile_Voxel_AddOrChange[id] = profile; } @@ -401,6 +403,12 @@ void ServerSession::update(GlobalTime gTime, float dTime) { if(iter != profile_Node_Lost.end() && *iter == id) profile_Node_Lost.erase(iter); + profile.reBind( + [&](EnumAssets type, ResourceId server) { + return AM.reBind(type, server); + } + ); + profile_Node_AddOrChange[id] = profile; } @@ -420,6 +428,12 @@ void ServerSession::update(GlobalTime gTime, float dTime) { if(iter != profile_World_Lost.end() && *iter == id) profile_World_Lost.erase(iter); + profile.reBind( + [&](EnumAssets type, ResourceId server) { + return AM.reBind(type, server); + } + ); + profile_World_AddOrChange[id] = profile; } @@ -439,6 +453,12 @@ void ServerSession::update(GlobalTime gTime, float dTime) { if(iter != profile_Portal_Lost.end() && *iter == id) profile_Portal_Lost.erase(iter); + profile.reBind( + [&](EnumAssets type, ResourceId server) { + return AM.reBind(type, server); + } + ); + profile_Portal_AddOrChange[id] = profile; } @@ -458,6 +478,12 @@ void ServerSession::update(GlobalTime gTime, float dTime) { if(iter != profile_Entity_Lost.end() && *iter == id) profile_Entity_Lost.erase(iter); + profile.reBind( + [&](EnumAssets type, ResourceId server) { + return AM.reBind(type, server); + } + ); + profile_Entity_AddOrChange[id] = profile; } @@ -477,6 +503,12 @@ void ServerSession::update(GlobalTime gTime, float dTime) { if(iter != profile_Item_Lost.end() && *iter == id) profile_Item_Lost.erase(iter); + profile.reBind( + [&](EnumAssets type, ResourceId server) { + return AM.reBind(type, server); + } + ); + profile_Item_AddOrChange[id] = profile; } @@ -491,10 +523,10 @@ void ServerSession::update(GlobalTime gTime, float dTime) { } { - for(auto& [id, info] : data.Entity_AddOrChange) { - auto iter = std::lower_bound(entity_Lost.begin(), entity_Lost.end(), id); - if(iter != entity_Lost.end() && *iter == id) - entity_Lost.erase(iter); + for(auto& [id, info] : data.Entity_AddOrChange) { + auto iter = std::lower_bound(entity_Lost.begin(), entity_Lost.end(), id); + if(iter != entity_Lost.end() && *iter == id) + entity_Lost.erase(iter); entity_AddOrChange[id] = info; } @@ -506,20 +538,20 @@ void ServerSession::update(GlobalTime gTime, float dTime) { entity_Lost.insert(entity_Lost.end(), data.Entity_Lost.begin(), data.Entity_Lost.end()); std::sort(entity_Lost.begin(), entity_Lost.end()); auto eraseIter = std::unique(entity_Lost.begin(), entity_Lost.end()); - entity_Lost.erase(eraseIter, entity_Lost.end()); + entity_Lost.erase(eraseIter, entity_Lost.end()); + } } - } - { - AssetsManager::ResourceUpdates updates = AM.pullResourceUpdates(); - result.AssetsNodestates = std::move(updates.Nodestates); - result.AssetsModels = std::move(updates.Models); - result.AssetsTextures = std::move(updates.Textures); - } + { + AssetsManager::ResourceUpdates updates = AM.pullResourceUpdates(); + result.AssetsNodestates = std::move(updates.Nodestates); + result.AssetsModels = std::move(updates.Models); + result.AssetsTextures = std::move(updates.Textures); + } - for(auto& [id, _] : profile_Voxel_AddOrChange) - result.Profiles_ChangeOrAdd[EnumDefContent::Voxel].push_back(id); - result.Profiles_Lost[EnumDefContent::Voxel] = profile_Voxel_Lost; + for(auto& [id, _] : profile_Voxel_AddOrChange) + result.Profiles_ChangeOrAdd[EnumDefContent::Voxel].push_back(id); + result.Profiles_Lost[EnumDefContent::Voxel] = profile_Voxel_Lost; for(auto& [id, _] : profile_Node_AddOrChange) result.Profiles_ChangeOrAdd[EnumDefContent::Node].push_back(id); @@ -657,7 +689,6 @@ void ServerSession::update(GlobalTime gTime, float dTime) { for(auto& [wId, regions] : regions_Lost_Result) result.Chunks_Lost[wId] = std::vector(regions.begin(), regions.end()); - { for(TickData& data : ticks) { } @@ -669,12 +700,23 @@ void ServerSession::update(GlobalTime gTime, float dTime) { // Применяем изменения по ресурсам, профилям и контенту // Определения { - for(auto& [resId, def] : profile_Node_AddOrChange) { - Profiles.DefNode[resId] = def; - } - for(auto& [resId, def] : profile_Entity_AddOrChange) { - Profiles.DefEntity[resId] = def; - } + for(auto& [resId, def] : profile_Voxel_AddOrChange) + Profiles.DefVoxels[resId] = def; + + for(auto& [resId, def] : profile_Node_AddOrChange) + Profiles.DefNodes[resId] = def; + + for(auto& [resId, def] : profile_World_AddOrChange) + Profiles.DefWorlds[resId] = def; + + for(auto& [resId, def] : profile_Portal_AddOrChange) + Profiles.DefPortals[resId] = def; + + for(auto& [resId, def] : profile_Entity_AddOrChange) + Profiles.DefEntitys[resId] = def; + + for(auto& [resId, def] : profile_Item_AddOrChange) + Profiles.DefItems[resId] = def; } // Чанки @@ -724,7 +766,6 @@ void ServerSession::update(GlobalTime gTime, float dTime) { regions[pos >> 2].Chunks[Pos::bvec4u(pos & 0x3).pack()].Nodes = std::move(data); } } - } // Сущности @@ -904,6 +945,9 @@ coro<> ServerSession::readPacket(Net::AsyncSocket &sock) { case ToClient::AssetsNextSend: co_await rP_AssetsNextSend(sock); co_return; + case ToClient::DefinitionsFull: + co_await rP_DefinitionsFull(sock); + co_return; case ToClient::DefinitionsUpdate: co_await rP_DefinitionsUpdate(sock); co_return; @@ -1035,55 +1079,281 @@ coro<> ServerSession::rP_AssetsNextSend(Net::AsyncSocket &sock) { AsyncContext.AssetsLoading.erase(AsyncContext.AssetsLoading.find(hash)); } +coro<> ServerSession::rP_DefinitionsFull(Net::AsyncSocket &sock) { + std::vector ids; + uint32_t size = 0; + + { + size = co_await sock.read(); + ids.clear(); + ids.reserve(size); + for(size_t iter = 0; iter < size; iter++) { + ids.push_back(co_await sock.read()); + } + + AsyncContext.ThisTickEntry.Profile_Voxel_AddOrChange.reserve(AsyncContext.ThisTickEntry.Profile_Voxel_AddOrChange.size()+size); + for(size_t iter = 0; iter < size; iter++) { + std::string data = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_Voxel_AddOrChange.emplace_back( + ids[iter], + DefVoxel{ + std::u8string_view((const char8_t*) data.data(), data.size()) + } + ); + } + } + + { + size = co_await sock.read(); + ids.clear(); + ids.reserve(size); + for(size_t iter = 0; iter < size; iter++) { + ids.push_back(co_await sock.read()); + } + + AsyncContext.ThisTickEntry.Profile_Node_AddOrChange.reserve(AsyncContext.ThisTickEntry.Profile_Node_AddOrChange.size()+size); + for(size_t iter = 0; iter < size; iter++) { + std::string data = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_Node_AddOrChange.emplace_back( + ids[iter], + DefNode{ + std::u8string_view((const char8_t*) data.data(), data.size()) + } + ); + } + } + + { + size = co_await sock.read(); + ids.clear(); + ids.reserve(size); + for(size_t iter = 0; iter < size; iter++) { + ids.push_back(co_await sock.read()); + } + + AsyncContext.ThisTickEntry.Profile_World_AddOrChange.reserve(AsyncContext.ThisTickEntry.Profile_World_AddOrChange.size()+size); + for(size_t iter = 0; iter < size; iter++) { + std::string data = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_World_AddOrChange.emplace_back( + ids[iter], + DefWorld{ + std::u8string_view((const char8_t*) data.data(), data.size()) + } + ); + } + } + + { + size = co_await sock.read(); + ids.clear(); + ids.reserve(size); + for(size_t iter = 0; iter < size; iter++) { + ids.push_back(co_await sock.read()); + } + + AsyncContext.ThisTickEntry.Profile_Portal_AddOrChange.reserve(AsyncContext.ThisTickEntry.Profile_Portal_AddOrChange.size()+size); + for(size_t iter = 0; iter < size; iter++) { + std::string data = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_Portal_AddOrChange.emplace_back( + ids[iter], + DefPortal{ + std::u8string_view((const char8_t*) data.data(), data.size()) + } + ); + } + } + + { + size = co_await sock.read(); + ids.clear(); + ids.reserve(size); + for(size_t iter = 0; iter < size; iter++) { + ids.push_back(co_await sock.read()); + } + + AsyncContext.ThisTickEntry.Profile_Entity_AddOrChange.reserve(AsyncContext.ThisTickEntry.Profile_Entity_AddOrChange.size()+size); + for(size_t iter = 0; iter < size; iter++) { + std::string data = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_Entity_AddOrChange.emplace_back( + ids[iter], + DefEntity{ + std::u8string_view((const char8_t*) data.data(), data.size()) + } + );} + } + + { + size = co_await sock.read(); + ids.clear(); + ids.reserve(size); + for(size_t iter = 0; iter < size; iter++) { + ids.push_back(co_await sock.read()); + } + + AsyncContext.ThisTickEntry.Profile_Item_AddOrChange.reserve(AsyncContext.ThisTickEntry.Profile_Item_AddOrChange.size()+size); + for(size_t iter = 0; iter < size; iter++) { + std::string data = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_Item_AddOrChange.emplace_back( + ids[iter], + DefItem{ + std::u8string_view((const char8_t*) data.data(), data.size()) + } + ); + } + } + + for(size_t type = 0; type < static_cast(EnumDefContent::MAX_ENUM); type++) { + size = co_await sock.read(); + + for(size_t iter = 0; iter < size; iter++) { + std::string domain = co_await sock.read(); + std::string key = co_await sock.read(); + + (void) domain; + (void) key; + } + } +} + coro<> ServerSession::rP_DefinitionsUpdate(Net::AsyncSocket &sock) { static std::atomic debugDefLogCount = 0; - uint32_t typeCount = co_await sock.read(); - typeCount = std::min(typeCount, static_cast(EnumDefContent::MAX_ENUM)); - - for(uint32_t type = 0; type < typeCount; ++type) { - uint32_t count = co_await sock.read(); - for(uint32_t i = 0; i < count; ++i) { - ResourceId id = co_await sock.read(); - std::string dataStr = co_await sock.read(); - (void)dataStr; - - if(type == static_cast(EnumDefContent::Node)) { - DefNode_t def; - def.NodestateId = 0; - def.TexId = id; - AsyncContext.ThisTickEntry.Profile_Node_AddOrChange.emplace_back(id, def); - if(id < 32) { - uint32_t idx = debugDefLogCount.fetch_add(1); - if(idx < 64) { - LOG.debug() << "DefNode id=" << id - << " nodestate=" << def.NodestateId - << " tex=" << def.TexId; - } + uint32_t size; + + { + size = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_Voxel_AddOrChange.reserve(AsyncContext.ThisTickEntry.Profile_Voxel_AddOrChange.size()+size); + for(size_t iter = 0; iter < size; ++iter) { + uint32_t id = co_await sock.read(); + std::string data = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_Voxel_AddOrChange.emplace_back( + id, + DefVoxel{ + std::u8string_view((const char8_t*) data.data(), data.size()) } - } + ); + } + } + + { + size = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_Node_AddOrChange.reserve(AsyncContext.ThisTickEntry.Profile_Node_AddOrChange.size()+size); + for(size_t iter = 0; iter < size; ++iter) { + uint32_t id = co_await sock.read(); + std::string data = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_Node_AddOrChange.emplace_back( + id, + DefNode{ + std::u8string_view((const char8_t*) data.data(), data.size()) + } + ); + } + } + + { + size = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_World_AddOrChange.reserve(AsyncContext.ThisTickEntry.Profile_World_AddOrChange.size()+size); + for(size_t iter = 0; iter < size; ++iter) { + uint32_t id = co_await sock.read(); + std::string data = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_World_AddOrChange.emplace_back( + id, + DefWorld{ + std::u8string_view((const char8_t*) data.data(), data.size()) + } + ); + } + } + + { + size = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_Portal_AddOrChange.reserve(AsyncContext.ThisTickEntry.Profile_Portal_AddOrChange.size()+size); + for(size_t iter = 0; iter < size; ++iter) { + uint32_t id = co_await sock.read(); + std::string data = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_Portal_AddOrChange.emplace_back( + id, + DefPortal{ + std::u8string_view((const char8_t*) data.data(), data.size()) + } + ); + } + } + + { + size = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_Entity_AddOrChange.reserve(AsyncContext.ThisTickEntry.Profile_Entity_AddOrChange.size()+size); + for(size_t iter = 0; iter < size; ++iter) { + uint32_t id = co_await sock.read(); + std::string data = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_Entity_AddOrChange.emplace_back( + id, + DefEntity{ + std::u8string_view((const char8_t*) data.data(), data.size()) + } + ); + } + } + + { + size = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_Item_AddOrChange.reserve(AsyncContext.ThisTickEntry.Profile_Item_AddOrChange.size()+size); + for(size_t iter = 0; iter < size; ++iter) { + uint32_t id = co_await sock.read(); + std::string data = co_await sock.read(); + AsyncContext.ThisTickEntry.Profile_Item_AddOrChange.emplace_back( + id, + DefItem{ + std::u8string_view((const char8_t*) data.data(), data.size()) + } + ); } } - uint32_t lostCount = co_await sock.read(); - lostCount = std::min(lostCount, static_cast(EnumDefContent::MAX_ENUM)); - for(uint32_t type = 0; type < lostCount; ++type) { - uint32_t count = co_await sock.read(); - for(uint32_t i = 0; i < count; ++i) { - ResourceId id = co_await sock.read(); - if(type == static_cast(EnumDefContent::Node)) - AsyncContext.ThisTickEntry.Profile_Node_Lost.push_back(id); - } + { + size = co_await sock.read(); + for(uint32_t iter = 0; iter < size; ++iter) + AsyncContext.ThisTickEntry.Profile_Voxel_Lost.push_back(co_await sock.read()); } - uint32_t dkCount = co_await sock.read(); - dkCount = std::min(dkCount, static_cast(EnumDefContent::MAX_ENUM)); - for(uint32_t type = 0; type < dkCount; ++type) { - uint32_t count = co_await sock.read(); - for(uint32_t i = 0; i < count; ++i) { - std::string key = co_await sock.read(); + { + size = co_await sock.read(); + for(uint32_t iter = 0; iter < size; ++iter) + AsyncContext.ThisTickEntry.Profile_Node_Lost.push_back(co_await sock.read()); + } + + { + size = co_await sock.read(); + for(uint32_t iter = 0; iter < size; ++iter) + AsyncContext.ThisTickEntry.Profile_World_Lost.push_back(co_await sock.read()); + } + + { + size = co_await sock.read(); + for(uint32_t iter = 0; iter < size; ++iter) + AsyncContext.ThisTickEntry.Profile_Portal_Lost.push_back(co_await sock.read()); + } + + { + size = co_await sock.read(); + for(uint32_t iter = 0; iter < size; ++iter) + AsyncContext.ThisTickEntry.Profile_Entity_Lost.push_back(co_await sock.read()); + } + + { + size = co_await sock.read(); + for(uint32_t iter = 0; iter < size; ++iter) + AsyncContext.ThisTickEntry.Profile_Item_Lost.push_back(co_await sock.read()); + } + + for(size_t type = 0; type < static_cast(EnumDefContent::MAX_ENUM); type++) { + size = co_await sock.read(); + + for(size_t iter = 0; iter < size; iter++) { std::string domain = co_await sock.read(); - (void)key; - (void)domain; + std::string key = co_await sock.read(); + + (void) domain; + (void) key; } } diff --git a/Src/Client/ServerSession.hpp b/Src/Client/ServerSession.hpp index 2c04a63..8ea44e5 100644 --- a/Src/Client/ServerSession.hpp +++ b/Src/Client/ServerSession.hpp @@ -122,17 +122,17 @@ private: // Полученные с сервера ресурсы std::vector> ReceivedAssets; - std::vector> Profile_Voxel_AddOrChange; + std::vector> Profile_Voxel_AddOrChange; std::vector Profile_Voxel_Lost; - std::vector> Profile_Node_AddOrChange; + std::vector> Profile_Node_AddOrChange; std::vector Profile_Node_Lost; - std::vector> Profile_World_AddOrChange; + std::vector> Profile_World_AddOrChange; std::vector Profile_World_Lost; - std::vector> Profile_Portal_AddOrChange; + std::vector> Profile_Portal_AddOrChange; std::vector Profile_Portal_Lost; - std::vector> Profile_Entity_AddOrChange; + std::vector> Profile_Entity_AddOrChange; std::vector Profile_Entity_Lost; - std::vector> Profile_Item_AddOrChange; + std::vector> Profile_Item_AddOrChange; std::vector Profile_Item_Lost; std::vector> Worlds_AddOrChange; @@ -197,6 +197,7 @@ private: coro<> rP_AssetsBindHH(Net::AsyncSocket &sock); coro<> rP_AssetsInitSend(Net::AsyncSocket &sock); coro<> rP_AssetsNextSend(Net::AsyncSocket &sock); + coro<> rP_DefinitionsFull(Net::AsyncSocket &sock); coro<> rP_DefinitionsUpdate(Net::AsyncSocket &sock); coro<> rP_ChunkVoxels(Net::AsyncSocket &sock); coro<> rP_ChunkNodes(Net::AsyncSocket &sock); diff --git a/Src/Client/Vulkan/VulkanRenderSession.cpp b/Src/Client/Vulkan/VulkanRenderSession.cpp index b4ee0e5..4bddccd 100644 --- a/Src/Client/Vulkan/VulkanRenderSession.cpp +++ b/Src/Client/Vulkan/VulkanRenderSession.cpp @@ -121,15 +121,15 @@ void ChunkMeshGenerator::run(uint8_t id) { uint8_t fullNodes[18][18][18]; // Профиль, который используется если на стороне клиента отсутствует нужных профиль - DefNode_t defaultProfileNode; + DefNode defaultProfileNode; // Кеш запросов профилей нод - std::unordered_map profilesNodeCache; - auto getNodeProfile = [&](DefNodeId id) -> const DefNode_t* { + std::unordered_map profilesNodeCache; + auto getNodeProfile = [&](DefNodeId id) -> const DefNode* { auto iterCache = profilesNodeCache.find(id); if(iterCache == profilesNodeCache.end()) { // Промах кеша - auto iterSS = SS->Profiles.DefNode.find(id); - if(iterSS != SS->Profiles.DefNode.end()) { + auto iterSS = SS->Profiles.DefNodes.find(id); + if(iterSS != SS->Profiles.DefNodes.end()) { return (profilesNodeCache[id] = &iterSS->second); } else { // Профиль отсутствует на клиенте @@ -189,46 +189,50 @@ void ChunkMeshGenerator::run(uint8_t id) { std::unordered_map nodeFullCuboidCache; auto nodeIsFull = [&](Node node) -> bool { + if(node.NodeId == 0) + return false; + auto iterCache = nodeFullCuboidCache.find(node.Data); if(iterCache == nodeFullCuboidCache.end()) { - const DefNode_t* profile = getNodeProfile(node.NodeId); - if(profile->TexId != 0) { - return (nodeFullCuboidCache[node.Data] = true); - } - - if(NSP && profile->NodestateId != 0 && NSP->hasNodestate(profile->NodestateId)) { - std::unordered_map states; - int32_t meta = node.Meta; - states.emplace("meta", meta); - const auto routes = NSP->getModelsForNode(profile->NodestateId, metaStatesInfo, states); - bool isFull = !routes.empty(); - if(isFull) { - for(const auto& variants : routes) { - for(const auto& [weight, faces] : variants) { - (void)weight; - auto hasFace = [&](EnumFace face) -> bool { - auto iterFace = faces.find(face); - return iterFace != faces.end() && !iterFace->second.empty(); - }; - if(!hasFace(EnumFace::Up) - || !hasFace(EnumFace::Down) - || !hasFace(EnumFace::East) - || !hasFace(EnumFace::West) - || !hasFace(EnumFace::South) - || !hasFace(EnumFace::North)) - { - isFull = false; - break; + const DefNode* profile = getNodeProfile(node.NodeId); + if(NSP) { + if(const AssetsNodestate* ptr = std::get_if(&profile->RenderStates)) { + if(NSP->hasNodestate(*ptr)) { + std::unordered_map states; + int32_t meta = node.Meta; + states.emplace("meta", meta); + const auto routes = NSP->getModelsForNode(*ptr, metaStatesInfo, states); + bool isFull = !routes.empty(); + if(isFull) { + for(const auto& variants : routes) { + for(const auto& [weight, faces] : variants) { + (void)weight; + auto hasFace = [&](EnumFace face) -> bool { + auto iterFace = faces.find(face); + return iterFace != faces.end() && !iterFace->second.empty(); + }; + if(!hasFace(EnumFace::Up) + || !hasFace(EnumFace::Down) + || !hasFace(EnumFace::East) + || !hasFace(EnumFace::West) + || !hasFace(EnumFace::South) + || !hasFace(EnumFace::North)) + { + isFull = false; + break; + } + } + if(!isFull) + break; } } - if(!isFull) - break; + + return (nodeFullCuboidCache[node.Data] = isFull); } } - return (nodeFullCuboidCache[node.Data] = isFull); } - return (nodeFullCuboidCache[node.Data] = false); + return (nodeFullCuboidCache[node.Data] = true); } else { return iterCache->second; } @@ -420,6 +424,10 @@ void ChunkMeshGenerator::run(uint8_t id) { for(int z = 0; z < 16; z++) for(int y = 0; y < 16; y++) for(int x = 0; x < 16; x++) { + const Node& nodeData = (*chunk)[x+y*16+z*16*16]; + if(nodeData.NodeId == 0) + continue; + const size_t vertexStart = result.NodeVertexs.size(); int fullCovered = 0; @@ -433,66 +441,46 @@ void ChunkMeshGenerator::run(uint8_t id) { if(fullCovered == 0b111111) continue; - const Node& nodeData = (*chunk)[x+y*16+z*16*16]; - const DefNode_t* node = getNodeProfile(nodeData.NodeId); - - if(debugMeshEnabled) { - const bool hasRenderable = (node->NodestateId != 0) || (node->TexId != 0); - if(hasRenderable && fullCovered != 0b111111) { - expectedColumnX[x] = 1; - expectedColumnY[y] = 1; - expectedColumnZ[z] = 1; - } - } + const DefNode* node = getNodeProfile(nodeData.NodeId); bool usedModel = false; - if(NSP && (node->NodestateId != 0 || NSP->hasNodestate(node->NodestateId))) { - auto iterCache = modelCache.find(nodeData.Data); - if(iterCache == modelCache.end()) { - std::unordered_map states; - states.emplace("meta", nodeData.Meta); + if(NSP) { + if(const AssetsNodestate* ptr = std::get_if(&node->RenderStates)) { + if(NSP->hasNodestate(*ptr)) { + auto iterCache = modelCache.find(nodeData.Data); + if(iterCache == modelCache.end()) { + std::unordered_map states; + states.emplace("meta", nodeData.Meta); - ModelCacheEntry entry; - entry.Routes = NSP->getModelsForNode(node->NodestateId, metaStatesInfo, states); - iterCache = modelCache.emplace(nodeData.Data, std::move(entry)).first; - } + ModelCacheEntry entry; + entry.Routes = NSP->getModelsForNode(*ptr, metaStatesInfo, states); + iterCache = modelCache.emplace(nodeData.Data, std::move(entry)).first; + } - if(!iterCache->second.Routes.empty()) { - uint32_t seed = uint32_t(nodeData.Data) * 2654435761u; - seed ^= uint32_t(x) * 73856093u; - seed ^= uint32_t(y) * 19349663u; - seed ^= uint32_t(z) * 83492791u; + if(!iterCache->second.Routes.empty()) { + uint32_t seed = uint32_t(nodeData.Data) * 2654435761u; + seed ^= uint32_t(x) * 73856093u; + seed ^= uint32_t(y) * 19349663u; + seed ^= uint32_t(z) * 83492791u; - for(size_t routeIndex = 0; routeIndex < iterCache->second.Routes.size(); routeIndex++) { - const auto& variants = iterCache->second.Routes[routeIndex]; - const auto* faces = pickVariant(variants, seed + uint32_t(routeIndex) * 374761393u); - if(faces) - appendModel(*faces, fullCovered, x, y, z); + for(size_t routeIndex = 0; routeIndex < iterCache->second.Routes.size(); routeIndex++) { + const auto& variants = iterCache->second.Routes[routeIndex]; + const auto* faces = pickVariant(variants, seed + uint32_t(routeIndex) * 374761393u); + if(faces) + appendModel(*faces, fullCovered, x, y, z); + } + + usedModel = true; + } } - - usedModel = true; } } if(usedModel) goto node_done; - if(NSP && node->TexId != 0) { - auto iterTex = baseTextureCache.find(node->TexId); - if(iterTex != baseTextureCache.end()) { - v.Tex = iterTex->second; - } else { - uint32_t resolvedTex = NSP->getTextureId(node->TexId); - v.Tex = resolvedTex; - baseTextureCache.emplace(node->TexId, resolvedTex); - } - } else { - v.Tex = node->TexId; - } - - if(v.Tex == 0) - goto node_done; + v.Tex = 0; // Рендерим обычный кубоид // XZ+Y @@ -700,58 +688,6 @@ void ChunkMeshGenerator::run(uint8_t id) { } node_done: - if(debugMeshEnabled) { - const bool emitted = result.NodeVertexs.size() > vertexStart; - if(emitted) { - generatedColumnX[x] = 1; - generatedColumnY[y] = 1; - generatedColumnZ[z] = 1; - } else { - const bool hasRenderable = (node->NodestateId != 0) || (node->TexId != 0); - if(hasRenderable && fullCovered != 0b111111) { - uint32_t warnIndex = debugMeshWarnCount.fetch_add(1); - if(warnIndex < 16) { - LOG.warn() << "Missing node geometry at chunk " << int(pos[0]) << ',' - << int(pos[1]) << ',' << int(pos[2]) - << " local " << x << ',' << y << ',' << z - << " nodeId " << nodeData.NodeId - << " meta " << int(nodeData.Meta) - << " covered " << fullCovered - << " tex " << node->TexId - << " nodestate " << node->NodestateId; - } - } - } - } - } - - if(debugMeshEnabled) { - auto collectMissing = [](const std::array& expected, - const std::array& generated) { - std::string res; - for(int i = 0; i < 16; i++) { - if(expected[i] && !generated[i]) { - if(!res.empty()) - res += ','; - res += std::to_string(i); - } - } - return res; - }; - - std::string missingX = collectMissing(expectedColumnX, generatedColumnX); - std::string missingY = collectMissing(expectedColumnY, generatedColumnY); - std::string missingZ = collectMissing(expectedColumnZ, generatedColumnZ); - if(!missingX.empty() || !missingY.empty() || !missingZ.empty()) { - uint32_t warnIndex = debugMeshWarnCount.fetch_add(1); - if(warnIndex < 16) { - LOG.warn() << "Missing mesh columns at chunk " << int(pos[0]) << ',' - << int(pos[1]) << ',' << int(pos[2]) - << " missingX[" << missingX << "]" - << " missingY[" << missingY << "]" - << " missingZ[" << missingZ << "]"; - } - } } // Вычислить индексы и сократить вершины @@ -1700,9 +1636,10 @@ void VulkanRenderSession::tickSync(TickSyncData& data) { for(AssetsNodestate id : changedNodestates) changed.insert(id); - for(const auto& [nodeId, def] : ServerSession->Profiles.DefNode) { - if(changed.contains(def.NodestateId)) - mcpData.ChangedNodes.push_back(nodeId); + for(const auto& [nodeId, def] : ServerSession->Profiles.DefNodes) { + if(const AssetsNodestate* ptr = std::get_if(&def.RenderStates)) + if(changed.contains(*ptr)) + mcpData.ChangedNodes.push_back(nodeId); } } diff --git a/Src/Client/Vulkan/VulkanRenderSession.hpp b/Src/Client/Vulkan/VulkanRenderSession.hpp index 8d87918..713bb82 100644 --- a/Src/Client/Vulkan/VulkanRenderSession.hpp +++ b/Src/Client/Vulkan/VulkanRenderSession.hpp @@ -254,26 +254,13 @@ public: } { - static std::atomic debugModelLogCount = 0; - uint32_t idx = debugModelLogCount.fetch_add(1); - if(idx < 128) { - size_t vertexCount = 0; - for(const auto& [_, verts] : model.Vertecies) - vertexCount += verts.size(); - LOG.debug() << "Model loaded id=" << key - << " verts=" << vertexCount - << " texKeys=" << model.TextureKeys.size() - << " pipelines=" << header.TexturePipelines.size(); - } - } - - if(model.Vertecies.empty()) { - static std::atomic debugEmptyModelLogCount = 0; - uint32_t idx = debugEmptyModelLogCount.fetch_add(1); - if(idx < 128) { - LOG.warn() << "Model has empty geometry id=" << key - << " pipelines=" << header.TexturePipelines.size(); - } + size_t vertexCount = 0; + for(const auto& [_, verts] : model.Vertecies) + vertexCount += verts.size(); + LOG.debug() << "Model loaded id=" << key + << " verts=" << vertexCount + << " texKeys=" << model.TextureKeys.size() + << " pipelines=" << header.TexturePipelines.size(); } Models.insert_or_assign(key, std::move(model)); diff --git a/Src/Common/IdProvider.hpp b/Src/Common/IdProvider.hpp index e8a0ffd..8cebb7a 100644 --- a/Src/Common/IdProvider.hpp +++ b/Src/Common/IdProvider.hpp @@ -161,8 +161,7 @@ public: // reverse читаем под shared lock std::shared_lock rlk(_ReverseMutex[t]); for(ResourceId id : new_ids) { - // id=0 не бывает в newlyInserted - const std::size_t idx = static_cast(id - 1); + const std::size_t idx = static_cast(id); if(idx >= _Reverse[t].size()) { // теоретически не должно случаться (мы пишем reverse до push в log) continue; @@ -175,8 +174,7 @@ public: rlk.unlock(); // 3) дописать в IdToDK (для новых клиентов) - // Важно: IdToDK[0] уже содержит "core/none" как элемент 0. - IdToDK[t].append_range(result[t]); // C++23 + IdToDK[t].append_range(result[t]); } return result; diff --git a/Src/Common/Packets.hpp b/Src/Common/Packets.hpp index 27df237..0e175f8 100644 --- a/Src/Common/Packets.hpp +++ b/Src/Common/Packets.hpp @@ -92,6 +92,7 @@ enum struct ToClient : uint8_t { AssetsInitSend, // Начало отправки запрошенного клиентом ресурса AssetsNextSend, // Продолжение отправки ресурса + DefinitionsFull, // Полная информация о профилях контента DefinitionsUpdate, // Обновление и потеря профилей контента (воксели, ноды, сущности, миры, ...) ChunkVoxels, // Обновление вокселей чанка diff --git a/Src/Server/AssetsManager.hpp b/Src/Server/AssetsManager.hpp index 678fc7c..eb22489 100644 --- a/Src/Server/AssetsManager.hpp +++ b/Src/Server/AssetsManager.hpp @@ -46,6 +46,28 @@ public: Out_applyResourcesUpdate applyResourcesUpdate(Out_checkAndPrepareResourcesUpdate& orr) { Out_applyResourcesUpdate result = AssetsPreloader::applyResourcesUpdate(orr); + { + static TOS::Logger LOG = "Server>AssetsManager"; + + for(size_t type = 0; type < static_cast(EnumAssets::MAX_ENUM); ++type) { + if(result.NewOrUpdates[type].empty()) + continue; + + EnumAssets typeEnum = static_cast(type); + const char* typeName = ::EnumAssetsToDirectory(typeEnum); + + for(const auto& bind : result.NewOrUpdates[type]) { + auto dk = getDK(typeEnum, bind.Id); + if(!dk) + continue; + + LOG.debug() + << typeName << ": " + << dk->Domain << '+' << dk->Key << " -> " << bind.Id; + } + } + } + for(auto& [hash, data] : orr.NewHeadless) { Resources.emplace(hash, ResourceHashData{0, std::make_shared(std::move(data))}); } @@ -104,4 +126,4 @@ private: > Resources; }; -} \ No newline at end of file +} diff --git a/Src/Server/ContentManager.cpp b/Src/Server/ContentManager.cpp index 3da4517..50615ce 100644 --- a/Src/Server/ContentManager.cpp +++ b/Src/Server/ContentManager.cpp @@ -1,6 +1,8 @@ #include "ContentManager.hpp" #include "Common/Abstract.hpp" #include +#include +#include namespace LV::Server { @@ -12,13 +14,22 @@ ContentManager::ContentManager(AssetsManager& am) ContentManager::~ContentManager() = default; void ContentManager::registerBase_Node(ResourceId id, const std::string& domain, const std::string& key, const sol::table& profile) { - std::optional& node = getEntry_Node(id); - if(!node) - node.emplace(); + std::optional* basePtr; - DefNode& def = *node; - def.Domain = domain; - def.Key = key; + { + size_t entryIndex = id / TableEntry::ChunkSize; + size_t entryId = id % TableEntry::ChunkSize; + + size_t need = entryIndex+1-Profiles_Base_Node.size(); + for(size_t iter = 0; iter < need; iter++) { + Profiles_Base_Node.emplace_back(std::make_unique>()); + } + + basePtr = &Profiles_Base_Node[entryIndex]->Entries[entryId]; + *basePtr = DefNode_Base(); + } + + DefNode_Base& def = **basePtr; { std::optional> parent = profile.get>>("parent"); @@ -92,7 +103,7 @@ void ContentManager::registerBase_Entity(ResourceId id, const std::string& domai void ContentManager::registerBase(EnumDefContent type, const std::string& domain, const std::string& key, const sol::table& profile) { ResourceId id = getId(type, domain, key); - ProfileChanges[(int) type].push_back(id); + ProfileChanges[static_cast(type)].push_back(id); if(type == EnumDefContent::Node) registerBase_Node(id, domain, key, profile); @@ -122,11 +133,54 @@ void ContentManager::unRegisterModifier(EnumDefContent type, const std::string& ProfileChanges[(int) type].push_back(id); } -void ContentManager::markAllProfilesDirty(EnumDefContent type) { - const auto &table = this->idToDK()[(int) type]; - size_t counter = 0; - for(const auto& [domain, key] : table) { - ProfileChanges[static_cast(type)].push_back(counter++); +// void ContentManager::markAllProfilesDirty(EnumDefContent type) { +// const auto &table = this->idToDK()[(int) type]; +// size_t counter = 0; +// for(const auto& [domain, key] : table) { +// ProfileChanges[static_cast(type)].push_back(counter++); +// } +// } + +template +void ContentManager::buildEndProfilesByType(auto& profiles, auto enumType, auto& base, auto& keys, auto& result, auto& modsTable) { + // Расширяем таблицу итоговых профилей до нужного количества + if(!keys.empty()) { + size_t need = keys.back() / TableEntry::ChunkSize; + if(need >= profiles.size()) { + profiles.reserve(need); + + for(size_t iter = 0; iter <= need-profiles.size(); ++iter) + profiles.emplace_back(std::make_unique>()); + } + } + + TOS::Logger("CM").debug() << "type: " << static_cast(enumType); + + // Пересчитываем профили + for(size_t id : keys) { + size_t entryIndex = id / TableEntry::ChunkSize; + size_t subIndex = id % TableEntry::ChunkSize; + + if( + entryIndex >= base.size() + || !base[entryIndex]->Entries[subIndex] + ) { + // Базовый профиль не существует + profiles[entryIndex]->Entries[subIndex] = std::nullopt; + // Уведомляем о потере профиля + result.LostProfiles[static_cast(enumType)].push_back(id); + } else { + // Собираем конечный профиль + std::vector> mods_default, *mods = &mods_default; + auto iter = modsTable.find(id); + if(iter != modsTable.end()) + mods = &iter->second; + + std::optional dk = getDK(enumType, id); + assert(dk); + TOS::Logger("CM").debug() << "\t" << dk->Domain << ":" << dk->Key << " -> " << id; + profiles[entryIndex]->Entries[subIndex] = base[entryIndex]->Entries[subIndex]->compile(AM, *this, dk->Domain, dk->Key, *mods); + } } } @@ -134,15 +188,148 @@ ContentManager::Out_buildEndProfiles ContentManager::buildEndProfiles() { Out_buildEndProfiles result; for(int type = 0; type < (int) EnumDefContent::MAX_ENUM; type++) { + std::shared_lock lock(Profiles_Mtx[type]); auto& keys = ProfileChanges[type]; std::sort(keys.begin(), keys.end()); auto iterErase = std::unique(keys.begin(), keys.end()); keys.erase(iterErase, keys.end()); - + switch(type) { + case 0: buildEndProfilesByType (Profiles_Voxel, EnumDefContent::Voxel, Profiles_Base_Voxel, keys, result, Profiles_Mod_Voxel); break; + case 1: buildEndProfilesByType (Profiles_Node, EnumDefContent::Node, Profiles_Base_Node, keys, result, Profiles_Mod_Node); break; + case 2: buildEndProfilesByType (Profiles_World, EnumDefContent::World, Profiles_Base_World, keys, result, Profiles_Mod_World); break; + case 3: buildEndProfilesByType (Profiles_Portal, EnumDefContent::Portal, Profiles_Base_Portal, keys, result, Profiles_Mod_Portal); break; + case 4: buildEndProfilesByType (Profiles_Entity, EnumDefContent::Entity, Profiles_Base_Entity, keys, result, Profiles_Mod_Entity); break; + case 5: buildEndProfilesByType (Profiles_Item, EnumDefContent::Item, Profiles_Base_Item, keys, result, Profiles_Mod_Item); break; + default: std::unreachable(); + } } return result; } +ContentManager::Out_getAllProfiles ContentManager::getAllProfiles() { + Out_getAllProfiles result; + + size_t counter; + + { + std::shared_lock lock(Profiles_Mtx[static_cast(EnumDefContent::Voxel)]); + result.ProfilesIds_Voxel.reserve(Profiles_Voxel.size()*TableEntry::ChunkSize); + counter = 0; + for(const auto& entry : Profiles_Voxel) + for(const auto& item : entry->Entries) { + size_t id = counter++; + if(item) + result.ProfilesIds_Voxel.push_back(id); + } + + result.ProfilesIds_Voxel.shrink_to_fit(); + result.Profiles_Voxel.reserve(result.ProfilesIds_Voxel.size()); + for(const auto& entry : Profiles_Voxel) + for(const auto& item : entry->Entries) + if(item) + result.Profiles_Voxel.push_back(&item.value()); + } + + { + std::shared_lock lock(Profiles_Mtx[static_cast(EnumDefContent::Node)]); + result.ProfilesIds_Node.reserve(Profiles_Node.size()*TableEntry::ChunkSize); + counter = 0; + for(const auto& entry : Profiles_Node) + for(const auto& item : entry->Entries) { + size_t id = counter++; + if(item) + result.ProfilesIds_Node.push_back(id); + } + + result.ProfilesIds_Node.shrink_to_fit(); + result.Profiles_Node.reserve(result.ProfilesIds_Node.size()); + for(const auto& entry : Profiles_Node) + for(const auto& item : entry->Entries) + if(item) + result.Profiles_Node.push_back(&item.value()); + } + + { + std::shared_lock lock(Profiles_Mtx[static_cast(EnumDefContent::World)]); + result.ProfilesIds_World.reserve(Profiles_World.size()*TableEntry::ChunkSize); + counter = 0; + for(const auto& entry : Profiles_World) + for(const auto& item : entry->Entries) { + size_t id = counter++; + if(item) + result.ProfilesIds_World.push_back(id); + } + + result.ProfilesIds_World.shrink_to_fit(); + result.Profiles_World.reserve(result.ProfilesIds_World.size()); + for(const auto& entry : Profiles_World) + for(const auto& item : entry->Entries) + if(item) + result.Profiles_World.push_back(&item.value()); + } + + { + std::shared_lock lock(Profiles_Mtx[static_cast(EnumDefContent::Portal)]); + result.ProfilesIds_Portal.reserve(Profiles_Portal.size()*TableEntry::ChunkSize); + counter = 0; + for(const auto& entry : Profiles_Portal) + for(const auto& item : entry->Entries) { + size_t id = counter++; + if(item) + result.ProfilesIds_Portal.push_back(id); + } + + result.ProfilesIds_Portal.shrink_to_fit(); + result.Profiles_Portal.reserve(result.ProfilesIds_Portal.size()); + for(const auto& entry : Profiles_Portal) + for(const auto& item : entry->Entries) + if(item) + result.Profiles_Portal.push_back(&item.value()); + } + + { + std::shared_lock lock(Profiles_Mtx[static_cast(EnumDefContent::Entity)]); + result.ProfilesIds_Entity.reserve(Profiles_Entity.size()*TableEntry::ChunkSize); + counter = 0; + for(const auto& entry : Profiles_Entity) + for(const auto& item : entry->Entries) { + size_t id = counter++; + if(item) + result.ProfilesIds_Entity.push_back(id); + } + + result.ProfilesIds_Entity.shrink_to_fit(); + result.Profiles_Entity.reserve(result.ProfilesIds_Entity.size()); + for(const auto& entry : Profiles_Entity) + for(const auto& item : entry->Entries) + if(item) + result.Profiles_Entity.push_back(&item.value()); + } + + { + std::shared_lock lock(Profiles_Mtx[static_cast(EnumDefContent::Item)]); + result.ProfilesIds_Item.reserve(Profiles_Item.size()*TableEntry::ChunkSize); + counter = 0; + for(const auto& entry : Profiles_Item) + for(const auto& item : entry->Entries) { + size_t id = counter++; + if(item) + result.ProfilesIds_Item.push_back(id); + } + + result.ProfilesIds_Item.shrink_to_fit(); + result.Profiles_Item.reserve(result.ProfilesIds_Item.size()); + for(const auto& entry : Profiles_Item) + for(const auto& item : entry->Entries) + if(item) + result.Profiles_Item.push_back(&item.value()); + } + + result.IdToDK = idToDK(); + + return result; +} + } diff --git a/Src/Server/ContentManager.hpp b/Src/Server/ContentManager.hpp index 6a33fe3..8bbae4b 100644 --- a/Src/Server/ContentManager.hpp +++ b/Src/Server/ContentManager.hpp @@ -3,20 +3,62 @@ #include "Common/Abstract.hpp" #include "AssetsManager.hpp" #include "Common/IdProvider.hpp" +#include "Common/Net.hpp" +#include "TOSLib.hpp" #include #include #include +#include #include namespace LV::Server { -struct DefVoxel_Base { }; -struct DefNode_Base { }; -struct DefWorld_Base { }; -struct DefPortal_Base { }; -struct DefEntity_Base { }; -struct DefItem_Base { }; +struct ResourceBase { + std::string Domain, Key; +}; + +class ContentManager; + +struct DefVoxel : public ResourceBase { + std::u8string dumpToClient() const { + return {}; + } +}; + +struct DefNode : public ResourceBase { + AssetsNodestate NodestateId; + + std::u8string dumpToClient() const { + auto wr = TOS::ByteBuffer::Writer(); + wr << uint32_t(NodestateId); + auto buff = wr.complite(); + return (std::u8string) std::u8string_view((const char8_t*) buff.data(), buff.size()); + } +}; +struct DefWorld : public ResourceBase { + std::u8string dumpToClient() const { + return {}; + } +}; + +struct DefPortal : public ResourceBase { + std::u8string dumpToClient() const { + return {}; + } +}; + +struct DefEntity : public ResourceBase { + std::u8string dumpToClient() const { + return {}; + } +}; + +struct DefItem : public ResourceBase { + std::u8string dumpToClient() const { + return {}; + } +}; struct DefVoxel_Mod { }; struct DefNode_Mod { }; @@ -25,20 +67,57 @@ struct DefPortal_Mod { }; struct DefEntity_Mod { }; struct DefItem_Mod { }; -struct ResourceBase { - std::string Domain, Key; +struct DefVoxel_Base { +private: + friend ContentManager; + DefVoxel compile(AssetsManager& am, ContentManager& cm, const std::string_view domain, const std::string_view key, const std::vector>& mods) const { + return DefVoxel(); + } }; -struct DefVoxel : public ResourceBase { }; -struct DefNode : public ResourceBase { - AssetsNodestate NodestateId; - std::vector ModelDeps; - std::vector TextureDeps; +struct DefNode_Base { +private: + friend ContentManager; + DefNode compile(AssetsManager& am, ContentManager& cm, const std::string_view domain, const std::string_view key, const std::vector>& mods) const { + DefNode profile; + std::string jsonKey = std::string(key)+".json"; + profile.NodestateId = am.getId(EnumAssets::Nodestate, domain, jsonKey); + TOS::Logger("Compile").info() << domain << ' ' << key << " -> " << profile.NodestateId; + return profile; + } +}; + +struct DefWorld_Base { +private: + friend ContentManager; + DefWorld compile(AssetsManager& am, ContentManager& cm, const std::string_view domain, const std::string_view key, const std::vector>& mods) const { + return DefWorld(); + } +}; + +struct DefPortal_Base { +private: + friend ContentManager; + DefPortal compile(AssetsManager& am, ContentManager& cm, const std::string_view domain, const std::string_view key, const std::vector>& mods) const { + return DefPortal(); + } +}; + +struct DefEntity_Base { +private: + friend ContentManager; + DefEntity compile(AssetsManager& am, ContentManager& cm, const std::string_view domain, const std::string_view key, const std::vector>& mods) const { + return DefEntity(); + } +}; + +struct DefItem_Base { +private: + friend ContentManager; + DefItem compile(AssetsManager& am, ContentManager& cm, const std::string_view domain, const std::string_view key, const std::vector>& mods) const { + return DefItem(); + } }; -struct DefWorld : public ResourceBase { }; -struct DefPortal : public ResourceBase { }; -struct DefEntity : public ResourceBase { }; -struct DefItem : public ResourceBase { }; /* DK to id @@ -114,7 +193,7 @@ public: MAX_ENUM > DKToId; - std::unordered_map*> Profiles_Voxel; + std::unordered_map*> Profiles_Voxel; std::unordered_map*> Profiles_Node; std::unordered_map*> Profiles_World; std::unordered_map*> Profiles_Portal; @@ -133,15 +212,76 @@ public: void registerModifier(EnumDefContent type, const std::string& mod, const std::string& domain, const std::string& key, const sol::table& profile); void unRegisterModifier(EnumDefContent type, const std::string& mod, const std::string& domain, const std::string& key); // Пометить все профили типа как изменённые (например, после перезагрузки ассетов) - void markAllProfilesDirty(EnumDefContent type); + // void markAllProfilesDirty(EnumDefContent type); // Список всех зарегистрированных профилей выбранного типа std::vector collectProfileIds(EnumDefContent type) const; // Компилирует изменённые профили struct Out_buildEndProfiles { - std::vector ChangedProfiles[MAX_ENUM]; + std::vector< + std::tuple + > ChangedProfiles_Voxel; + + std::vector< + std::tuple + > ChangedProfiles_Node; + + std::vector< + std::tuple + > ChangedProfiles_World; + + std::vector< + std::tuple + > ChangedProfiles_Portal; + + std::vector< + std::tuple + > ChangedProfiles_Entity; + + std::vector< + std::tuple + > ChangedProfiles_Item; + + std::array< + std::vector, + MAX_ENUM + > LostProfiles; + + std::array< + std::vector, + static_cast(EnumDefContent::MAX_ENUM) + > IdToDK; }; + // Компилирует конечные профили по базе и модификаторам (предоставляет клиентам изменённые и потерянные) Out_buildEndProfiles buildEndProfiles(); + + struct Out_getAllProfiles { + std::vector ProfilesIds_Voxel; + std::vector Profiles_Voxel; + + std::vector ProfilesIds_Node; + std::vector Profiles_Node; + + std::vector ProfilesIds_World; + std::vector Profiles_World; + + std::vector ProfilesIds_Portal; + std::vector Profiles_Portal; + + std::vector ProfilesIds_Entity; + std::vector Profiles_Entity; + + std::vector ProfilesIds_Item; + std::vector Profiles_Item; + + std::array< + std::vector, + static_cast(EnumDefContent::MAX_ENUM) + > IdToDK; + }; + + // Выдаёт все профили (для новых клиентов) + Out_getAllProfiles getAllProfiles(); std::optional& getEntry_Voxel(ResourceId resId) { @@ -278,17 +418,19 @@ private: void registerBase_World(ResourceId id, const std::string& domain, const std::string& key, const sol::table& profile); void registerBase_Entity(ResourceId id, const std::string& domain, const std::string& key, const sol::table& profile); + template + void buildEndProfilesByType(auto& profiles, auto enumType, auto& base, auto& keys, auto& result, auto& mods); TOS::Logger LOG = "Server>ContentManager"; AssetsManager& AM; // Профили зарегистрированные модами - std::vector>> Profiles_Base_Voxel; - std::vector>> Profiles_Base_Node; - std::vector>> Profiles_Base_World; - std::vector>> Profiles_Base_Portal; - std::vector>> Profiles_Base_Entity; - std::vector>> Profiles_Base_Item; + std::vector>> Profiles_Base_Voxel; + std::vector>> Profiles_Base_Node; + std::vector>> Profiles_Base_World; + std::vector>> Profiles_Base_Portal; + std::vector>> Profiles_Base_Entity; + std::vector>> Profiles_Base_Item; // Изменения, накладываемые на профили // Идентификатор [домен мода модификатора, модификатор] diff --git a/Src/Server/GameServer.cpp b/Src/Server/GameServer.cpp index 6401733..632c435 100644 --- a/Src/Server/GameServer.cpp +++ b/Src/Server/GameServer.cpp @@ -786,7 +786,7 @@ void GameServer::BackingAsyncLua_t::run(int id) { uint8_t kMetaGrass = 1; DefNodeId kNodeDirt = lru.getIdNode("test", "dirt"); DefNodeId kNodeStone = lru.getIdNode("test", "stone"); - DefNodeId kNodeWood = lru.getIdNode("test", "wood"); + DefNodeId kNodeWood = lru.getIdNode("test", "log"); DefNodeId kNodeLeaves = lru.getIdNode("test", "leaves"); DefNodeId kNodeLava = lru.getIdNode("test", "lava"); DefNodeId kNodeWater = lru.getIdNode("test", "water"); @@ -1370,7 +1370,6 @@ void GameServer::init(fs::path worldPath) { Content.CM.buildEndProfiles(); - LOG.info() << "Инициализация"; initLua(); pushEvent("init"); @@ -1615,6 +1614,7 @@ void GameServer::stepConnections() { std::vector packets; packets.push_back(RemoteClient::makePacket_informateAssets_DK(Content.AM.idToDK())); packets.push_back(RemoteClient::makePacket_informateAssets_HH(Content.AM.collectHashBindings(), lost)); + packets.append_range(RemoteClient::makePackets_informateDefContent_Full(Content.CM.getAllProfiles())); for(const std::shared_ptr& client : newClients) { if(!packets.empty()) { @@ -1685,7 +1685,8 @@ void GameServer::reloadMods() { { // TODO: перезагрузка модов - Content.CM.buildEndProfiles(); + ContentManager::Out_buildEndProfiles out = Content.CM.buildEndProfiles(); + packetsToSend.append_range(RemoteClient::makePackets_informateDefContentUpdate(out)); } LOG.info() << "Перезагрузка ассетов"; diff --git a/Src/Server/RemoteClient.cpp b/Src/Server/RemoteClient.cpp index cfb3c93..da2c683 100644 --- a/Src/Server/RemoteClient.cpp +++ b/Src/Server/RemoteClient.cpp @@ -94,24 +94,122 @@ Net::Packet RemoteClient::makePacket_informateAssets_HH( return pack; } -std::vector RemoteClient::makePackets_sendDefContentUpdate( - std::array< - std::vector< - std::pair< - ResourceId, // Идентификатор профиля - std::u8string // Двоичный формат профиля - > - >, - static_cast(EnumDefContent::MAX_ENUM) - > newOrUpdate, // Новые или изменённые - std::array< - std::vector, - static_cast(EnumDefContent::MAX_ENUM) - > lost, // Потерянные профили - std::array< - std::vector>, - static_cast(EnumDefContent::MAX_ENUM) - > idToDK // Новые привязки +std::vector RemoteClient::makePackets_informateDefContent_Full( + const ContentManager::Out_getAllProfiles& profiles +) { + std::vector packets; + Net::Packet pack; + + auto check = [&](size_t needSize) { + if(pack.size()+needSize > 65500) { + packets.emplace_back(std::move(pack)); + pack.clear(); + } + }; + + pack << (uint8_t) ToClient::DefinitionsFull; + + { + pack << (uint32_t) profiles.ProfilesIds_Voxel.size(); + for(uint32_t id : profiles.ProfilesIds_Voxel) { + check(4); + pack << id; + } + + for(const auto& profile : profiles.Profiles_Voxel) { + std::u8string data = profile->dumpToClient(); + check(data.size()); + pack << std::string_view((const char*) data.data(), data.size()); + } + } + + { + pack << (uint32_t) profiles.ProfilesIds_Node.size(); + for(uint32_t id : profiles.ProfilesIds_Node) { + check(4); + pack << id; + } + + for(const auto& profile : profiles.Profiles_Node) { + std::u8string data = profile->dumpToClient(); + check(data.size()); + pack << std::string_view((const char*) data.data(), data.size()); + } + } + + { + pack << (uint32_t) profiles.ProfilesIds_World.size(); + for(uint32_t id : profiles.ProfilesIds_World) { + check(4); + pack << id; + } + + for(const auto& profile : profiles.Profiles_World) { + std::u8string data = profile->dumpToClient(); + check(data.size()); + pack << std::string_view((const char*) data.data(), data.size()); + } + } + + { + pack << (uint32_t) profiles.ProfilesIds_Portal.size(); + for(uint32_t id : profiles.ProfilesIds_Portal) { + check(4); + pack << id; + } + + for(const auto& profile : profiles.Profiles_Portal) { + std::u8string data = profile->dumpToClient(); + check(data.size()); + pack << std::string_view((const char*) data.data(), data.size()); + } + } + + { + pack << (uint32_t) profiles.ProfilesIds_Entity.size(); + for(uint32_t id : profiles.ProfilesIds_Entity) { + check(4); + pack << id; + } + + for(const auto& profile : profiles.Profiles_Entity) { + std::u8string data = profile->dumpToClient(); + check(data.size()); + pack << std::string_view((const char*) data.data(), data.size()); + } + } + + { + pack << (uint32_t) profiles.ProfilesIds_Item.size(); + for(uint32_t id : profiles.ProfilesIds_Item) { + check(4); + pack << id; + } + + for(const auto& profile : profiles.Profiles_Item) { + std::u8string data = profile->dumpToClient(); + check(data.size()); + pack << std::string_view((const char*) data.data(), data.size()); + } + } + + for(size_t type = 0; type < static_cast(EnumDefContent::MAX_ENUM); type++) { + pack << uint32_t(profiles.IdToDK[type].size()); + + for(const auto& [domain, key] : profiles.IdToDK[type]) { + check(domain.size() + key.size() + 8); + pack << domain << key; + } + } + + if(pack.size()) + packets.emplace_back(std::move(pack)); + + return packets; +} + +std::vector RemoteClient::makePackets_informateDefContentUpdate( + const ContentManager::Out_buildEndProfiles& profiles ) { std::vector packets; Net::Packet pack; @@ -124,33 +222,86 @@ std::vector RemoteClient::makePackets_sendDefContentUpdate( }; pack << (uint8_t) ToClient::DefinitionsUpdate; - pack << uint32_t(newOrUpdate.size()); - for(size_t type = 0; type < static_cast(EnumDefContent::MAX_ENUM); type++) { - pack << uint32_t(newOrUpdate[type].size()); - for(const auto& [id, data] : newOrUpdate[type]) { - check(data.size()); - pack << id << (const std::string&) data; - } - } - - pack << uint32_t(lost.size()); - for(size_t type = 0; type < static_cast(EnumDefContent::MAX_ENUM); type++) { - pack << uint32_t(lost[type].size()); - - for(ResourceId id : lost[type]) { - check(4); + { + pack << uint32_t(profiles.ChangedProfiles_Voxel.size()); + for(const auto& [id, profile] : profiles.ChangedProfiles_Voxel) { pack << id; + std::u8string data = profile->dumpToClient(); + check(data.size()); + pack << std::string_view((const char*) data.data(), data.size()); } } - pack << uint32_t(idToDK.size()); - for(size_t type = 0; type < static_cast(EnumDefContent::MAX_ENUM); type++) { - pack << uint32_t(idToDK[type].size()); - - for(const auto& [domain, key] : idToDK[type]) { - check(domain.size() + key.size() + 8); - pack << key << domain; + { + pack << uint32_t(profiles.ChangedProfiles_Node.size()); + for(const auto& [id, profile] : profiles.ChangedProfiles_Node) { + pack << id; + std::u8string data = profile->dumpToClient(); + check(data.size()); + pack << std::string_view((const char*) data.data(), data.size()); + } + } + + { + pack << uint32_t(profiles.ChangedProfiles_World.size()); + for(const auto& [id, profile] : profiles.ChangedProfiles_World) { + pack << id; + std::u8string data = profile->dumpToClient(); + check(data.size()); + pack << std::string_view((const char*) data.data(), data.size()); + } + } + + { + pack << uint32_t(profiles.ChangedProfiles_Portal.size()); + for(const auto& [id, profile] : profiles.ChangedProfiles_Portal) { + pack << id; + std::u8string data = profile->dumpToClient(); + check(data.size()); + pack << std::string_view((const char*) data.data(), data.size()); + } + } + + { + pack << uint32_t(profiles.ChangedProfiles_Entity.size()); + for(const auto& [id, profile] : profiles.ChangedProfiles_Entity) { + pack << id; + std::u8string data = profile->dumpToClient(); + check(data.size()); + pack << std::string_view((const char*) data.data(), data.size()); + } + } + + { + pack << uint32_t(profiles.ChangedProfiles_Item.size()); + for(const auto& [id, profile] : profiles.ChangedProfiles_Item) { + pack << id; + std::u8string data = profile->dumpToClient(); + check(data.size()); + pack << std::string_view((const char*) data.data(), data.size()); + } + } + + { + for(size_t type = 0; type < static_cast(EnumDefContent::MAX_ENUM); type++) { + pack << uint32_t(profiles.LostProfiles[type].size()); + + for(const ResourceId id : profiles.LostProfiles[type]) { + check(sizeof(ResourceId)); + pack << id; + } + } + } + + { + for(size_t type = 0; type < static_cast(EnumDefContent::MAX_ENUM); type++) { + pack << uint32_t(profiles.IdToDK[type].size()); + + for(const auto& [domain, key] : profiles.IdToDK[type]) { + check(domain.size() + key.size() + 8); + pack << key << domain; + } } } diff --git a/Src/Server/RemoteClient.hpp b/Src/Server/RemoteClient.hpp index 2d03df4..e1504a4 100644 --- a/Src/Server/RemoteClient.hpp +++ b/Src/Server/RemoteClient.hpp @@ -388,25 +388,15 @@ public: const std::vector>>& resources ); + + // Создаёт пакет со всеми данными об игровых профилях + static std::vector makePackets_informateDefContent_Full( + const ContentManager::Out_getAllProfiles& profiles + ); + // Создаёт пакет об обновлении игровых профилей - static std::vector makePackets_sendDefContentUpdate( - std::array< - std::vector< - std::pair< - ResourceId, // Идентификатор профиля - std::u8string // Двоичный формат профиля - > - >, - static_cast(EnumDefContent::MAX_ENUM) - > newOrUpdate, // Новые или изменённые - std::array< - std::vector, - static_cast(EnumDefContent::MAX_ENUM) - > lost, // Потерянные профили - std::array< - std::vector>, - static_cast(EnumDefContent::MAX_ENUM) - > idToDK // Новые привязки + static std::vector makePackets_informateDefContentUpdate( + const ContentManager::Out_buildEndProfiles& profiles ); void onUpdate();