From cfbbfa286a13964acd9725f318d5ddf4d2e2c082 Mon Sep 17 00:00:00 2001 From: DrSocalkwe3n Date: Wed, 27 Aug 2025 00:26:11 +0600 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B4=D0=B0=D1=87?= =?UTF-8?q?=D0=B0=20=D1=80=D0=B5=D1=81=D1=83=D1=80=D1=81=D0=BE=D0=B2=20?= =?UTF-8?q?=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD=D1=82=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Src/Client/Abstract.hpp | 31 ++++--- Src/Client/AssetsManager.cpp | 19 ++-- Src/Client/AssetsManager.hpp | 13 +-- Src/Client/ServerSession.cpp | 112 +++++++++++++++--------- Src/Client/ServerSession.hpp | 163 +++++++++++++++++++++-------------- Src/Client/Vulkan/Vulkan.cpp | 3 +- Src/Client/Vulkan/Vulkan.hpp | 2 +- Src/Common/Abstract.hpp | 2 - Src/Server/RemoteClient.cpp | 48 ++++++++++- Src/Server/RemoteClient.hpp | 2 + Src/TOSAsync.hpp | 48 ++++++----- Src/assets.cpp | 40 ++++----- Src/assets.hpp | 18 ++-- Src/main.cpp | 2 - 14 files changed, 313 insertions(+), 190 deletions(-) diff --git a/Src/Client/Abstract.hpp b/Src/Client/Abstract.hpp index a8c0f36..60491fd 100644 --- a/Src/Client/Abstract.hpp +++ b/Src/Client/Abstract.hpp @@ -136,23 +136,34 @@ struct DefNode_t {}; /* Интерфейс обработчика сессии с сервером */ class IServerSession { - struct ArrayHasher { - std::size_t operator()(const Hash_t& a) const { - std::size_t h = 0; - for (auto e : a) - h ^= std::hash{}(e) + 0x9e3779b9 + (h << 6) + (h >> 2); + // struct ArrayHasher { + // std::size_t operator()(const Hash_t& a) const { + // std::size_t h = 0; + // for (auto e : a) + // h ^= std::hash{}(e) + 0x9e3779b9 + (h << 6) + (h >> 2); - return h; - } - }; + // return h; + // } + // }; public: + struct AssetEntry { + EnumAssets Type; + ResourceId Id; + std::string Domain, Key; + Resource Res; + }; + + static constexpr uint64_t TIME_BEFORE_UNLOAD_RESOURCE = 180; struct { - std::unordered_map Resources; + // Оперируемые ресурсы + std::unordered_map Assets; + // Недавно использованные ресурсы, пока хранятся здесь в течении TIME_BEFORE_UNLOAD_RESOURCE секунд + std::unordered_map> NotInUseAssets; } Binary; struct { - std::unordered_map DefVoxel; + std::unordered_map DefVoxel; std::unordered_map DefNode; std::unordered_map DefWorld; std::unordered_map DefPortal; diff --git a/Src/Client/AssetsManager.cpp b/Src/Client/AssetsManager.cpp index 6f48acc..ad59e33 100644 --- a/Src/Client/AssetsManager.cpp +++ b/Src/Client/AssetsManager.cpp @@ -1,10 +1,12 @@ #include "AssetsManager.hpp" #include "Common/Abstract.hpp" #include "sqlite3.h" +#include #include #include #include #include +#include #include @@ -114,7 +116,7 @@ AssetsManager::AssetsManager(boost::asio::io_context &ioc, const fs::path &cache } sql = R"( - SELECT data inline_cache where sha256=?; + SELECT data FROM inline_cache where sha256=?; )"; if(sqlite3_prepare_v2(DB, sql, -1, &STMT_INLINE_GET, nullptr) != SQLITE_OK) { @@ -157,16 +159,21 @@ AssetsManager::~AssetsManager() { STMT_DISK_INSERT, STMT_DISK_UPDATE_TIME, STMT_DISK_REMOVE, STMT_DISK_CONTAINS, STMT_DISK_SUM, STMT_DISK_COUNT, STMT_INLINE_INSERT, STMT_INLINE_GET, STMT_INLINE_UPDATE_TIME, STMT_INLINE_SUM, STMT_INLINE_COUNT - }) + }) { if(stmt) sqlite3_finalize(stmt); + } if(DB) sqlite3_close(DB); + + OffThread.join(); + + LOG.info() << "Хранилище кеша закрыто"; } coro<> AssetsManager::asyncDestructor() { - assert(NeedShutdown); // Должен быть вызван нормальный shutdown + NeedShutdown = true; co_await IAsyncDestructible::asyncDestructor(); } @@ -175,7 +182,7 @@ void AssetsManager::readWriteThread(AsyncUseControl::Lock lock) { std::vector assets; size_t maxCacheDatabaseSize, maxLifeTime; - while(!NeedShutdown && !WriteQueue.get_read().empty()) { + while(!NeedShutdown || !WriteQueue.get_read().empty()) { // Получить новые данные if(Changes.get_read().AssetsChange) { auto lock = Changes.lock(); @@ -377,9 +384,11 @@ void AssetsManager::readWriteThread(AsyncUseControl::Lock lock) { continue; } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); } } catch(const std::exception& exc) { - LOG.warn() << "Ошибка в работе потока: " << exc.what(); + LOG.warn() << "Ошибка в работе потока:\n" << exc.what(); IssuedAnError = true; } } diff --git a/Src/Client/AssetsManager.hpp b/Src/Client/AssetsManager.hpp index 8492ac7..8e78539 100644 --- a/Src/Client/AssetsManager.hpp +++ b/Src/Client/AssetsManager.hpp @@ -146,17 +146,6 @@ public: lock->FullRecheck = true; } - // Уведомление о завершении работы - void prepareShutdown() { - NeedShutdown = true; - } - - // После этого вызова уже нельзя будет обращатся ко внешним ресурсам - void shutdown() { - assert(NeedShutdown); - OffThread.join(); - } - bool hasError() { return IssuedAnError; } @@ -208,7 +197,7 @@ private: bool NeedShutdown = false, IssuedAnError = false; std::thread OffThread; - + virtual coro<> asyncDestructor(); AssetsManager(boost::asio::io_context &ioc, const fs::path &cachePath, size_t maxCacheDatabaseSize, size_t maxLifeTime); diff --git a/Src/Client/ServerSession.cpp b/Src/Client/ServerSession.cpp index 57729ef..9a6de8d 100644 --- a/Src/Client/ServerSession.cpp +++ b/Src/Client/ServerSession.cpp @@ -2,6 +2,7 @@ #include "Client/Abstract.hpp" #include "Common/Abstract.hpp" #include "Common/Net.hpp" +#include "TOSAsync.hpp" #include "TOSLib.hpp" #include "glm/ext/quaternion_geometric.hpp" #include @@ -18,6 +19,28 @@ namespace LV::Client { +ServerSession::ServerSession(asio::io_context &ioc, std::unique_ptr&& socket) + : IAsyncDestructible(ioc), Socket(std::move(socket)), NetInputPackets(1024) +{ + assert(Socket.get()); + + try { + AM = AssetsManager::Create(ioc, "Cache"); + asio::co_spawn(ioc, run(AUC.use()), asio::detached); + // TODO: добавить оптимизацию для подключения клиента к внутреннему серверу + } catch(const std::exception &exc) { + MAKE_ERROR("Ошибка инициализации обработчика объекта подключения к серверу:\n" << exc.what()); + } +} + +coro<> ServerSession::asyncDestructor() { + co_await IAsyncDestructible::asyncDestructor(); +} + + + + + ParsedPacket::~ParsedPacket() = default; struct PP_Content_ChunkVoxels : public ParsedPacket { @@ -88,20 +111,9 @@ struct PP_Definition_FreeNode : public ParsedPacket { {} }; -struct PP_Resource_InitResSend : public ParsedPacket { - Hash_t Hash; - BinaryResource Resource; - - PP_Resource_InitResSend(Hash_t hash, BinaryResource res) - : ParsedPacket(ToClient::L1::Resource, (uint8_t) ToClient::L2Resource::InitResSend), Hash(hash), Resource(res) - {} -}; - using namespace TOS; ServerSession::~ServerSession() { - WorkDeadline.cancel(); - UseLock.wait_no_use(); } coro<> ServerSession::asyncAuthorizeWithServer(tcp::socket &socket, const std::string username, const std::string token, int a_ar_r, std::function onProgress) { @@ -338,13 +350,6 @@ void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) { ParsedPacket *pack; while(NetInputPackets.pop(pack)) { if(pack->Level1 == ToClient::L1::Definition) { - ToClient::L2Resource l2 = ToClient::L2Resource(pack->Level2); - if(l2 == ToClient::L2Resource::InitResSend) { - PP_Resource_InitResSend &p = *dynamic_cast(pack); - - } - - } else if(pack->Level1 == ToClient::L1::Definition) { ToClient::L2Definition l2 = ToClient::L2Definition(pack->Level2); if(l2 == ToClient::L2Definition::Voxel) { @@ -471,21 +476,17 @@ void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) { } } -coro<> ServerSession::run() { - auto useLock = UseLock.lock(); +void ServerSession::setRenderSession(IRenderSession* session) { + RS = session; +} +coro<> ServerSession::run(AsyncUseControl::Lock) { try { while(!IsGoingShutdown && IsConnected) { co_await readPacket(*Socket); } } catch(const std::exception &exc) { - // if(const auto *errc = dynamic_cast(&exc); - // errc && errc->code() == boost::asio::error::operation_aborted) - // { - // co_return; - // } - - TOS::Logger("ServerSession").warn() << exc.what(); + LOG.error() << "Ошибка обработки сокета:\n" << exc.what(); } IsConnected = false; @@ -551,19 +552,33 @@ coro<> ServerSession::rP_Resource(Net::AsyncSocket &sock) { case ToClient::L2Resource::Bind: { uint32_t count = co_await sock.read(); + AsyncContext.ThisTickEntry.AssetsBinds.reserve(AsyncContext.ThisTickEntry.AssetsBinds.size()+count); + for(size_t iter = 0; iter < count; iter++) { uint8_t type = co_await sock.read(); uint32_t id = co_await sock.read(); + std::string domain, key; + domain = co_await sock.read(); + key = co_await sock.read(); Hash_t hash; co_await sock.read((std::byte*) hash.data(), hash.size()); + + AsyncContext.ThisTickEntry.AssetsBinds.emplace_back( + (EnumAssets) type, (ResourceId) id, std::move(domain), + std::move(key), hash + ); } } case ToClient::L2Resource::Lost: { uint32_t count = co_await sock.read(); + AsyncContext.ThisTickEntry.AssetsLost.reserve(AsyncContext.ThisTickEntry.AssetsLost.size()+count); + for(size_t iter = 0; iter < count; iter++) { - uint8_t type = co_await sock.read(); + // uint8_t type = co_await sock.read(); uint32_t id = co_await sock.read(); + + AsyncContext.ThisTickEntry.AssetsLost.push_back(id); } } case ToClient::L2Resource::InitResSend: @@ -571,26 +586,41 @@ coro<> ServerSession::rP_Resource(Net::AsyncSocket &sock) { uint32_t size = co_await sock.read(); Hash_t hash; co_await sock.read((std::byte*) hash.data(), hash.size()); + ResourceId id = co_await sock.read(); + EnumAssets type = (EnumAssets) co_await sock.read(); + std::string domain = co_await sock.read(); + std::string key = co_await sock.read(); - 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()); - - PP_Resource_InitResSend *packet = new PP_Resource_InitResSend( - hash, - std::make_shared(std::move(data)) - ); - - while(!NetInputPackets.push(packet)); + AsyncContext.AssetsLoading[hash] = AssetLoading{ + type, id, std::move(domain), std::move(key), + std::u8string(size, '\0'), 0 + }; co_return; } case ToClient::L2Resource::ChunkSend: + { + Hash_t hash; + co_await sock.read((std::byte*) hash.data(), hash.size()); + uint32_t size = co_await sock.read(); + AssetLoading& al = AsyncContext.AssetsLoading.at(hash); + if(al.Data.size()-al.Offset < size) + MAKE_ERROR("Несоответствие ожидаемого размера ресурса"); + + co_await sock.read((std::byte*) al.Data.data() + al.Offset, size); + al.Offset += size; + + if(al.Offset == al.Data.size()) { + // Ресурс полностью загружен + AsyncContext.LoadedAssets.lock()->emplace_back( + al.Type, al.Id, std::move(al.Domain), std::move(al.Key), std::move(al.Data) + ); + + AsyncContext.AssetsLoading.erase(AsyncContext.AssetsLoading.find(hash)); + } co_return; + } default: protocolError(); } diff --git a/Src/Client/ServerSession.hpp b/Src/Client/ServerSession.hpp index cbb5c37..be3a5bc 100644 --- a/Src/Client/ServerSession.hpp +++ b/Src/Client/ServerSession.hpp @@ -6,12 +6,15 @@ #include "Common/Lockable.hpp" #include "Common/Net.hpp" #include "Common/Packets.hpp" +#include "TOSAsync.hpp" #include #include #include #include #include -#include +#include +#include +#include namespace LV::Client { @@ -26,18 +29,100 @@ struct ParsedPacket { virtual ~ParsedPacket(); }; -class ServerSession : public AsyncObject, public IServerSession, public ISurfaceEventListener { +class ServerSession : public IAsyncDestructible, public IServerSession, public ISurfaceEventListener { +public: + using Ptr = std::shared_ptr; + +public: + static Ptr Create(asio::io_context &ioc, std::unique_ptr &&socket) { + return createShared(ioc, new ServerSession(ioc, std::move(socket))); + } + + virtual ~ServerSession(); + + // Авторизоваться или (зарегистрироваться и авторизоваться) или зарегистрироваться + static coro<> asyncAuthorizeWithServer(tcp::socket &socket, const std::string username, const std::string token, int a_ar_r, std::function onProgress = nullptr); + // Начать игровой протокол в авторизированном сокете + static coro> asyncInitGameProtocol(asio::io_context &ioc, tcp::socket &&socket, std::function onProgress = nullptr); + + void shutdown(EnumDisconnect type); + + bool isConnected() { + return Socket->isAlive() && IsConnected; + } + + // ISurfaceEventListener + + virtual void onResize(uint32_t width, uint32_t height) override; + virtual void onChangeFocusState(bool isFocused) override; + virtual void onCursorPosChange(int32_t width, int32_t height) override; + virtual void onCursorMove(float xMove, float yMove) override; + + virtual void onCursorBtn(EnumCursorBtn btn, bool state) override; + virtual void onKeyboardBtn(int btn, int state) override; + virtual void onJoystick() override; + + // IServerSession + + virtual void atFreeDrawTime(GlobalTime gTime, float dTime) override; + void setRenderSession(IRenderSession* session); + +private: + TOS::Logger LOG = "ServerSession"; + std::unique_ptr Socket; IRenderSession *RS = nullptr; // Обработчик кеша ресурсов сервера - CacheHandler::Ptr CHDB; + AssetsManager::Ptr AM; + + struct AssetLoading { + EnumAssets Type; + ResourceId Id; + std::string Domain, Key; + std::u8string Data; + size_t Offset; + }; + + struct AssetBindEntry { + EnumAssets Type; + ResourceId Id; + std::string Domain, Key; + Hash_t Hash; + }; + + struct TickData { + std::vector LostWorld; + // std::vector> + + // Потерянные из видимости ресурсы + std::vector AssetsLost; + // Новые привязки ресурсов + std::vector AssetsBinds; + }; + + struct { + // Сюда обращается ветка, обрабатывающая сокет; run() + // Получение ресурсов с сервера + std::unordered_map AssetsLoading; + // Получение привязок + + // Накопление данных за такт сервера + TickData ThisTickEntry; + + // Обменный пункт + // Привязки ресурсов + TOS::SpinlockObject> AssetsBindings; + // Полученные ресурсы с сервера + TOS::SpinlockObject> LoadedAssets; + // Пакеты обновлений игрового мира + TOS::SpinlockObject> TickSequence; + } AsyncContext; + + - DestroyLock UseLock; bool IsConnected = true, IsGoingShutdown = false; - TOS::Logger LOG = "ServerSession"; - boost::lockfree::spsc_queue NetInputPackets; // PYR - поворот камеры по осям xyz в радианах, PYR_Offset для сглаживание поворота @@ -59,70 +144,20 @@ class ServerSession : public AsyncObject, public IServerSession, public ISurface GlobalTime LastSendPYR_POS; -public: - // Нужен сокет, на котором только что был согласован игровой протокол (asyncInitGameProtocol) - ServerSession(asio::io_context &ioc, std::unique_ptr &&socket, IRenderSession *rs = nullptr) - : AsyncObject(ioc), Socket(std::move(socket)), RS(rs), NetInputPackets(1024) - { - assert(Socket.get()); - - try { - fs::create_directories("Cache"); - CHDB = CacheHandlerBasic::Create(ioc, "Cache"); - - // Отправка информации о загруженном кеше - // TODO: добавить оптимизацию для подключения клиента к внутреннему серверу - auto [data, count] = CHDB->getAll(); - Net::Packet packet; - packet << uint32_t(count); - packet.write((const std::byte*) data.data(), data.size()); - Socket->pushPacket(std::move(packet)); - } catch(const std::exception &exc) { - MAKE_ERROR("Ошибка инициализации обработчика кеша ресурсов сервера:\n" << exc.what()); - } - - co_spawn(run()); - } - - virtual ~ServerSession(); - - // Авторизоваться или (зарегистрироваться и авторизоваться) или зарегистрироваться - static coro<> asyncAuthorizeWithServer(tcp::socket &socket, const std::string username, const std::string token, int a_ar_r, std::function onProgress = nullptr); - // Начать игровой протокол в авторизированном сокете - static coro> asyncInitGameProtocol(asio::io_context &ioc, tcp::socket &&socket, std::function onProgress = nullptr); - - void shutdown(EnumDisconnect type); - - bool isConnected() { - return Socket->isAlive() && IsConnected; - } - - void waitShutdown() { - UseLock.wait_no_use(); - } - - - // ISurfaceEventListener - - virtual void onResize(uint32_t width, uint32_t height) override; - virtual void onChangeFocusState(bool isFocused) override; - virtual void onCursorPosChange(int32_t width, int32_t height) override; - virtual void onCursorMove(float xMove, float yMove) override; - - virtual void onCursorBtn(EnumCursorBtn btn, bool state) override; - virtual void onKeyboardBtn(int btn, int state) override; - virtual void onJoystick() override; - - virtual void atFreeDrawTime(GlobalTime gTime, float dTime) override; - -private: - coro<> run(); + // Приём данных с сокета + coro<> run(AsyncUseControl::Lock); void protocolError(); coro<> readPacket(Net::AsyncSocket &sock); coro<> rP_System(Net::AsyncSocket &sock); coro<> rP_Resource(Net::AsyncSocket &sock); coro<> rP_Definition(Net::AsyncSocket &sock); coro<> rP_Content(Net::AsyncSocket &sock); + + + // Нужен сокет, на котором только что был согласован игровой протокол (asyncInitGameProtocol) + ServerSession(asio::io_context &ioc, std::unique_ptr &&socket); + + virtual coro<> asyncDestructor() override; }; } \ No newline at end of file diff --git a/Src/Client/Vulkan/Vulkan.cpp b/Src/Client/Vulkan/Vulkan.cpp index 2f988b7..a491183 100644 --- a/Src/Client/Vulkan/Vulkan.cpp +++ b/Src/Client/Vulkan/Vulkan.cpp @@ -2215,7 +2215,8 @@ void Vulkan::gui_MainMenu() { std::unique_ptr sock = std::move(ConnectionProgress.Socket); Game.RSession = std::make_unique(); *this << Game.RSession; - Game.Session = std::make_unique(IOC, std::move(sock), Game.RSession.get()); + Game.Session = ServerSession::Create(IOC, std::move(sock)); + Game.Session->setRenderSession(Game.RSession.get()); Game.RSession->setServerSession(Game.Session.get()); Game.ImGuiInterfaces.push_back(&Vulkan::gui_ConnectedToServer); } diff --git a/Src/Client/Vulkan/Vulkan.hpp b/Src/Client/Vulkan/Vulkan.hpp index 62a732f..955322b 100644 --- a/Src/Client/Vulkan/Vulkan.hpp +++ b/Src/Client/Vulkan/Vulkan.hpp @@ -250,7 +250,7 @@ public: DestroyLock UseLock; std::thread MainThread; std::shared_ptr RSession; - std::unique_ptr Session; + ServerSession::Ptr Session; std::list ImGuiInterfaces; std::unique_ptr Server; diff --git a/Src/Common/Abstract.hpp b/Src/Common/Abstract.hpp index 5116c68..e0b1a01 100644 --- a/Src/Common/Abstract.hpp +++ b/Src/Common/Abstract.hpp @@ -411,8 +411,6 @@ using AssetsTexture = ResourceId; using AssetsSound = ResourceId; using AssetsFont = ResourceId; -using BinaryResource = std::shared_ptr; - /* Определения контента, доставляются клиентам сразу */ diff --git a/Src/Server/RemoteClient.cpp b/Src/Server/RemoteClient.cpp index d8bfe28..2e23f22 100644 --- a/Src/Server/RemoteClient.cpp +++ b/Src/Server/RemoteClient.cpp @@ -487,6 +487,10 @@ ResourceRequest RemoteClient::pushPreparedPackets() { nextRequest = std::move(lock->NextRequest); } + if(AssetsInWork.AssetsPacket.size()) { + toSend.push_back(std::move(AssetsInWork.AssetsPacket)); + } + Socket.pushPackets(&toSend); toSend.clear(); @@ -759,7 +763,7 @@ void RemoteClient::NetworkAndResource_t::decrementAssets(ResUses_t::RefAssets_t& << uint32_t(lost.size()); for(auto& [type, id] : lost) - NextPacket << uint8_t(type) << uint32_t(id); + NextPacket /* << uint8_t(type)*/ << uint32_t(id); } } @@ -795,6 +799,48 @@ void RemoteClient::onUpdate() { } LastPos = cameraPos; + + // Отправка ресурсов + if(!AssetsInWork.ToSend.empty()) { + auto& toSend = AssetsInWork.ToSend; + size_t chunkSize = std::max(1'024'000 / toSend.size(), 4096); + + Net::Packet& p = AssetsInWork.AssetsPacket; + + bool hasFullSended = false; + + for(auto& [type, domain, key, id, res, sended] : toSend) { + if(sended == 0) { + // Оповещаем о начале отправки ресурса + p << (uint8_t) ToClient::L1::Resource + << (uint8_t) ToClient::L2Resource::InitResSend + << uint32_t(res.size()); + p.write((const std::byte*) res.hash().data(), 32); + p << uint32_t(id) << uint8_t(type) << domain << key; + } + + // Отправляем чанк + size_t willSend = std::min(chunkSize, res.size()-sended); + p << (uint8_t) ToClient::L1::Resource + << (uint8_t) ToClient::L2Resource::ChunkSend; + p.write((const std::byte*) res.hash().data(), 32); + p << uint32_t(willSend); + p.write(res.data() + sended, willSend); + sended += willSend; + + if(sended == willSend) { + hasFullSended = true; + } + } + + if(hasFullSended) { + for(ssize_t iter = toSend.size()-1; iter > 0; iter--) { + if(std::get<4>(toSend[iter]).size() == std::get<5>(toSend[iter])) { + toSend.erase(toSend.begin()+iter); + } + } + } + } } std::vector> RemoteClient::getViewPoints() { diff --git a/Src/Server/RemoteClient.hpp b/Src/Server/RemoteClient.hpp index 0c4ac70..f7f6fdb 100644 --- a/Src/Server/RemoteClient.hpp +++ b/Src/Server/RemoteClient.hpp @@ -313,6 +313,8 @@ class RemoteClient { // Отправляемые на клиент ресурсы // Тип, домен, ключ, идентификатор, ресурс, количество отправленных байт std::vector> ToSend; + // Пакет с ресурсами + Net::Packet AssetsPacket; } AssetsInWork; TOS::SpinlockObject NetworkAndResource; diff --git a/Src/TOSAsync.hpp b/Src/TOSAsync.hpp index 7e92baf..d0e003b 100644 --- a/Src/TOSAsync.hpp +++ b/Src/TOSAsync.hpp @@ -227,12 +227,13 @@ protected: template> static std::shared_ptr createShared(asio::io_context &ioc, T *ptr) { - return std::shared_ptr(ptr, [&ioc = ioc](T *ptr) { - boost::asio::co_spawn(ioc, [&ioc = ioc](IAsyncDestructible *ptr) -> coro<> { - try { co_await ptr->asyncDestructor(); } catch(...) { } - delete ptr; - co_return; - } (ptr), boost::asio::detached); + return std::shared_ptr(ptr, [&ioc](T *ptr) { + boost::asio::co_spawn(ioc, + [ptr, &ioc]() mutable -> coro<> { + try { co_await dynamic_cast(ptr)->asyncDestructor(); } catch(...) { } + asio::post(ioc, [ptr](){ delete ptr; }); + }, + boost::asio::detached); }); } @@ -240,23 +241,25 @@ protected: static coro> createShared(T *ptr) { co_return std::shared_ptr(ptr, [ioc = asio::get_associated_executor(co_await asio::this_coro::executor)](T *ptr) { - boost::asio::co_spawn(ioc, [](IAsyncDestructible *ptr) -> coro<> { - try { co_await ptr->asyncDestructor(); } catch(...) { } - delete ptr; - co_return; - } (ptr), boost::asio::detached); + boost::asio::co_spawn(ioc, + [ptr, &ioc]() mutable -> coro<> { + try { co_await dynamic_cast(ptr)->asyncDestructor(); } catch(...) { } + asio::post(ioc, [ptr](){ delete ptr; }); + }, + boost::asio::detached); }); } template> static std::unique_ptr> createUnique(asio::io_context &ioc, T *ptr) { - return std::unique_ptr>(ptr, [&ioc = ioc](T *ptr) { - boost::asio::co_spawn(ioc, [](IAsyncDestructible *ptr) -> coro<> { - try { co_await ptr->asyncDestructor(); } catch(...) { } - delete ptr; - co_return; - } (ptr), boost::asio::detached); + return std::unique_ptr>(ptr, [&ioc](T *ptr) { + boost::asio::co_spawn(ioc, + [ptr, &ioc]() mutable -> coro<> { + try { co_await dynamic_cast(ptr)->asyncDestructor(); } catch(...) { } + asio::post(ioc, [ptr](){ delete ptr; }); + }, + boost::asio::detached); }); } @@ -264,11 +267,12 @@ protected: static coro>> createUnique(T *ptr) { co_return std::unique_ptr>(ptr, [ioc = asio::get_associated_executor(co_await asio::this_coro::executor)](T *ptr) { - boost::asio::co_spawn(ioc, [](IAsyncDestructible *ptr) -> coro<> { - try { co_await ptr->asyncDestructor(); } catch(...) { } - delete ptr; - co_return; - } (ptr), boost::asio::detached); + boost::asio::co_spawn(ioc, + [ptr, &ioc]() mutable -> coro<> { + try { co_await dynamic_cast(ptr)->asyncDestructor(); } catch(...) { } + asio::post(ioc, [ptr](){ delete ptr; }); + }, + boost::asio::detached); }); } }; diff --git a/Src/assets.cpp b/Src/assets.cpp index 06d9fa0..32bf901 100644 --- a/Src/assets.cpp +++ b/Src/assets.cpp @@ -11,17 +11,17 @@ namespace fs = std::filesystem; namespace LV { -Resource::Resource() = default; -Resource::~Resource() = default; +iResource::iResource() = default; +iResource::~iResource() = default; -static std::mutex ResourceCacheMtx; -static std::unordered_map> ResourceCache; +static std::mutex iResourceCacheMtx; +static std::unordered_map> iResourceCache; -class FS_Resource : public Resource { +class FS_iResource : public iResource { boost::scoped_array Array; public: - FS_Resource(const std::filesystem::path &path) + FS_iResource(const std::filesystem::path &path) { std::ifstream fd(path); @@ -36,18 +36,18 @@ public: Data = Array.get(); } - virtual ~FS_Resource() = default; + virtual ~FS_iResource() = default; }; -std::shared_ptr getResource(const std::string &path) { - std::unique_lock lock(ResourceCacheMtx); +std::shared_ptr getResource(const std::string &path) { + std::unique_lock lock(iResourceCacheMtx); - if(auto iter = ResourceCache.find(path); iter != ResourceCache.end()) { - std::shared_ptr resource = iter->second.lock(); - if(!resource) { - ResourceCache.erase(iter); + if(auto iter = iResourceCache.find(path); iter != iResourceCache.end()) { + std::shared_ptr iResource = iter->second.lock(); + if(!iResource) { + iResourceCache.erase(iter); } else { - return resource; + return iResource; } } @@ -55,15 +55,15 @@ std::shared_ptr getResource(const std::string &path) { fs_path /= path; if(fs::exists(fs_path)) { - std::shared_ptr resource = std::make_shared(fs_path); - ResourceCache.emplace(path, resource); - TOS::Logger("Resources").debug() << "Ресурс " << fs_path << " найден в фс"; - return resource; + std::shared_ptr iResource = std::make_shared(fs_path); + iResourceCache.emplace(path, iResource); + TOS::Logger("iResources").debug() << "Ресурс " << fs_path << " найден в фс"; + return iResource; } if(auto iter = _binary_assets_symbols.find(path); iter != _binary_assets_symbols.end()) { - TOS::Logger("Resources").debug() << "Ресурс " << fs_path << " is inlined"; - return std::make_shared((const uint8_t*) std::get<0>(iter->second), std::get<1>(iter->second)-std::get<0>(iter->second)); + TOS::Logger("iResources").debug() << "Ресурс " << fs_path << " is inlined"; + return std::make_shared((const uint8_t*) std::get<0>(iter->second), std::get<1>(iter->second)-std::get<0>(iter->second)); } MAKE_ERROR("Ресурс " << path << " не найден"); diff --git a/Src/assets.hpp b/Src/assets.hpp index b2bc5f5..0bb288b 100644 --- a/Src/assets.hpp +++ b/Src/assets.hpp @@ -22,24 +22,24 @@ struct iBinaryStream : detail::membuf { }; -class Resource { +class iResource { protected: const uint8_t* Data; size_t Size; public: - Resource(); - Resource(const uint8_t* data, size_t size) + iResource(); + iResource(const uint8_t* data, size_t size) : Data(data), Size(size) {} - virtual ~Resource(); + virtual ~iResource(); - Resource(const Resource&) = delete; - Resource(Resource&&) = delete; - Resource& operator=(const Resource&) = delete; - Resource& operator=(Resource&&) = delete; + iResource(const iResource&) = delete; + iResource(iResource&&) = delete; + iResource& operator=(const iResource&) = delete; + iResource& operator=(iResource&&) = delete; const uint8_t* getData() const { return Data; } size_t getSize() const { return Size; } @@ -49,6 +49,6 @@ public: }; -std::shared_ptr getResource(const std::string &path); +std::shared_ptr getResource(const std::string &path); } \ No newline at end of file diff --git a/Src/main.cpp b/Src/main.cpp index 657bba3..658dbb0 100644 --- a/Src/main.cpp +++ b/Src/main.cpp @@ -4,8 +4,6 @@ #include #include -#include - namespace LV { /*