From c1b16949fabcde89aa2922e71555bffc9a5d20a9 Mon Sep 17 00:00:00 2001 From: DrSocalkwe3n Date: Tue, 12 Aug 2025 17:41:36 +0600 Subject: [PATCH] * --- Src/Common/Abstract.hpp | 2 +- Src/Server/Abstract.hpp | 2 +- Src/Server/AssetsManager.cpp | 155 ++++++++++- Src/Server/AssetsManager.hpp | 54 +++- Src/Server/BinaryResourceManager.cpp | 383 --------------------------- Src/Server/BinaryResourceManager.hpp | 153 ----------- Src/Server/GameServer.hpp | 7 +- 7 files changed, 189 insertions(+), 567 deletions(-) delete mode 100644 Src/Server/BinaryResourceManager.cpp delete mode 100644 Src/Server/BinaryResourceManager.hpp diff --git a/Src/Common/Abstract.hpp b/Src/Common/Abstract.hpp index e78df9d..f3080db 100644 --- a/Src/Common/Abstract.hpp +++ b/Src/Common/Abstract.hpp @@ -499,7 +499,7 @@ enum struct TexturePipelineCMD : uint8_t { }; struct TexturePipeline { - std::vector BinTextures; + std::vector BinTextures; std::u8string Pipeline; }; diff --git a/Src/Server/Abstract.hpp b/Src/Server/Abstract.hpp index f2cf1b0..6a6a2d1 100644 --- a/Src/Server/Abstract.hpp +++ b/Src/Server/Abstract.hpp @@ -172,7 +172,7 @@ using NodeStateCondition = std::bitset<256>; NodeStateCondition nodestateExpression(const std::vector& entries, const std::string& expression); struct ModelTransform { - std::vector Ids; + std::vector Ids; uint16_t Weight = 1; bool UVLock = false; }; diff --git a/Src/Server/AssetsManager.cpp b/Src/Server/AssetsManager.cpp index 16b6480..0272446 100644 --- a/Src/Server/AssetsManager.cpp +++ b/Src/Server/AssetsManager.cpp @@ -7,14 +7,55 @@ namespace LV::Server { +coro AssetsManager::loadResourceFromFile(EnumAssets type, fs::path path) const { + co_return AssetsManager::Resource(path); +} -coro AssetsManager::recheckResources(AssetsRegister info) const { +coro AssetsManager::loadResourceFromLua(EnumAssets type, void*) const { + co_return AssetsManager::Resource("assets/null"); +} + +std::tuple&> AssetsManager::Local::nextId(EnumAssets type) { + auto& table = Table[(int) type]; + ResourceId_t id = -1; + std::optional *data = nullptr; + + for(size_t index = 0; index < table.size(); index++) { + auto& entry = *table[index]; + + if(entry.IsFull) + continue; + + uint32_t pos = entry.Empty._Find_first(); + entry.Empty.reset(pos); + + if(entry.Empty._Find_first() == entry.Empty.size()) + entry.IsFull = true; + + id = index*TableEntry::ChunkSize + pos; + data = &entry.Entries[pos]; + } + + if(!data) { + table.emplace_back(std::make_unique()); + id = (table.size()-1)*TableEntry::ChunkSize; + data = &table.back()->Entries[0]; + } + + return {id, *data}; +} + +coro AssetsManager::recheckResources(AssetsRegister info) { Out_recheckResources result; // Найти пропавшие ресурсы for(int type = 0; type < (int) EnumAssets::MAX_ENUM; type++) { - for(auto& [domain, resources] : KeyToId[type]) { + auto lock = LocalObj.lock(); + for(auto& [domain, resources] : lock->KeyToId[type]) { for(auto& [key, id] : resources) { + if(!lock->Table[type][id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]) + continue; + bool exists = false; for(const fs::path& path : info.Assets) { @@ -60,9 +101,10 @@ coro AssetsManager::recheckResources(Assets // Найти новые или изменённые ресурсы for(int type = 0; type < (int) EnumAssets::MAX_ENUM; type++) { - const auto& keyToId = KeyToId[type]; for(auto& [domain, resources] : info.Custom[type]) { + auto lock = LocalObj.lock(); + const auto& keyToId = lock->KeyToId[type]; auto iterDomain = keyToId.find(domain); auto& findList = findedResources[type][domain]; @@ -72,7 +114,7 @@ coro AssetsManager::recheckResources(Assets for(auto& [key, id] : resources) { // Подобрать идентификатор // TODO: реализовать регистрации ресурсов из lua - domainList.emplace_back(key, Resource("assets/null")); + domainList.emplace_back(key, Resource("assets/null"), fs::file_time_type::min()); findList.insert(key); } } else { @@ -82,9 +124,10 @@ coro AssetsManager::recheckResources(Assets continue; else if(iterDomain->second.contains(key)) { // Ресурс уже есть, TODO: нужно проверить его изменение + result.NewOrChange[type][domain].emplace_back(key, co_await loadResourceFromFile((EnumAssets) type, "assets/null"), fs::file_time_type::min()); } else { // Ресурс не был известен - result.NewOrChange[type][domain].emplace_back(key, Resource("assets/null")); + result.NewOrChange[type][domain].emplace_back(key, co_await loadResourceFromFile((EnumAssets) type, "assets/null"), fs::file_time_type::min()); } findList.insert(key); @@ -117,7 +160,8 @@ coro AssetsManager::recheckResources(Assets } auto& findList = findedResources[type][domain]; - auto iterDomain = KeyToId[type].find(domain); + auto lock = LocalObj.lock(); + auto iterDomain = lock->KeyToId[type].find(domain); if(!fs::exists(resourcesPath) || !fs::is_directory(resourcesPath)) continue; @@ -132,20 +176,19 @@ coro AssetsManager::recheckResources(Assets if(findList.contains(key)) // Ресурс уже был найден в вышестоящей директории continue; - - else if(iterDomain != KeyToId[type].end() && iterDomain->second.contains(key)) { + else if(iterDomain != lock->KeyToId[type].end() && iterDomain->second.contains(key)) { // Ресурс уже есть, TODO: нужно проверить его изменение ResourceId_t id = iterDomain->second.at(key); - DataEntry& entry = *Table[type][id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; + DataEntry& entry = *lock->Table[type][id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; fs::file_time_type lwt = fs::last_write_time(file); - if(lwt <= entry.FileChangeTime) - continue; - - + if(lwt != entry.FileChangeTime) + // Будем считать что ресурс изменился + result.NewOrChange[type][domain].emplace_back(key, co_await loadResourceFromFile((EnumAssets) type, file), lwt); } else { // Ресурс не был известен - result.NewOrChange[type][domain].emplace_back(key, Resource("assets/null")); + fs::file_time_type lwt = fs::last_write_time(file); + result.NewOrChange[type][domain].emplace_back(key, co_await loadResourceFromFile((EnumAssets) type, file), lwt); } findList.insert(key); @@ -158,4 +201,88 @@ coro AssetsManager::recheckResources(Assets co_return result; } +AssetsManager::Out_applyResourceChange AssetsManager::applyResourceChange(const Out_recheckResources& orr) { + // Потерянные и обновлённые идентификаторы + Out_applyResourceChange result; + + // Удаляем ресурсы + /* + Удаляются только ресурсы, при этом за ними остаётся бронь на идентификатор + Уже скомпилированные зависимости к ресурсам не будут + перекомпилироваться для смены идентификатора. Если нужный ресурс + появится, то привязка останется. Новые клиенты не получат ресурс + которого нет, но он может использоваться + */ + for(int type = 0; type < (int) EnumAssets::MAX_ENUM; type++) { + for(auto& [domain, resources] : orr.Lost[type]) { + auto lock = LocalObj.lock(); + auto& keyToIdDomain = lock->KeyToId[type].at(domain); + + for(const std::string& key : resources) { + auto iter = keyToIdDomain.find(key); + assert(iter != keyToIdDomain.end()); + + ResourceId_t resId = iter->second; + // keyToIdDomain.erase(iter); + // lost[type].push_back(resId); + + uint32_t localId = resId % TableEntry::ChunkSize; + auto& chunk = lock->Table[type][resId / TableEntry::ChunkSize]; + // chunk->IsFull = false; + // chunk->Empty.set(localId); + chunk->Entries[localId].reset(); + } + } + } + + // Добавляем + for(int type = 0; type < (int) EnumAssets::MAX_ENUM; type++) { + for(auto& [domain, resources] : orr.NewOrChange[type]) { + auto lock = LocalObj.lock(); + auto& keyToIdDomain = lock->KeyToId[type][domain]; + + for(auto& [key, resource, lwt] : resources) { + ResourceId_t id = -1; + std::optional* data = nullptr; + + if(auto iterId = keyToIdDomain.find(key); iterId != keyToIdDomain.end()) { + id = iterId->second; + data = &lock->Table[(int) type][id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; + } else { + auto [_id, _data] = lock->nextId((EnumAssets) type); + id = _id; + data = &_data; + } + + result.NewOrChange[type].push_back({id, resource}); + keyToIdDomain[key] = id; + + data->emplace(lwt, resource); + } + } + + // Удалённые идентификаторы не считаются удалёнными, если были изменены + std::unordered_set noc(result.NewOrChange[type].begin(), result.NewOrChange[type].end()); + 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])); + } + + return result; +} + +ResourceId_t 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 70aba5c..df053a0 100644 --- a/Src/Server/AssetsManager.hpp +++ b/Src/Server/AssetsManager.hpp @@ -2,6 +2,7 @@ #include "Abstract.hpp" #include "Common/Abstract.hpp" +#include "TOSLib.hpp" #include "boost/asio/io_context.hpp" #include "sha2.hpp" #include @@ -14,6 +15,11 @@ namespace LV::Server { namespace fs = std::filesystem; +/* + Работает с ресурсами из папок assets. + Использует папку server_cache/assets для хранения + преобразованных ресурсов +*/ class AssetsManager { public: struct Resource { @@ -64,21 +70,27 @@ private: std::array, ChunkSize> Entries; TableEntry() { - Empty.reset(); + Empty.set(); } }; - // Данные не меняются в процессе работы сервера. - // Изменения возможны при синхронизации всего сервера - // и перехода в режим перезагрузки модов + struct Local { + // Связь ресурсов по идентификаторам + std::vector> Table[(int) EnumAssets::MAX_ENUM]; + // Связь домены -> {ключ -> идентификатор} + std::unordered_map> KeyToId[(int) EnumAssets::MAX_ENUM]; + + std::tuple&> nextId(EnumAssets type); + }; - // Связь ресурсов по идентификаторам - std::vector> Table[(int) EnumAssets::MAX_ENUM]; - // Связь домены -> {ключ -> идентификатор} - std::unordered_map> KeyToId[(int) EnumAssets::MAX_ENUM]; - - DataEntry& getEntry(EnumAssets type, ResourceId_t id); + TOS::SpinlockObject LocalObj; + /* + Загрузка ресурса с файла. При необходимости приводится + к внутреннему формату и сохраняется в кеше + */ + coro loadResourceFromFile(EnumAssets type, fs::path path) const; + coro loadResourceFromLua(EnumAssets type, void*) const; public: AssetsManager(asio::io_context& ioc); @@ -111,10 +123,28 @@ public: // Потерянные ресурсы std::unordered_map> Lost[(int) EnumAssets::MAX_ENUM]; // Домен и ключ ресурса - std::unordered_map>> NewOrChange[(int) EnumAssets::MAX_ENUM]; + std::unordered_map>> NewOrChange[(int) EnumAssets::MAX_ENUM]; }; - coro recheckResources(AssetsRegister) const; + coro recheckResources(AssetsRegister); + + /* + Применяет расчитанные изменения. + Раздаёт идентификаторы ресурсам и записывает их в таблицу + */ + struct Out_applyResourceChange { + std::vector Lost[(int) EnumAssets::MAX_ENUM]; + std::vector> NewOrChange[(int) EnumAssets::MAX_ENUM]; + }; + + Out_applyResourceChange applyResourceChange(const Out_recheckResources& orr); + + + /* + Выдаёт идентификатор ресурса, даже если он не существует или был удалён. + resource должен содержать домен и путь + */ + ResourceId_t getId(EnumAssets type, const std::string& domain, const std::string& key); }; } \ No newline at end of file diff --git a/Src/Server/BinaryResourceManager.cpp b/Src/Server/BinaryResourceManager.cpp deleted file mode 100644 index fad5062..0000000 --- a/Src/Server/BinaryResourceManager.cpp +++ /dev/null @@ -1,383 +0,0 @@ -#include "Common/Abstract.hpp" -#include "Server/Abstract.hpp" -#include -#include -#define BOOST_ASIO_HAS_IO_URING 1 -#include "BinaryResourceManager.hpp" -#include -#include -#include -#include -#include -#include - - -namespace LV::Server { - -struct UriParse { - std::string Protocol, Path; - - std::string getFull() const { - return Protocol + "://" + Path; - } -}; - -UriParse parseUri(const std::string& uri) { - size_t pos = uri.find("://"); - - if(pos == std::string::npos) - return {"assets", uri}; - else - return {uri.substr(0, pos), uri.substr(pos+3)}; -} - -struct Resource { - // Файл загруженный с диска - std::shared_ptr Loaded; - // Источник - Hash_t Hash; - size_t LastUsedTime = 0; - EnumBinResource Type; - ResourceId_t ResId; - UriParse Uri; - - std::string LastError; -}; - -void BinaryResourceManager::run() { - TOS::Logger LOG = "BinaryResourceManager::run"; - LOG.debug() << "Поток чтения двоичных ресурсов запущен"; - - // Ресурсы - кешированные в оперативную память или в процессе загрузки - std::unordered_map> knownResource[(int) EnumBinResource::MAX_ENUM]; - // Трансляция идентификаторов в Uri (противоположность KnownResource) - std::vector resIdToUri[(int) EnumBinResource::MAX_ENUM]; - // Новые полученные идентификаторы и те, чьи ресурсы нужно снова загрузить - std::vector newRes[(int) EnumBinResource::MAX_ENUM]; - // Пути поиска ресурсов - std::vector assets; - // Запросы хешей - std::vector binToHash[(int) EnumBinResource::MAX_ENUM]; - // - std::unordered_map> hashToResource; - std::vector hashToLoad; - - auto lambdaLoadResource = [&](UriParse uri, int type) -> std::variant, std::string> - { - // std::shared_ptr resObj = std::make_shared(); - // knownResource[type][resId] = resObj; - - if(uri.Protocol != "assets") - return "Протокол не поддерживается"; - else { - auto var = loadFile(assets, uri.Path, (EnumBinResource) type); - - if(var.index() == 0) { - std::shared_ptr resource = std::get<0>(var); - resource = convertFormate(resource, (EnumBinResource) type); - resource->calcHash(); - return resource; - } else { - return std::get<1>(var); - } - } - }; - - try { - while(!NeedShutdown) { - bool hasWork = false; - auto lock = Local.lock(); - - for(int type = 0; type < (int) EnumBinResource::MAX_ENUM; type++) { - for(ResourceId_t iter = 0; iter < lock->ResIdToUri[type].size(); iter++) { - newRes[type].push_back(resIdToUri[type].size()+iter); - } - - resIdToUri[type].insert(resIdToUri[type].end(), lock->ResIdToUri[type].begin(), lock->ResIdToUri[type].end()); - resIdToUri[type].clear(); - - binToHash[type].insert(binToHash[type].end(), lock->BinToHash[type].begin(), lock->BinToHash[type].end()); - lock->BinToHash[type].clear(); - } - - bool assetsUpdate = false; - if(!lock->Assets.empty()) { - // Требуется пересмотр всех ресурсов - assets = std::move(lock->Assets); - assetsUpdate = true; - } - - std::vector hashRequest = std::move(lock->Hashes); - - lock.unlock(); - - if(!hashRequest.empty()) { - std::vector> hashToResourceOut; - - for(Hash_t hash : hashRequest) { - auto iter = hashToResource.find(hash); - - if(iter == hashToResource.end()) - continue; - - if(!iter->second->Loaded) { - hashToLoad.push_back(hash); - continue; - } - - iter->second->LastUsedTime = TOS::Time::getSeconds(); - hashToResourceOut.push_back(iter->second->Loaded); - } - - auto outLock = Out.lock(); - outLock->HashToResource.insert(outLock->HashToResource.end(), hashToResourceOut.begin(), hashToResourceOut.end()); - } - - { - std::unordered_map binToHashOut[(int) EnumBinResource::MAX_ENUM]; - - for(int type = 0; type < (int) EnumBinResource::MAX_ENUM; type++) { - for(ResourceId_t resId : binToHash[type]) { - std::shared_ptr resource = knownResource[type][resId]; - if(!resource) - continue; // Идентификатор не известен - - binToHashOut[type][resId] = resource->Hash; - } - } - } - - // Загрузка ресурсов по новым идентификаторам - for(int type = 0; type < (int) EnumBinResource::MAX_ENUM; type++) { - if(newRes[type].empty()) - continue; - - hasWork = true; - - while(!newRes[type].empty()) { - ResourceId_t resId = newRes[type].back(); - newRes[type].pop_back(); - - assert(resId < resIdToUri[type].size()); - UriParse uri = parseUri(resIdToUri[type][resId]); - std::shared_ptr resObj = std::make_shared(); - resObj->LastUsedTime = TOS::Time::getSeconds(); - resObj->Type = (EnumBinResource) type; - resObj->ResId = resId; - resObj->Uri = uri; - - auto var = lambdaLoadResource(uri, type); - - if(var.index() == 0) { - resObj->Loaded = std::get<0>(var); - resObj->Hash = resObj->Loaded->Hash; - hashToResource[resObj->Hash] = resObj; - } else { - std::fill(resObj->Hash.begin(), resObj->Hash.end(), 0); - resObj->LastError = std::get<1>(var); - } - - knownResource[type][resId] = resObj; - } - } - - while(!hashToLoad.empty()) { - Hash_t hash = hashToLoad.back(); - hashToLoad.pop_back(); - - auto iter = hashToResource.find(hash); - if(iter == hashToResource.end()) - continue; - - std::shared_ptr &res = iter->second; - - if(res->Loaded) { - Out.lock()->HashToResource.push_back(res->Loaded); - } else { - if(!res->LastError.empty()) - continue; - - auto var = lambdaLoadResource(res->Uri, (int) res->Type); - if(var.index() == 0) { - hasWork = true; - res->Loaded = std::get<0>(var); - res->LastUsedTime = TOS::Time::getSeconds(); - res->LastError.clear(); - - if(res->Hash != res->Loaded->Hash) { - // Хеш изменился - Out.lock()->BinToHash[(int) res->Type][res->ResId] = res->Loaded->Hash; - res->Hash = res->Loaded->Hash; - std::shared_ptr resObj = res; - hashToResource.erase(iter); - hashToResource[hash] = resObj; - } else { - Out.lock()->HashToResource.push_back(res->Loaded); - } - } else { - res->LastError = std::get<1>(var); - } - } - } - - // Удаляем долго не используемые ресурсы - { - size_t now = TOS::Time::getSeconds(); - for(int type = 0; type < (int) EnumBinResource::MAX_ENUM; type++) { - for(auto& resObj : knownResource[type]) { - if(now - resObj.second->LastUsedTime > 30) - resObj.second->Loaded = nullptr; - } - } - } - - if(assetsUpdate) { - hashToLoad.clear(); - hashToResource.clear(); - - for(int type = 0; type < (int) EnumBinResource::MAX_ENUM; type++) { - for(auto& [resId, resObj] : knownResource[type]) { - auto var = lambdaLoadResource(resObj->Uri, type); - - if(var.index() == 0) { - hasWork = true; - resObj->Loaded = std::get<0>(var); - resObj->LastUsedTime = TOS::Time::getSeconds(); - resObj->LastError.clear(); - - if(resObj->Hash != resObj->Loaded->Hash) { - // Хеш изменился - Out.lock()->BinToHash[type][resId] = resObj->Loaded->Hash; - resObj->Hash = resObj->Loaded->Hash; - } - - hashToResource[resObj->Hash] = resObj; - } else { - resObj->LastError = std::get<1>(var); - } - } - } - } - - if(!hasWork) - TOS::Time::sleep3(10); - } - } catch(const std::exception& exc) { - LOG.error() << exc.what(); - } - - NeedShutdown = true; - LOG.debug() << "Поток чтения двоичных ресурсов остановлен"; -} - -std::variant, std::string> -BinaryResourceManager::loadFile(const std::vector& assets, const std::string& path, EnumBinResource type) -{ - try { - std::shared_ptr file = std::make_shared(); - - std::string firstPath; - - switch(type) { - case EnumBinResource::Texture: firstPath = "texture"; break; - case EnumBinResource::Animation: firstPath = "animation"; break; - case EnumBinResource::Model: firstPath = "model"; break; - case EnumBinResource::Sound: firstPath = "sound"; break; - case EnumBinResource::Font: firstPath = "font"; break; - default: assert(false); - } - - for(fs::path assetsPath : assets) { - fs::path p = assetsPath / firstPath / path; - if(!fs::exists(p)) - continue; - - std::ifstream fd(p); - - if(!fd) - MAKE_ERROR("Не удалось открыть файл: " << p.string()); - - fd.seekg(0, std::ios::end); - std::streamsize size = fd.tellg(); - fd.seekg(0, std::ios::beg); - file->Data.resize(size); - fd.read((char*) file->Data.data(), size); - - return file; - } - - MAKE_ERROR("Файл не найден"); - } catch(const std::exception& exc) { - return exc.what(); - } -} - -std::shared_ptr convertFormate(std::shared_ptr file, EnumBinResource type) { - return file; -} - -BinaryResourceManager::BinaryResourceManager(asio::io_context &ioc) - : AsyncObject(ioc), Thread(&BinaryResourceManager::run, this) -{ -} - -BinaryResourceManager::~BinaryResourceManager() { - NeedShutdown = true; - Thread.join(); -} - -void BinaryResourceManager::recheckResources(std::vector assets /* Пути до активных папок assets */) { - -} - -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()); - } - - lock->Hashes.insert(lock->Hashes.end(), resources.Hashes.begin(), resources.Hashes.end()); -} - -void BinaryResourceManager::update(float dtime) { - // 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 iterRI = ResourcesInfo.find(resId); - // if(iterRI != ResourcesInfo.end()) { - // PreparedInformation[resId] = iterRI->second->Loaded; - // } - // } -} - -// 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); -// } - -} \ No newline at end of file diff --git a/Src/Server/BinaryResourceManager.hpp b/Src/Server/BinaryResourceManager.hpp deleted file mode 100644 index 3ae7712..0000000 --- a/Src/Server/BinaryResourceManager.hpp +++ /dev/null @@ -1,153 +0,0 @@ -#pragma once - -#include "Common/Abstract.hpp" -#include "Common/Lockable.hpp" -#include "Server/RemoteClient.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include "Abstract.hpp" -#include "TOSLib.hpp" - - -namespace LV::Server { - -namespace fs = std::filesystem; - -/* - Может прийти множество запросов на один не загруженный ресурс - - Чтение происходит отдельным потоком, переконвертацию пока предлагаю в realtime. - Хэш вычисляется после чтения и может быть иным чем при прошлом чтении (ресурс изменили наживую) - тогда обычным оповещением клиентам дойдёт новая версия - - Подержать какое-то время ресурс в памяти - - - - Ключи сопоставляются с идентификаторами и с хешеми. При появлении нового ключа, - ему выдаётся идентификатор и делается запрос на загрузку ресурса для вычисления хеша. - recheckResources делает повторную загрузку всех ресурсов для проверки изменения хешей. - - -*/ - -class BinaryResourceManager : public AsyncObject { -private: - -// Поток сервера - // Последовательная регистрация ресурсов - ResourceId_t NextId[(int) EnumAssets::MAX_ENUM] = {0}; - // Известные ресурсы, им присвоен идентификатор - // Нужно для потока загрузки - std::unordered_map KnownResource[(int) EnumBinResource::MAX_ENUM]; - -// Местные потоки - struct LocalObj_t { - // Трансляция идентификаторов в Uri (противоположность KnownResource) - // Передаётся в отдельный поток - std::vector ResIdToUri[(int) EnumBinResource::MAX_ENUM]; - // Кому-то нужно сопоставить идентификаторы с хешами - std::vector BinToHash[(int) EnumBinResource::MAX_ENUM]; - // Запрос ресурсов, по которым потоки загружают ресурсы с диска - std::vector Hashes; - // Передача новых путей поиска ресурсов в другой поток - std::vector Assets; - }; - - TOS::SpinlockObject Local; -public: - // Подготовленные оповещения о ресурсах - struct OutObj_t { - std::unordered_map BinToHash[(int) EnumBinResource::MAX_ENUM]; - std::vector> HashToResource; - }; - -private: - TOS::SpinlockObject Out; - volatile bool NeedShutdown = false; - std::thread Thread; - - void run(); - std::variant, std::string> - loadFile(const std::vector& assets, const std::string& path, EnumBinResource type); - std::shared_ptr convertFormate(std::shared_ptr file, EnumBinResource type); - -public: - // Если ресурс будет обновлён или загружен будет вызвано onResourceUpdate - BinaryResourceManager(asio::io_context &ioc); - virtual ~BinaryResourceManager(); - - // Перепроверка изменений ресурсов - void recheckResources(std::vector assets /* Пути до активных папок assets */); - // Выдаёт или назначает идентификатор для ресурса - ResourceId_t getResource(const std::string& uri, EnumBinResource bin) { - std::string fullUri; - - { - size_t pos = uri.find("://"); - - if(pos == std::string::npos) - fullUri = "assets://" + uri; - else - fullUri = uri; - } - - 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}); - - auto lock = Local.lock(); - lock->ResIdToUri[index].push_back(uri); - - 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); - - // Получение обновлений или оповещений ресурсов - OutObj_t takePreparedInformation() { - return std::move(*Out.lock()); - } - - // Серверный такт - void update(float dtime); - -}; - - -} \ No newline at end of file diff --git a/Src/Server/GameServer.hpp b/Src/Server/GameServer.hpp index 6c90f95..df54169 100644 --- a/Src/Server/GameServer.hpp +++ b/Src/Server/GameServer.hpp @@ -1,5 +1,6 @@ #pragma once +#include "Server/AssetsManager.hpp" #define SOL_EXCEPTIONS_SAFE_PROPAGATION 1 #include @@ -23,7 +24,7 @@ #include "ContentEventController.hpp" #include "WorldDefManager.hpp" -#include "BinaryResourceManager.hpp" +#include "AssetsManager.hpp" #include "World.hpp" #include "SaveBackend.hpp" @@ -71,7 +72,7 @@ class GameServer : public AsyncObject { struct ContentObj { public: - BinaryResourceManager BRM; + AssetsManager AM; ResourceId_t NextId[(int) EnumDefContent::MAX_ENUM] = {0}; std::unordered_map ContentKeyToId[(int) EnumDefContent::MAX_ENUM]; // EnumDefContent @@ -117,7 +118,7 @@ class GameServer : public AsyncObject { ContentObj(asio::io_context& ioc) - : BRM(ioc) + : AM(ioc) {} } Content;