diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c20b69..71998c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,7 +67,7 @@ set(Boost_USE_STATIC_LIBS ON) set(BOOST_INCLUDE_LIBRARIES asio thread json) set(BOOST_ENABLE_CMAKE ON) set(BOOST_IOSTREAMS_ENABLE_ZLIB ON) -set(BOOST_INCLUDE_LIBRARIES asio thread json iostreams) +set(BOOST_INCLUDE_LIBRARIES asio thread json iostreams interprocess) FetchContent_Declare( Boost GIT_REPOSITORY https://github.com/boostorg/boost.git @@ -76,7 +76,7 @@ FetchContent_Declare( USES_TERMINAL_DOWNLOAD true ) FetchContent_MakeAvailable(Boost) -target_link_libraries(luavox_common INTERFACE Boost::asio Boost::thread Boost::json Boost::iostreams) +target_link_libraries(luavox_common INTERFACE Boost::asio Boost::thread Boost::json Boost::iostreams Boost::interprocess) # glm # find_package(glm REQUIRED) diff --git a/Src/Common/Abstract.hpp b/Src/Common/Abstract.hpp index 91f891f..e78df9d 100644 --- a/Src/Common/Abstract.hpp +++ b/Src/Common/Abstract.hpp @@ -388,27 +388,34 @@ struct Object_t { using ResourceId_t = uint32_t; /* - Bin привязывается к путю. Если по путю обновляется объект, пересчитывается его кеш и на клиентах обновляется -*/ + Объекты, собранные из папки assets или зарегистрированные модами. + Клиент получает полную информацию о таких объектах и при надобности + запрашивает получение файла. + Id -> Key + SHA256 -enum class EnumBinResource { - Texture, Animation, Model, Sound, Font, MAX_ENUM + Если объекты удаляются, то сторона клиента об этом не уведомляется +*/ +enum class EnumAssets { + Nodestate, Patricle, Animation, Model, Texture, Sound, Font, MAX_ENUM }; +using AssetsNodestate = ResourceId_t; +using AssetsParticle = ResourceId_t; +using AssetsAnimation = ResourceId_t; +using AssetsModel = ResourceId_t; +using AssetsTexture = ResourceId_t; +using AssetsSound = ResourceId_t; +using AssetsFont = ResourceId_t; + using BinaryResource = std::shared_ptr; -// Двоичные данные -using BinTextureId_t = ResourceId_t; -using BinAnimationId_t = ResourceId_t; -using BinModelId_t = ResourceId_t; -using BinSoundId_t = ResourceId_t; -using BinFontId_t = ResourceId_t; - +/* + Определения контента, доставляются клиентам сразу +*/ enum class EnumDefContent { - Voxel, Node, Generator, World, Portal, Entity, Item, MAX_ENUM + Voxel, Node, World, Portal, Entity, Item, MAX_ENUM }; -// Игровые определения using DefVoxelId_t = ResourceId_t; using DefNodeId_t = ResourceId_t; using DefWorldId_t = ResourceId_t; @@ -416,9 +423,12 @@ using DefPortalId_t = ResourceId_t; using DefEntityId_t = ResourceId_t; using DefItemId_t = ResourceId_t; -// Контент, основанный на игровых определениях +/* + Контент, основанный на определениях. + Отдельные свойства могут менятся в самих объектах +*/ + using WorldId_t = ResourceId_t; -using PortalId_t = ResourceId_t; // struct LightPrism { // uint8_t R : 2, G : 2, B : 2; diff --git a/Src/Server/AssetsManager.cpp b/Src/Server/AssetsManager.cpp new file mode 100644 index 0000000..7c8340c --- /dev/null +++ b/Src/Server/AssetsManager.cpp @@ -0,0 +1,11 @@ +#include "AssetsManager.hpp" + + +namespace LV::Server { + + +coro AssetsManager::recheckResources(AssetsRegister info) const { + +} + +} \ No newline at end of file diff --git a/Src/Server/AssetsManager.hpp b/Src/Server/AssetsManager.hpp new file mode 100644 index 0000000..4c8b044 --- /dev/null +++ b/Src/Server/AssetsManager.hpp @@ -0,0 +1,116 @@ +#pragma once + +#include "Abstract.hpp" +#include "Common/Abstract.hpp" +#include "boost/asio/io_context.hpp" +#include "sha2.hpp" +#include +#include +#include +#include + + +namespace LV::Server { + +namespace fs = std::filesystem; + +class AssetsManager { +public: + struct Resource { + private: + struct Inline { + boost::interprocess::file_mapping MMap; + boost::interprocess::mapped_region Region; + Hash_t Hash; + + Inline(fs::path path) + : MMap(path.c_str(), boost::interprocess::read_only), + Region(MMap, boost::interprocess::read_only) + {} + }; + + std::shared_ptr In; + + public: + Resource(fs::path path) + : In(std::make_shared(path)) + { + In->Hash = sha2::sha256((const uint8_t*) In->Region.get_address(), In->Region.get_size()); + } + + Resource(const Resource&) = default; + Resource(Resource&&) = default; + Resource& operator=(const Resource&) = default; + Resource& operator=(Resource&&) = default; + bool operator<=>(const Resource&) const = default; + + const std::byte* data() const { return (const std::byte*) In->Region.get_address(); } + size_t size() const { return In->Region.get_size(); } + Hash_t hash() const { return In->Hash; } + }; + +private: + // Данные об отслеживаемых файлах + struct DataEntry { + // Время последнего изменения файла + size_t FileChangeTime; + Resource Res; + }; + + struct TableEntry { + bool IsFull = false; + std::bitset<4096> Empty; + std::array, 4096> Entries; + + TableEntry() { + Empty.reset(); + } + }; + + // Данные не меняются в процессе работы сервера. + // Изменения возможны при синхронизации всего сервера + // и перехода в режим перезагрузки модов + + // Связь ресурсов по идентификаторам + std::vector> Table[(int) EnumAssets::MAX_ENUM]; + // Связь домены -> {ключ -> идентификатор} + std::unordered_map> KeyToId[(int) EnumAssets::MAX_ENUM]; + + DataEntry& getEntry(EnumAssets type, ResourceId_t id); + + +public: + AssetsManager(asio::io_context& ioc); + ~AssetsManager(); + + /* + Перепроверка изменений ресурсов по дате изменения, пересчёт хешей. + Обнаруженные изменения должны быть отправлены всем клиентам. + Ресурсы будут обработаны в подходящий формат и сохранены в кеше. + Одновременно может выполнятся только одна такая функция + Используется в GameServer + */ + + struct AssetsRegister { + /* + Пути до активных папок assets, соответствую порядку загруженным модам. + От последнего мода к первому. + Тот файл, что был загружен раньше и будет использоваться + */ + std::vector Assets; + /* + У этих ресурсов приоритет выше, если их удастся получить, + то использоваться будут именно они + */ + std::vector> Custom; + }; + + struct Out_recheckResources { + std::vector> NewOrChange; + std::vector> Lost; + }; + + coro recheckResources(AssetsRegister) const; +}; + +} \ No newline at end of file diff --git a/Src/Server/BinaryResourceManager.cpp b/Src/Server/BinaryResourceManager.cpp index 418fe35..fad5062 100644 --- a/Src/Server/BinaryResourceManager.cpp +++ b/Src/Server/BinaryResourceManager.cpp @@ -74,6 +74,7 @@ void BinaryResourceManager::run() { if(var.index() == 0) { std::shared_ptr resource = std::get<0>(var); + resource = convertFormate(resource, (EnumBinResource) type); resource->calcHash(); return resource; } else { @@ -311,6 +312,10 @@ BinaryResourceManager::loadFile(const std::vector& assets, const std:: } } +std::shared_ptr convertFormate(std::shared_ptr file, EnumBinResource type) { + return file; +} + BinaryResourceManager::BinaryResourceManager(asio::io_context &ioc) : AsyncObject(ioc), Thread(&BinaryResourceManager::run, this) { diff --git a/Src/Server/BinaryResourceManager.hpp b/Src/Server/BinaryResourceManager.hpp index b324b3b..3ae7712 100644 --- a/Src/Server/BinaryResourceManager.hpp +++ b/Src/Server/BinaryResourceManager.hpp @@ -42,7 +42,7 @@ private: // Поток сервера // Последовательная регистрация ресурсов - ResourceId_t NextId[(int) EnumBinResource::MAX_ENUM] = {0}; + ResourceId_t NextId[(int) EnumAssets::MAX_ENUM] = {0}; // Известные ресурсы, им присвоен идентификатор // Нужно для потока загрузки std::unordered_map KnownResource[(int) EnumBinResource::MAX_ENUM]; @@ -76,6 +76,7 @@ private: 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 diff --git a/Src/Server/RemoteClient.hpp b/Src/Server/RemoteClient.hpp index b9cda64..36831c5 100644 --- a/Src/Server/RemoteClient.hpp +++ b/Src/Server/RemoteClient.hpp @@ -277,6 +277,7 @@ public: Pos::Object CameraPos = {0, 0, 0}; ToServer::PacketQuat CameraQuat = {0}; TOS::SpinlockObject> Actions; + ResourceId_t RecievedAssets[(int) EnumAssets::MAX_ENUM] = {0}; public: RemoteClient(asio::io_context &ioc, tcp::socket socket, const std::string username, std::vector &&client_cache)