This commit is contained in:
2025-08-11 17:30:19 +06:00
parent efcf8daf7e
commit 9556e1affd
7 changed files with 162 additions and 18 deletions

View File

@@ -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)

View File

@@ -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<const std::u8string>;
// Двоичные данные
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;

View File

@@ -0,0 +1,11 @@
#include "AssetsManager.hpp"
namespace LV::Server {
coro<AssetsManager::Out_recheckResources> AssetsManager::recheckResources(AssetsRegister info) const {
}
}

View File

@@ -0,0 +1,116 @@
#pragma once
#include "Abstract.hpp"
#include "Common/Abstract.hpp"
#include "boost/asio/io_context.hpp"
#include "sha2.hpp"
#include <boost/interprocess/file_mapping.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <filesystem>
#include <unordered_map>
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<Inline> In;
public:
Resource(fs::path path)
: In(std::make_shared<Inline>(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<std::optional<DataEntry>, 4096> Entries;
TableEntry() {
Empty.reset();
}
};
// Данные не меняются в процессе работы сервера.
// Изменения возможны при синхронизации всего сервера
// и перехода в режим перезагрузки модов
// Связь ресурсов по идентификаторам
std::vector<std::unique_ptr<TableEntry>> Table[(int) EnumAssets::MAX_ENUM];
// Связь домены -> {ключ -> идентификатор}
std::unordered_map<std::string, std::unordered_map<std::string, ResourceId_t>> 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<fs::path> Assets;
/*
У этих ресурсов приоритет выше, если их удастся получить,
то использоваться будут именно они
*/
std::vector<std::tuple<std::string, EnumAssets, void*>> Custom;
};
struct Out_recheckResources {
std::vector<std::tuple< ResourceId_t, EnumAssets, Resource >> NewOrChange;
std::vector<std::tuple< ResourceId_t, EnumAssets >> Lost;
};
coro<Out_recheckResources> recheckResources(AssetsRegister) const;
};
}

View File

@@ -74,6 +74,7 @@ void BinaryResourceManager::run() {
if(var.index() == 0) {
std::shared_ptr<ResourceFile> resource = std::get<0>(var);
resource = convertFormate(resource, (EnumBinResource) type);
resource->calcHash();
return resource;
} else {
@@ -311,6 +312,10 @@ BinaryResourceManager::loadFile(const std::vector<fs::path>& assets, const std::
}
}
std::shared_ptr<ResourceFile> convertFormate(std::shared_ptr<ResourceFile> file, EnumBinResource type) {
return file;
}
BinaryResourceManager::BinaryResourceManager(asio::io_context &ioc)
: AsyncObject(ioc), Thread(&BinaryResourceManager::run, this)
{

View File

@@ -42,7 +42,7 @@ private:
// Поток сервера
// Последовательная регистрация ресурсов
ResourceId_t NextId[(int) EnumBinResource::MAX_ENUM] = {0};
ResourceId_t NextId[(int) EnumAssets::MAX_ENUM] = {0};
// Известные ресурсы, им присвоен идентификатор
// Нужно для потока загрузки
std::unordered_map<std::string, ResourceId_t> KnownResource[(int) EnumBinResource::MAX_ENUM];
@@ -76,6 +76,7 @@ private:
void run();
std::variant<std::shared_ptr<ResourceFile>, std::string>
loadFile(const std::vector<fs::path>& assets, const std::string& path, EnumBinResource type);
std::shared_ptr<ResourceFile> convertFormate(std::shared_ptr<ResourceFile> file, EnumBinResource type);
public:
// Если ресурс будет обновлён или загружен будет вызвано onResourceUpdate

View File

@@ -277,6 +277,7 @@ public:
Pos::Object CameraPos = {0, 0, 0};
ToServer::PacketQuat CameraQuat = {0};
TOS::SpinlockObject<std::queue<uint8_t>> Actions;
ResourceId_t RecievedAssets[(int) EnumAssets::MAX_ENUM] = {0};
public:
RemoteClient(asio::io_context &ioc, tcp::socket socket, const std::string username, std::vector<ResourceFile::Hash_t> &&client_cache)