*
This commit is contained in:
@@ -7,14 +7,21 @@
|
|||||||
|
|
||||||
namespace LV::Server {
|
namespace LV::Server {
|
||||||
|
|
||||||
coro<AssetsManager::Resource> AssetsManager::loadResourceFromFile(EnumAssets type, fs::path path) const {
|
AssetsManager::Resource AssetsManager::loadResourceFromFile(EnumAssets type, fs::path path) const {
|
||||||
co_return AssetsManager::Resource(path);
|
return AssetsManager::Resource(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
coro<AssetsManager::Resource> AssetsManager::loadResourceFromLua(EnumAssets type, void*) const {
|
AssetsManager::Resource AssetsManager::loadResourceFromLua(EnumAssets type, void*) const {
|
||||||
co_return AssetsManager::Resource("assets/null");
|
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) {
|
std::tuple<ResourceId_t, std::optional<AssetsManager::DataEntry>&> AssetsManager::Local::nextId(EnumAssets type) {
|
||||||
auto& table = Table[(int) type];
|
auto& table = Table[(int) type];
|
||||||
ResourceId_t id = -1;
|
ResourceId_t id = -1;
|
||||||
@@ -45,7 +52,7 @@ std::tuple<ResourceId_t, std::optional<AssetsManager::DataEntry>&> AssetsManager
|
|||||||
return {id, *data};
|
return {id, *data};
|
||||||
}
|
}
|
||||||
|
|
||||||
coro<AssetsManager::Out_recheckResources> AssetsManager::recheckResources(AssetsRegister info) {
|
AssetsManager::Out_recheckResources AssetsManager::recheckResources(const AssetsRegister& info) {
|
||||||
Out_recheckResources result;
|
Out_recheckResources result;
|
||||||
|
|
||||||
// Найти пропавшие ресурсы
|
// Найти пропавшие ресурсы
|
||||||
@@ -124,10 +131,10 @@ coro<AssetsManager::Out_recheckResources> AssetsManager::recheckResources(Assets
|
|||||||
continue;
|
continue;
|
||||||
else if(iterDomain->second.contains(key)) {
|
else if(iterDomain->second.contains(key)) {
|
||||||
// Ресурс уже есть, TODO: нужно проверить его изменение
|
// Ресурс уже есть, 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 {
|
} 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);
|
findList.insert(key);
|
||||||
@@ -184,11 +191,11 @@ coro<AssetsManager::Out_recheckResources> AssetsManager::recheckResources(Assets
|
|||||||
fs::file_time_type lwt = fs::last_write_time(file);
|
fs::file_time_type lwt = fs::last_write_time(file);
|
||||||
if(lwt != entry.FileChangeTime)
|
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 {
|
} else {
|
||||||
// Ресурс не был известен
|
// Ресурс не был известен
|
||||||
fs::file_time_type lwt = fs::last_write_time(file);
|
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);
|
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) {
|
AssetsManager::Out_applyResourceChange AssetsManager::applyResourceChange(const Out_recheckResources& orr) {
|
||||||
|
|||||||
@@ -89,8 +89,8 @@ private:
|
|||||||
Загрузка ресурса с файла. При необходимости приводится
|
Загрузка ресурса с файла. При необходимости приводится
|
||||||
к внутреннему формату и сохраняется в кеше
|
к внутреннему формату и сохраняется в кеше
|
||||||
*/
|
*/
|
||||||
coro<Resource> loadResourceFromFile(EnumAssets type, fs::path path) const;
|
Resource loadResourceFromFile(EnumAssets type, fs::path path) const;
|
||||||
coro<Resource> loadResourceFromLua(EnumAssets type, void*) const;
|
Resource loadResourceFromLua(EnumAssets type, void*) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AssetsManager(asio::io_context& ioc);
|
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];
|
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);
|
Out_applyResourceChange applyResourceChange(const Out_recheckResources& orr);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Выдаёт идентификатор ресурса, даже если он не существует или был удалён.
|
Выдаёт идентификатор ресурса, даже если он не существует или был удалён.
|
||||||
resource должен содержать домен и путь
|
resource должен содержать домен и путь
|
||||||
|
|||||||
15
Src/Server/ContentManager.cpp
Normal file
15
Src/Server/ContentManager.cpp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#include "ContentManager.hpp"
|
||||||
|
|
||||||
|
namespace LV::Server {
|
||||||
|
|
||||||
|
|
||||||
|
ContentManager::ContentManager(asio::io_context& ioc)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentManager::~ContentManager() = default;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
62
Src/Server/ContentManager.hpp
Normal file
62
Src/Server/ContentManager.hpp
Normal 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();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "Common/Net.hpp"
|
#include "Common/Net.hpp"
|
||||||
#include "Common/Packets.hpp"
|
#include "Common/Packets.hpp"
|
||||||
#include "Server/Abstract.hpp"
|
#include "Server/Abstract.hpp"
|
||||||
|
#include "Server/AssetsManager.hpp"
|
||||||
#include "Server/ContentEventController.hpp"
|
#include "Server/ContentEventController.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
@@ -1407,15 +1408,6 @@ void GameServer::init(fs::path worldPath) {
|
|||||||
|
|
||||||
LOG.info() << "Загрузка инстансов модов";
|
LOG.info() << "Загрузка инстансов модов";
|
||||||
|
|
||||||
|
|
||||||
// Тест луа
|
|
||||||
|
|
||||||
|
|
||||||
// sol::function func = res.call<>();
|
|
||||||
// int type = func();
|
|
||||||
|
|
||||||
// LOG.debug() << type;
|
|
||||||
|
|
||||||
LoadedMods = mlt.LoadChain;
|
LoadedMods = mlt.LoadChain;
|
||||||
|
|
||||||
LuaMainState.open_libraries();
|
LuaMainState.open_libraries();
|
||||||
@@ -1428,72 +1420,60 @@ void GameServer::init(fs::path worldPath) {
|
|||||||
ModInstances.emplace_back(info.Id, res.call<sol::table>());
|
ModInstances.emplace_back(info.Id, res.call<sol::table>());
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG.info() << "Пре Инициализация";
|
std::function<void(const std::string&)> pushEvent = [&](const std::string& function) {
|
||||||
initLuaPre();
|
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) {
|
if(!result.valid()) {
|
||||||
std::optional<sol::protected_function> func = core.get<std::optional<sol::protected_function>>("preInit");
|
sol::error err = result;
|
||||||
if(func) {
|
MAKE_ERROR("Ошибка инициализации мода " << id << ":\n" << err.what());
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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() << "Инициализация";
|
LOG.info() << "Инициализация";
|
||||||
initLua();
|
initLua();
|
||||||
|
pushEvent("init");
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG.info() << "Пост Инициализация";
|
LOG.info() << "Пост Инициализация";
|
||||||
initLuaPost();
|
initLuaPost();
|
||||||
|
pushEvent("postInit");
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Загрузить миры с существующими профилями
|
// Загрузить миры с существующими профилями
|
||||||
|
LOG.info() << "Загрузка существующих миров...";
|
||||||
|
|
||||||
Expanse.Worlds[0] = std::make_unique<World>(0);
|
Expanse.Worlds[0] = std::make_unique<World>(0);
|
||||||
|
|
||||||
|
LOG.info() << "Оповещаем моды о завершении загрузки";
|
||||||
|
pushEvent("serverReady");
|
||||||
|
|
||||||
|
LOG.info() << "Загрузка существующих миров...";
|
||||||
BackingChunkPressure.Threads.resize(4);
|
BackingChunkPressure.Threads.resize(4);
|
||||||
BackingChunkPressure.Worlds = &Expanse.Worlds;
|
BackingChunkPressure.Worlds = &Expanse.Worlds;
|
||||||
for(size_t iter = 0; iter < BackingChunkPressure.Threads.size(); iter++) {
|
for(size_t iter = 0; iter < BackingChunkPressure.Threads.size(); iter++) {
|
||||||
@@ -1652,10 +1632,53 @@ DefNode_t GameServer::createNodeProfileByLua(const sol::table& profile) {
|
|||||||
return result;
|
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() {
|
void GameServer::initLuaPre() {
|
||||||
auto &lua = LuaMainState;
|
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) {
|
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_]+)$");
|
std::optional<std::vector<std::optional<std::string>>> result_o = TOS::Str::match(id, "^(?:([\\w\\d_]+):)?([\\w\\d_]+)$");
|
||||||
|
|
||||||
|
|||||||
@@ -302,6 +302,7 @@ class GameServer : public AsyncObject {
|
|||||||
std::vector<std::pair<std::string, sol::table>> ModInstances;
|
std::vector<std::pair<std::string, sol::table>> ModInstances;
|
||||||
// Идентификатор текущегго мода, находящевося в обработке
|
// Идентификатор текущегго мода, находящевося в обработке
|
||||||
std::string CurrentModId;
|
std::string CurrentModId;
|
||||||
|
AssetsManager::AssetsRegister AssetsInit;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GameServer(asio::io_context &ioc, fs::path worldPath);
|
GameServer(asio::io_context &ioc, fs::path worldPath);
|
||||||
@@ -339,6 +340,7 @@ private:
|
|||||||
DefNode_t createNodeProfileByLua(const sol::table& profile);
|
DefNode_t createNodeProfileByLua(const sol::table& profile);
|
||||||
|
|
||||||
|
|
||||||
|
void initLuaAssets();
|
||||||
void initLuaPre();
|
void initLuaPre();
|
||||||
void initLua();
|
void initLua();
|
||||||
void initLuaPost();
|
void initLuaPost();
|
||||||
|
|||||||
Reference in New Issue
Block a user