This commit is contained in:
2025-08-13 11:49:56 +06:00
parent c1b16949fa
commit 4c7e2c8e72
6 changed files with 183 additions and 75 deletions

View File

@@ -7,14 +7,21 @@
namespace LV::Server {
coro<AssetsManager::Resource> AssetsManager::loadResourceFromFile(EnumAssets type, fs::path path) const {
co_return AssetsManager::Resource(path);
AssetsManager::Resource AssetsManager::loadResourceFromFile(EnumAssets type, fs::path path) const {
return AssetsManager::Resource(path);
}
coro<AssetsManager::Resource> AssetsManager::loadResourceFromLua(EnumAssets type, void*) const {
co_return AssetsManager::Resource("assets/null");
AssetsManager::Resource AssetsManager::loadResourceFromLua(EnumAssets type, void*) const {
return AssetsManager::Resource("assets/null");
}
AssetsManager::AssetsManager(asio::io_context& ioc)
{
}
AssetsManager::~AssetsManager() = default;
std::tuple<ResourceId_t, std::optional<AssetsManager::DataEntry>&> AssetsManager::Local::nextId(EnumAssets type) {
auto& table = Table[(int) type];
ResourceId_t id = -1;
@@ -45,7 +52,7 @@ std::tuple<ResourceId_t, std::optional<AssetsManager::DataEntry>&> AssetsManager
return {id, *data};
}
coro<AssetsManager::Out_recheckResources> AssetsManager::recheckResources(AssetsRegister info) {
AssetsManager::Out_recheckResources AssetsManager::recheckResources(const AssetsRegister& info) {
Out_recheckResources result;
// Найти пропавшие ресурсы
@@ -124,10 +131,10 @@ coro<AssetsManager::Out_recheckResources> 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());
result.NewOrChange[type][domain].emplace_back(key, loadResourceFromFile((EnumAssets) type, "assets/null"), fs::file_time_type::min());
} else {
// Ресурс не был известен
result.NewOrChange[type][domain].emplace_back(key, co_await loadResourceFromFile((EnumAssets) type, "assets/null"), fs::file_time_type::min());
result.NewOrChange[type][domain].emplace_back(key, loadResourceFromFile((EnumAssets) type, "assets/null"), fs::file_time_type::min());
}
findList.insert(key);
@@ -184,11 +191,11 @@ coro<AssetsManager::Out_recheckResources> AssetsManager::recheckResources(Assets
fs::file_time_type lwt = fs::last_write_time(file);
if(lwt != entry.FileChangeTime)
// Будем считать что ресурс изменился
result.NewOrChange[type][domain].emplace_back(key, co_await loadResourceFromFile((EnumAssets) type, file), lwt);
result.NewOrChange[type][domain].emplace_back(key, loadResourceFromFile((EnumAssets) type, file), lwt);
} else {
// Ресурс не был известен
fs::file_time_type lwt = fs::last_write_time(file);
result.NewOrChange[type][domain].emplace_back(key, co_await loadResourceFromFile((EnumAssets) type, file), lwt);
result.NewOrChange[type][domain].emplace_back(key, loadResourceFromFile((EnumAssets) type, file), lwt);
}
findList.insert(key);
@@ -198,7 +205,7 @@ coro<AssetsManager::Out_recheckResources> AssetsManager::recheckResources(Assets
}
co_return result;
return result;
}
AssetsManager::Out_applyResourceChange AssetsManager::applyResourceChange(const Out_recheckResources& orr) {

View File

@@ -89,8 +89,8 @@ private:
Загрузка ресурса с файла. При необходимости приводится
к внутреннему формату и сохраняется в кеше
*/
coro<Resource> loadResourceFromFile(EnumAssets type, fs::path path) const;
coro<Resource> loadResourceFromLua(EnumAssets type, void*) const;
Resource loadResourceFromFile(EnumAssets type, fs::path path) const;
Resource loadResourceFromLua(EnumAssets type, void*) const;
public:
AssetsManager(asio::io_context& ioc);
@@ -126,7 +126,7 @@ public:
std::unordered_map<std::string, std::vector<std::tuple<std::string, Resource, fs::file_time_type>>> NewOrChange[(int) EnumAssets::MAX_ENUM];
};
coro<Out_recheckResources> recheckResources(AssetsRegister);
Out_recheckResources recheckResources(const AssetsRegister&);
/*
Применяет расчитанные изменения.
@@ -139,7 +139,6 @@ public:
Out_applyResourceChange applyResourceChange(const Out_recheckResources& orr);
/*
Выдаёт идентификатор ресурса, даже если он не существует или был удалён.
resource должен содержать домен и путь

View File

@@ -0,0 +1,15 @@
#include "ContentManager.hpp"
namespace LV::Server {
ContentManager::ContentManager(asio::io_context& ioc)
{
}
ContentManager::~ContentManager() = default;
}

View File

@@ -0,0 +1,62 @@
#pragma once
#include "Server/Abstract.hpp"
namespace LV::Server {
struct DefVoxel {
};
struct DefNode {
};
struct DefWorld {
};
struct DefPortal {
};
struct DefEntity {
};
struct DefItem {
};
class ContentManager {
// Профили зарегистрированные модами
// Изменения, накладываемые на профили
// Следующие идентификаторы регистрации контента
ResourceId_t NextId[(int) EnumDefContent::MAX_ENUM] = {0};
// Домен -> {ключ -> идентификатор}
std::unordered_map<std::string, std::unordered_map<std::string, ResourceId_t>> ContentKeyToId[(int) EnumDefContent::MAX_ENUM];
template<typename T>
struct TableEntry {
static constexpr size_t ChunkSize = 4096;
std::array<std::optional<T>, ChunkSize> Entries;
};
// Конечные профили контента
std::vector<std::unique_ptr<TableEntry<DefVoxel>>> Profiles_Voxel;
std::vector<std::unique_ptr<TableEntry<DefNode>>> Profiles_Node;
std::vector<std::unique_ptr<TableEntry<DefWorld>>> Profiles_World;
std::vector<std::unique_ptr<TableEntry<DefPortal>>> Profiles_Portal;
std::vector<std::unique_ptr<TableEntry<DefEntity>>> Profiles_Entity;
std::vector<std::unique_ptr<TableEntry<DefItem>>> Profiles_Item;
public:
ContentManager(asio::io_context& ioc);
~ContentManager();
};
}

View File

@@ -3,6 +3,7 @@
#include "Common/Net.hpp"
#include "Common/Packets.hpp"
#include "Server/Abstract.hpp"
#include "Server/AssetsManager.hpp"
#include "Server/ContentEventController.hpp"
#include <algorithm>
#include <array>
@@ -1407,15 +1408,6 @@ void GameServer::init(fs::path worldPath) {
LOG.info() << "Загрузка инстансов модов";
// Тест луа
// sol::function func = res.call<>();
// int type = func();
// LOG.debug() << type;
LoadedMods = mlt.LoadChain;
LuaMainState.open_libraries();
@@ -1428,72 +1420,60 @@ void GameServer::init(fs::path worldPath) {
ModInstances.emplace_back(info.Id, res.call<sol::table>());
}
LOG.info() << "Пре Инициализация";
initLuaPre();
std::function<void(const std::string&)> pushEvent = [&](const std::string& function) {
for(auto& [id, core] : ModInstances) {
std::optional<sol::protected_function> func = core.get<std::optional<sol::protected_function>>(function);
if(func) {
sol::protected_function_result result;
try {
result = func->operator()();
} catch(const std::exception &exc) {
MAKE_ERROR("Ошибка инициализации мода " << id << ":\n" << exc.what());
}
for(auto& [id, core] : ModInstances) {
std::optional<sol::protected_function> func = core.get<std::optional<sol::protected_function>>("preInit");
if(func) {
sol::protected_function_result result;
try {
result = func->operator()();
} catch(const std::exception &exc) {
MAKE_ERROR("Ошибка инициализации мода " << id << ":\n" << exc.what());
}
if(!result.valid()) {
sol::error err = result;
MAKE_ERROR("Ошибка инициализации мода " << id << ":\n" << err.what());
if(!result.valid()) {
sol::error err = result;
MAKE_ERROR("Ошибка инициализации мода " << id << ":\n" << err.what());
}
}
}
};
initLuaAssets();
pushEvent("initAssets");
for(ssize_t index = mlt.LoadChain.size(); index >= 0; index--) {
AssetsInit.Assets.push_back(mlt.LoadChain[index].Path / "assets");
}
Content.AM.applyResourceChange(Content.AM.recheckResources(AssetsInit));
LOG.info() << "Пре Инициализация";
initLuaPre();
pushEvent("lowPreInit");
// TODO: регистрация контента из mod/content/*
pushEvent("preInit");
pushEvent("highPreInit");
LOG.info() << "Инициализация";
initLua();
for(auto& [id, core] : ModInstances) {
CurrentModId = id;
std::optional<sol::protected_function> func = core.get<std::optional<sol::protected_function>>("init");
if(func) {
sol::protected_function_result result;
try {
result = func->operator()();
} catch(...) {
MAKE_ERROR("Ошибка инициализации мода " << id << ":\n");
}
if(!result.valid()) {
sol::error err = result;
MAKE_ERROR("Ошибка инициализации мода " << id << ":\n" << err.what());
}
}
}
pushEvent("init");
LOG.info() << "Пост Инициализация";
initLuaPost();
for(auto& [id, core] : ModInstances) {
CurrentModId = id;
std::optional<sol::protected_function> func = core.get<std::optional<sol::protected_function>>("postInit");
if(func) {
sol::protected_function_result result;
try {
result = func->operator()();
} catch(const std::exception &exc) {
MAKE_ERROR("Ошибка инициализации мода " << id << ":\n" << exc.what());
}
if(!result.valid()) {
sol::error err = result;
MAKE_ERROR("Ошибка инициализации мода " << id << ":\n" << err.what());
}
}
}
pushEvent("postInit");
// Загрузить миры с существующими профилями
LOG.info() << "Загрузка существующих миров...";
Expanse.Worlds[0] = std::make_unique<World>(0);
LOG.info() << "Оповещаем моды о завершении загрузки";
pushEvent("serverReady");
LOG.info() << "Загрузка существующих миров...";
BackingChunkPressure.Threads.resize(4);
BackingChunkPressure.Worlds = &Expanse.Worlds;
for(size_t iter = 0; iter < BackingChunkPressure.Threads.size(); iter++) {
@@ -1652,10 +1632,53 @@ DefNode_t GameServer::createNodeProfileByLua(const sol::table& profile) {
return result;
}
void GameServer::initLuaAssets() {
auto &lua = LuaMainState;
std::optional<sol::table> core = lua["core"];
if(!core)
core = lua.create_named_table("core");
std::function<void(EnumAssets, const std::string&, const sol::table&)> reg
= [this](EnumAssets type, const std::string& key, const sol::table& profile)
{
std::optional<std::vector<std::optional<std::string>>> result_o = TOS::Str::match(key, "^(?:([\\w\\d_]+):)?([\\w\\d_]+)$");
if(!result_o) {
MAKE_ERROR("Недействительный идентификатор ноды: " << key);
}
auto &result = *result_o;
if(result[1])
AssetsInit.Custom[(int) type][*result[1]][*result[2]] = nullptr;
else
AssetsInit.Custom[(int) type][CurrentModId][*result[2]] = nullptr;
};
core->set_function("register_nodestate", std::bind(reg, EnumAssets::Nodestate, std::placeholders::_1, std::placeholders::_2));
core->set_function("register_particle", std::bind(reg, EnumAssets::Patricle, std::placeholders::_1, std::placeholders::_2));
core->set_function("register_animation", std::bind(reg, EnumAssets::Animation, std::placeholders::_1, std::placeholders::_2));
core->set_function("register_model", std::bind(reg, EnumAssets::Model, std::placeholders::_1, std::placeholders::_2));
core->set_function("register_texture", std::bind(reg, EnumAssets::Texture, std::placeholders::_1, std::placeholders::_2));
core->set_function("register_sound", std::bind(reg, EnumAssets::Sound, std::placeholders::_1, std::placeholders::_2));
core->set_function("register_font", std::bind(reg, EnumAssets::Font, std::placeholders::_1, std::placeholders::_2));
return resources;
}
void GameServer::initLuaPre() {
auto &lua = LuaMainState;
sol::table core = lua["core"];
auto lambdaError = [](sol::this_state L) {
luaL_error(L.lua_state(), "Данная функция может использоваться только в стадии [assetsInit]");
};
for(const char* name : {"register_nodestate", "register_particle", "register_animation",
"register_model", "register_texture", "register_sound", "register_font"})
core.set_function(name, lambdaError);
sol::table core = lua.create_named_table("core");
core.set_function("register_node", [&](const std::string& id, const sol::table& profile) {
std::optional<std::vector<std::optional<std::string>>> result_o = TOS::Str::match(id, "^(?:([\\w\\d_]+):)?([\\w\\d_]+)$");

View File

@@ -302,6 +302,7 @@ class GameServer : public AsyncObject {
std::vector<std::pair<std::string, sol::table>> ModInstances;
// Идентификатор текущегго мода, находящевося в обработке
std::string CurrentModId;
AssetsManager::AssetsRegister AssetsInit;
public:
GameServer(asio::io_context &ioc, fs::path worldPath);
@@ -339,6 +340,7 @@ private:
DefNode_t createNodeProfileByLua(const sol::table& profile);
void initLuaAssets();
void initLuaPre();
void initLua();
void initLuaPost();