diff --git a/Cache/db.sqlite3 b/Cache/db.sqlite3 deleted file mode 100644 index 23e5b5b..0000000 Binary files a/Cache/db.sqlite3 and /dev/null differ diff --git a/Src/Client/ServerSession.cpp b/Src/Client/ServerSession.cpp index d459825..b360779 100644 --- a/Src/Client/ServerSession.cpp +++ b/Src/Client/ServerSession.cpp @@ -512,24 +512,24 @@ coro<> ServerSession::rP_Resource(Net::AsyncSocket &sock) { uint8_t second = co_await sock.read(); switch((ToClient::L2Resource) second) { - case ToClient::L2Resource::Texture: - - co_return; - case ToClient::L2Resource::FreeTexture: - - co_return; - case ToClient::L2Resource::Sound: - - co_return; - case ToClient::L2Resource::FreeSound: - - co_return; - case ToClient::L2Resource::Model: - - co_return; - case ToClient::L2Resource::FreeModel: - - co_return; + case ToClient::L2Resource::Bind: + { + uint32_t count = co_await sock.read(); + for(size_t iter = 0; iter < count; iter++) { + uint8_t type = co_await sock.read(); + uint32_t id = co_await sock.read(); + Hash_t hash; + co_await sock.read((std::byte*) hash.data(), hash.size()); + } + } + case ToClient::L2Resource::Lost: + { + uint32_t count = co_await sock.read(); + for(size_t iter = 0; iter < count; iter++) { + uint8_t type = co_await sock.read(); + uint32_t id = co_await sock.read(); + } + } case ToClient::L2Resource::InitResSend: { uint32_t size = co_await sock.read(); @@ -537,6 +537,8 @@ coro<> ServerSession::rP_Resource(Net::AsyncSocket &sock) { co_await sock.read((std::byte*) hash.data(), hash.size()); uint32_t chunkSize = co_await sock.read(); + assert(chunkSize < std::pow(2, 26)); + std::u8string data(size, '\0'); co_await sock.read((std::byte*) data.data(), data.size()); diff --git a/Src/Common/Abstract.hpp b/Src/Common/Abstract.hpp index b76c0f5..3ad260e 100644 --- a/Src/Common/Abstract.hpp +++ b/Src/Common/Abstract.hpp @@ -389,7 +389,7 @@ using ResourceId_t = uint32_t; */ enum class EnumBinResource { - Texture, Animation, Model, Sound, Font + Texture, Animation, Model, Sound, Font, MAX_ENUM }; using BinaryResource = std::shared_ptr; @@ -401,14 +401,8 @@ using BinModelId_t = ResourceId_t; using BinSoundId_t = ResourceId_t; using BinFontId_t = ResourceId_t; -// Шаблоны использования бинарных ресурсов -// using DefTextureId_t = ResourceId_t; -// using DefModelId_t = ResourceId_t; -// using DefSoundId_t = ResourceId_t; -// using DefFontId_t = ResourceId_t; - enum class EnumDefContent { - Voxel, Node, Generator, World, Portal, Entity, FuncEntitry + Voxel, Node, Generator, World, Portal, Entity, Item, MAX_ENUM }; // Игровые определения @@ -496,6 +490,10 @@ struct TexturePipeline { std::u8string Pipeline; }; +struct DefVoxel_t { + +}; + struct DefNode_t { enum struct EnumDrawType : uint8_t { NoDraw, // Не рисуется @@ -505,6 +503,22 @@ struct DefNode_t { TexturePipeline Texs[6]; }; +struct DefWorld_t { + +}; + +struct DefPortal_t { + +}; + +struct DefEntity_t { + +}; + +struct DefItem_t { + +}; + using Hash_t = std::array; } diff --git a/Src/Server/BinaryResourceManager.cpp b/Src/Server/BinaryResourceManager.cpp index 2d3808b..b1c01de 100644 --- a/Src/Server/BinaryResourceManager.cpp +++ b/Src/Server/BinaryResourceManager.cpp @@ -20,99 +20,67 @@ BinaryResourceManager::~BinaryResourceManager() { } -void BinaryResourceManager::recheckResources() { +void BinaryResourceManager::recheckResources(std::vector assets /* Пути до активных папок assets */) { } -ResourceId_t BinaryResourceManager::mapUriToId(const std::string &uri) { - UriParse parse = parseUri(uri); - if(parse.Protocol != "assets") - MAKE_ERROR("Неизвестный протокол ресурса '" << parse.Protocol << "'. Полный путь: " << parse.Orig); +void BinaryResourceManager::needResourceResponse(const ResourceRequest& resources) { + auto lock = Local.lock(); + for(int iter = 0; iter < (int) EnumBinResource::MAX_ENUM; iter++) { + lock->BinToHash[iter].insert(lock->BinToHash[iter].end(), resources.BinToHash[iter].begin(), resources.BinToHash[iter].end()); + } - return getResource_Assets(parse.Path); -} - -void BinaryResourceManager::needResourceResponse(const std::vector &resources) { - UpdatedResources.lock_write()->insert(resources.end(), resources.begin(), resources.end()); + lock->Hashes.insert(lock->Hashes.end(), resources.Hashes.begin(), resources.Hashes.end()); } void BinaryResourceManager::update(float dtime) { - if(UpdatedResources.no_lock_readable().empty()) - return; + // if(UpdatedResources.no_lock_readable().empty()) + // return; - auto lock = UpdatedResources.lock_write(); - for(ResourceId_t resId : *lock) { - auto iterPI = PreparedInformation.find(resId); - if(iterPI != PreparedInformation.end()) - continue; + // auto lock = UpdatedResources.lock_write(); + // for(ResourceId_t resId : *lock) { + // auto iterPI = PreparedInformation.find(resId); + // if(iterPI != PreparedInformation.end()) + // continue; - auto iterRI = ResourcesInfo.find(resId); - if(iterRI != ResourcesInfo.end()) { - PreparedInformation[resId] = iterRI->second->Loaded; - } - } + // auto iterRI = ResourcesInfo.find(resId); + // if(iterRI != ResourcesInfo.end()) { + // PreparedInformation[resId] = iterRI->second->Loaded; + // } + // } } BinaryResourceManager::UriParse BinaryResourceManager::parseUri(const std::string &uri) { size_t pos = uri.find("://"); if(pos == std::string::npos) - return {uri, "assets", uri}; + return {"assets", uri}; else - return {uri, uri.substr(0, pos), uri.substr(pos+3)}; + return {uri.substr(0, pos), uri.substr(pos+3)}; } -ResourceId_t BinaryResourceManager::getResource_Assets(std::string path) { - size_t pos = path.find("/"); +// coro<> BinaryResourceManager::checkResource_Assets(ResourceId_t id, fs::path path, std::shared_ptr res) { +// try { +// asio::stream_file fd(IOC, path, asio::stream_file::flags::read_only); - if(pos == std::string::npos) - MAKE_ERROR("Не действительный путь assets: '" << path << "'"); - - std::string domain = path.substr(0, pos); - std::string inDomainPath = path.substr(pos+1); +// if(fd.size() > 1024*1024*16) +// MAKE_ERROR("Превышен лимит размера файла: " << fd.size() << " > " << 1024*1024*16); - ResourceId_t &resId = KnownResource[path]; - if(!resId) - resId = NextId++; +// std::shared_ptr file = std::make_shared(); +// file->Data.resize(fd.size()); +// co_await asio::async_read(fd, asio::mutable_buffer(file->Data.data(), file->Data.size())); +// file->calcHash(); +// res->LastError.clear(); +// } catch(const std::exception &exc) { +// res->LastError = exc.what(); +// res->IsLoading = false; - std::shared_ptr &res = ResourcesInfo[resId]; - if(!res) { - res = std::make_shared(); +// if(const boost::system::system_error *errc = dynamic_cast(&exc); errc && errc->code() == asio::error::operation_aborted) +// co_return; +// } - auto iter = Domains.find("domain"); - if(iter == Domains.end()) { - UpdatedResources.lock_write()->push_back(resId); - } else { - res->IsLoading = true; - co_spawn(checkResource_Assets(resId, iter->second / inDomainPath, res)); - } - } - - return resId; -} - -coro<> BinaryResourceManager::checkResource_Assets(ResourceId_t id, fs::path path, std::shared_ptr res) { - try { - asio::stream_file fd(IOC, path, asio::stream_file::flags::read_only); - - if(fd.size() > 1024*1024*16) - MAKE_ERROR("Превышен лимит размера файла: " << fd.size() << " > " << 1024*1024*16); - - std::shared_ptr file = std::make_shared(); - file->Data.resize(fd.size()); - co_await asio::async_read(fd, asio::mutable_buffer(file->Data.data(), file->Data.size())); - file->calcHash(); - res->LastError.clear(); - } catch(const std::exception &exc) { - res->LastError = exc.what(); - res->IsLoading = false; - - if(const boost::system::system_error *errc = dynamic_cast(&exc); errc && errc->code() == asio::error::operation_aborted) - co_return; - } - - res->IsLoading = false; - UpdatedResources.lock_write()->push_back(id); -} +// res->IsLoading = false; +// UpdatedResources.lock_write()->push_back(id); +// } } \ No newline at end of file diff --git a/Src/Server/BinaryResourceManager.hpp b/Src/Server/BinaryResourceManager.hpp index 94f43cc..034f991 100644 --- a/Src/Server/BinaryResourceManager.hpp +++ b/Src/Server/BinaryResourceManager.hpp @@ -26,7 +26,6 @@ namespace fs = std::filesystem; тогда обычным оповещениям клиентам дойдёт новая версия Подержать какое-то время ресурс в памяти - */ class BinaryResourceManager : public AsyncObject { @@ -34,34 +33,52 @@ public: private: struct Resource { - // Файл загруженный на диск + // Файл загруженный с диска std::shared_ptr Loaded; // Источник std::string Uri; bool IsLoading = false; + size_t LastUsedTime = 0; std::string LastError; }; struct UriParse { - std::string Orig, Protocol, Path; + std::string Protocol, Path; + + std::string getFull() const { + return Protocol + "://" + Path; + } }; - // Последовательная регистрация ресурсов - BinTextureId_t NextIdTexture = 0, NextIdAnimation = 0, NextIdModel = 0, - NextIdSound = 0, NextIdFont = 0; - // Ресурсы - кешированные в оперативную память или в процессе загрузки - std::map> - - // Известные ресурсы - std::map KnownResource; - std::map> ResourcesInfo; - // Сюда - TOS::SpinlockObject> UpdatedResources; - // Подготовленая таблица оповещения об изменениях ресурсов - // Должна забираться сервером и отчищаться - std::unordered_map> PreparedInformation; +// Поток сервера + // Последовательная регистрация ресурсов + ResourceId_t NextId[(int) EnumBinResource::MAX_ENUM] = {0}; + // Известные ресурсы, им присвоен идентификатор + std::unordered_map KnownResource[(int) EnumBinResource::MAX_ENUM]; + std::unordered_map> ResourcesInfo[(int) EnumBinResource::MAX_ENUM]; + +// Местные потоки + struct LocalObj_t { + // Ресурсы - кешированные в оперативную память или в процессе загрузки + std::map> InMemory[(int) EnumBinResource::MAX_ENUM]; + // Кому-то нужно сопоставить идентификаторы с хэшами + std::vector BinToHash[(int) EnumBinResource::MAX_ENUM]; + // Запрос ресурсов, по которым потоки загружают ресурсы с диска + std::vector Hashes; + }; + + TOS::SpinlockObject Local; +public: + // Подготовленные оповещения о ресурсах + struct OutObj_t { + std::unordered_map BinToHash[(int) EnumBinResource::MAX_ENUM]; + std::vector> HashToResource; + }; + +private: + TOS::SpinlockObject Out; public: // Если ресурс будет обновлён или загружен будет вызвано onResourceUpdate @@ -71,17 +88,48 @@ public: // Перепроверка изменений ресурсов void recheckResources(std::vector assets /* Пути до активных папок assets */); // Выдаёт или назначает идентификатор для ресурса - BinTextureId_t getTexture (const std::string& uri); - BinAnimationId_t getAnimation(const std::string& uri); - BinModelId_t getModel (const std::string& uri); - BinSoundId_t getSound (const std::string& uri); - BinFontId_t getFont (const std::string& uri); + ResourceId_t getResource(const std::string& uri, EnumBinResource bin) { + std::string fullUri = parseUri(uri).getFull(); + int index = (int) bin; + + auto &container = KnownResource[index]; + auto iter = container.find(fullUri); + if(iter == container.end()) { + assert(NextId[index] != ResourceId_t(-1)); + ResourceId_t nextId = NextId[index]++; + container.insert(iter, {fullUri, nextId}); + return nextId; + } + + return iter->second; + } + + BinTextureId_t getTexture(const std::string& uri) { + return getResource(uri, EnumBinResource::Texture); + } + + BinAnimationId_t getAnimation(const std::string& uri) { + return getResource(uri, EnumBinResource::Animation); + } + + BinModelId_t getModel(const std::string& uri) { + return getResource(uri, EnumBinResource::Model); + } + + BinSoundId_t getSound(const std::string& uri) { + return getResource(uri, EnumBinResource::Sound); + } + + BinFontId_t getFont(const std::string& uri) { + return getResource(uri, EnumBinResource::Font); + } + + // Запросить ресурсы через pushPreparedPackets + void needResourceResponse(const ResourceRequest& resources); - // Запросить ресурсы через onResourceUpdate - void needResourceResponse(const ResourceRequest &&resources); // Получение обновлений или оповещений ресурсов - std::unordered_map> takePreparedInformation() { - return std::move(PreparedInformation); + OutObj_t takePreparedInformation() { + return std::move(*Out.lock()); } // Серверный такт @@ -89,8 +137,6 @@ public: protected: UriParse parseUri(const std::string &uri); - ResourceId_t getResource_Assets(std::string path); - coro<> checkResource_Assets(ResourceId_t id, fs::path path, std::shared_ptr res); }; diff --git a/Src/Server/GameServer.cpp b/Src/Server/GameServer.cpp index 744fa39..c4b6e2d 100644 --- a/Src/Server/GameServer.cpp +++ b/Src/Server/GameServer.cpp @@ -33,7 +33,7 @@ namespace LV::Server { GameServer::GameServer(asio::io_context &ioc, fs::path worldPath) : AsyncObject(ioc), - Content(ioc, nullptr, nullptr, nullptr, nullptr, nullptr) + Content(ioc) { BackingChunkPressure.Threads.resize(4); BackingNoiseGenerator.Threads.resize(4); @@ -745,6 +745,8 @@ TexturePipeline GameServer::buildTexturePipeline(const std::string& pl) { cmd_name += pl[pos]; } } + + MAKE_ERROR("Ожидался конец команды объявленной на " << startPos << ", наткнулись на конец потока"); }; parse_obj = [&](size_t pos) -> std::pair { @@ -1652,6 +1654,7 @@ void GameServer::stepSyncContent() { for(std::shared_ptr& cec : Game.CECs) { cec->onUpdate(); + // Это для пробы строительства и ломания нод while(!cec->Build.empty()) { Pos::GlobalNode node = cec->Build.front(); cec->Build.pop(); @@ -1679,86 +1682,129 @@ void GameServer::stepSyncContent() { } } - // Оповещения о ресурсах и профилях - Content.Texture.update(CurrentTickDuration); - if(Content.Texture.hasPreparedInformation()) { - auto table = Content.Texture.takePreparedInformation(); - for(std::shared_ptr& cec : Game.CECs) { - cec->Remote->informateBinTexture(table); - } - } - - Content.Animation.update(CurrentTickDuration); - if(Content.Animation.hasPreparedInformation()) { - auto table = Content.Animation.takePreparedInformation(); - for(std::shared_ptr& cec : Game.CECs) { - cec->Remote->informateBinAnimation(table); - } - } - - Content.Model.update(CurrentTickDuration); - if(Content.Model.hasPreparedInformation()) { - auto table = Content.Model.takePreparedInformation(); - for(std::shared_ptr& cec : Game.CECs) { - cec->Remote->informateBinModel(table); - } - } - - Content.Sound.update(CurrentTickDuration); - if(Content.Sound.hasPreparedInformation()) { - auto table = Content.Sound.takePreparedInformation(); - for(std::shared_ptr& cec : Game.CECs) { - cec->Remote->informateBinSound(table); - } - } - - Content.Font.update(CurrentTickDuration); - if(Content.Font.hasPreparedInformation()) { - auto table = Content.Font.takePreparedInformation(); - for(std::shared_ptr& cec : Game.CECs) { - cec->Remote->informateBinFont(table); - } - } // Сбор запросов на ресурсы и профили + отправка пакетов игрокам - ResourceRequest full; + ResourceRequest full = std::move(Content.OnContentChanges); for(std::shared_ptr& cec : Game.CECs) { full.insert(cec->Remote->pushPreparedPackets()); } - BackingChunkPressure.startCollectChanges(); 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(!full.BinTexture.empty()) - Content.Texture.needResourceResponse(full.BinTexture); + if(hasData) { + for(std::shared_ptr& cec : Game.CECs) { + cec->Remote->informateIdToHash(out.BinToHash); + } + } - if(!full.BinAnimation.empty()) - Content.Animation.needResourceResponse(full.BinAnimation); + if(!out.HashToResource.empty()) + for(std::shared_ptr& cec : Game.CECs) { + cec->Remote->informateBinary(out.HashToResource); + } + } - if(!full.BinModel.empty()) - Content.Model.needResourceResponse(full.BinModel); + // Оповещаем об игровых профилях + if(!full.Voxel.empty()) { + std::unordered_map defines; - if(!full.BinSound.empty()) - Content.Sound.needResourceResponse(full.BinSound); - - if(!full.BinFont.empty()) - Content.Font.needResourceResponse(full.BinFont); - - if(!full.Node.empty()) { - std::unordered_map nodeDefines; - - for(DefNodeId_t id : full.Node) { - auto iter = Content.NodeDefines.find(id); - if(iter != Content.NodeDefines.end()) { - nodeDefines[id] = &iter->second; + for(DefVoxelId_t id : full.Node) { + auto iter = Content.ContentIdToDef_Voxel.find(id); + if(iter != Content.ContentIdToDef_Voxel.end()) { + defines[id] = &iter->second; } } for(std::shared_ptr& cec : Game.CECs) { - cec->Remote->informateDefNode(nodeDefines); + cec->Remote->informateDefVoxel(defines); } } + + if(!full.Node.empty()) { + std::unordered_map defines; + + for(DefNodeId_t id : full.Node) { + auto iter = Content.ContentIdToDef_Node.find(id); + if(iter != Content.ContentIdToDef_Node.end()) { + defines[id] = &iter->second; + } + } + + for(std::shared_ptr& cec : Game.CECs) { + cec->Remote->informateDefNode(defines); + } + } + + if(!full.World.empty()) { + std::unordered_map defines; + + for(DefWorldId_t id : full.Node) { + auto iter = Content.ContentIdToDef_World.find(id); + if(iter != Content.ContentIdToDef_World.end()) { + defines[id] = &iter->second; + } + } + + for(std::shared_ptr& cec : Game.CECs) { + cec->Remote->informateDefWorld(defines); + } + } + + if(!full.Portal.empty()) { + std::unordered_map defines; + + for(DefPortalId_t id : full.Node) { + auto iter = Content.ContentIdToDef_Portal.find(id); + if(iter != Content.ContentIdToDef_Portal.end()) { + defines[id] = &iter->second; + } + } + + for(std::shared_ptr& cec : Game.CECs) { + cec->Remote->informateDefPortal(defines); + } + } + + if(!full.Entity.empty()) { + std::unordered_map defines; + + 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 c12706c..bae30e0 100644 --- a/Src/Server/GameServer.hpp +++ b/Src/Server/GameServer.hpp @@ -50,32 +50,42 @@ class GameServer : public AsyncObject { struct ContentObj { public: - // WorldDefManager WorldDM; - // VoxelDefManager VoxelDM; - // NodeDefManager NodeDM; - BinaryResourceManager Texture; - BinaryResourceManager Animation; - BinaryResourceManager Model; - BinaryResourceManager Sound; - BinaryResourceManager Font; + BinaryResourceManager BRM; - ContentObj(asio::io_context &ioc, - std::shared_ptr zeroTexture, - std::shared_ptr zeroAnimation, - std::shared_ptr zeroModel, - std::shared_ptr zeroSound, - std::shared_ptr zeroFont) - : Texture(ioc, zeroTexture), - Animation(ioc, zeroAnimation), - Model(ioc, zeroModel), - Sound(ioc, zeroSound), - Font(ioc, zeroFont) + ResourceId_t NextId[(int) EnumDefContent::MAX_ENUM] = {0}; + std::unordered_map ContentKeyToId[(int) EnumDefContent::MAX_ENUM]; // EnumDefContent + + std::unordered_map ContentIdToDef_Voxel; + std::unordered_map ContentIdToDef_Node; + std::unordered_map ContentIdToDef_World; + std::unordered_map ContentIdToDef_Portal; + std::unordered_map ContentIdToDef_Entity; + std::unordered_map ContentIdToDef_Item; + + + ResourceId_t getContentDefId(const std::string& key, EnumDefContent def) { + int index = int(def); + assert(index < (int) EnumDefContent::MAX_ENUM); + + auto &container = ContentKeyToId[index]; + auto iter = container.find(key); + if(iter == container.end()) { + assert(NextId[index] != ResourceId_t(-1)); + ResourceId_t nextId = NextId[index]++; + container.insert(iter, {key, nextId}); + return nextId; + } + + return iter->second; + } + + // Если контент был перерегистрирован (исключая двоичные ресурсы), то профили будут повторно разосланы + ResourceRequest OnContentChanges; + + + ContentObj(asio::io_context& ioc) + : BRM(ioc) {} - - - std::map NodeDefines; - std::map NodeKeys; - } Content; struct { diff --git a/Src/Server/RemoteClient.cpp b/Src/Server/RemoteClient.cpp index b921bb3..525804b 100644 --- a/Src/Server/RemoteClient.cpp +++ b/Src/Server/RemoteClient.cpp @@ -510,8 +510,7 @@ void RemoteClient::informateBinary(const std::vectorData.size()); - for(auto part : hash) - NextPacket << part; + NextPacket.write((const std::byte*) hash.data(), hash.size()); NextPacket << uint32_t(resource->Data.size()); @@ -526,25 +525,27 @@ void RemoteClient::informateBinary(const std::vector>& resourcesLink) { +void RemoteClient::informateIdToHash(const std::unordered_map* resourcesLink) { std::vector> newForClient; - for(auto& [type, id, hash] : resourcesLink) { - // Посмотрим что известно клиенту - 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({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); + for(int type = 0; type < (int) EnumBinResource::MAX_ENUM; type++) { + for(auto& [id, hash] : resourcesLink[type]) { + // Посмотрим что известно клиенту + 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 { + // Ресурс не отслеживается клиентом } - } else { - // Ресурс не отслеживается клиентом } } @@ -563,7 +564,7 @@ void RemoteClient::informateIdToHash(const std::vector &voxels) +void RemoteClient::informateDefVoxel(const std::unordered_map &voxels) { for(auto pair : voxels) { DefVoxelId_t id = pair.first; @@ -624,7 +625,7 @@ void RemoteClient::informateDefNode(const std::unordered_map &worlds) +void RemoteClient::informateDefWorld(const std::unordered_map &worlds) { for(auto pair : worlds) { DefWorldId_t id = pair.first; @@ -637,7 +638,7 @@ void RemoteClient::informateDefWorld(const std::unordered_map &portals) +void RemoteClient::informateDefPortal(const std::unordered_map &portals) { for(auto pair : portals) { DefPortalId_t id = pair.first; @@ -650,7 +651,7 @@ void RemoteClient::informateDefPortal(const std::unordered_map &entityes) +void RemoteClient::informateDefEntity(const std::unordered_map &entityes) { for(auto pair : entityes) { DefEntityId_t id = pair.first; @@ -663,7 +664,7 @@ void RemoteClient::informateDefEntity(const std::unordered_map &items) +void RemoteClient::informateDefItem(const std::unordered_map &items) { for(auto pair : items) { DefItemId_t id = pair.first; diff --git a/Src/Server/RemoteClient.hpp b/Src/Server/RemoteClient.hpp index 0b81396..b9cda64 100644 --- a/Src/Server/RemoteClient.hpp +++ b/Src/Server/RemoteClient.hpp @@ -140,7 +140,7 @@ public: */ struct ResourceRequest { std::vector Hashes; - std::vector BinToHash[5]; + std::vector BinToHash[5 /*EnumBinResource*/]; std::vector Voxel; std::vector Node; @@ -163,7 +163,7 @@ struct ResourceRequest { } void uniq() { - for(std::vector *vec : {&BinToHash, &Voxel, &Node, &World, + for(std::vector *vec : {&Voxel, &Node, &World, &Portal, &Entity, &Item }) { @@ -172,6 +172,13 @@ struct ResourceRequest { vec->erase(last, vec->end()); } + for(int type = 0; type < (int) EnumBinResource::MAX_ENUM; type++) + { + std::sort(BinToHash[type].begin(), BinToHash[type].end()); + auto last = std::unique(BinToHash[type].begin(), BinToHash[type].end()); + BinToHash[type].erase(last, BinToHash[type].end()); + } + std::sort(Hashes.begin(), Hashes.end()); auto last = std::unique(Hashes.begin(), Hashes.end()); Hashes.erase(last, Hashes.end()); @@ -343,15 +350,15 @@ public: // Привязывает локальный идентификатор с хешем. Если его нет у клиента, // то делается запрос на получение ресурсы для последующей отправки клиенту - void informateIdToHash(const std::vector>& resourcesLink); + void informateIdToHash(const std::unordered_map* resourcesLink); // Игровые определения - void informateDefVoxel(const std::unordered_map &voxels); + 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 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); private: void checkPacketBorder(uint16_t size);