This commit is contained in:
2025-08-05 18:07:41 +06:00
parent c1df4a21f3
commit e5cfdd3787
2 changed files with 134 additions and 12 deletions

View File

@@ -15,6 +15,8 @@
#include <memory>
#include <mutex>
#include <sol/forward.hpp>
#include <sol/optional_implementation.hpp>
#include <sol/protected_function_result.hpp>
#include <sstream>
#include <string>
#include <thread>
@@ -240,7 +242,7 @@ std::vector<std::vector<ModInfo>> rangDepends(const std::vector<ModInfo>& mods)
std::vector<std::vector<ModInfo>> ranging;
std::vector<ModInfo> state, next = mods;
while(true) {
while(!next.empty()) {
state = std::move(next);
for(size_t index = 0; index < state.size(); index++) {
@@ -267,8 +269,7 @@ std::vector<std::vector<ModInfo>> rangDepends(const std::vector<ModInfo>& mods)
// Циклическая зависимость
ranging.push_back(std::move(next));
break;
} else if(next.empty())
break;
}
ranging.push_back(std::move(state));
}
@@ -381,7 +382,7 @@ std::variant<ModLoadTree, std::vector<std::string>> buildLoadChain(const std::ve
{
std::vector<std::vector<ModInfo>> rangeLoad = rangDepends(toLoad);
for(auto begin = rangeLoad.rbegin(), end = rangeLoad.rend(); begin != end; begin++) {
unloadChain.insert(unloadChain.end(), begin->begin(), begin->end());
loadChain.insert(loadChain.end(), begin->begin(), begin->end());
}
}
@@ -1262,6 +1263,22 @@ std::string GameServer::deBuildTexturePipeline(const TexturePipeline& pipeline)
return "";
}
int my_exception_handler(lua_State* lua, sol::optional<const std::exception&> maybe_exception, sol::string_view description) {
std::cout << "An exception occurred in a function, here's what it says ";
if (maybe_exception) {
std::cout << "(straight from the exception): ";
const std::exception& ex = *maybe_exception;
std::cout << ex.what() << std::endl;
}
else {
std::cout << "(from the description parameter): ";
std::cout.write(description.data(), static_cast<std::streamsize>(description.size()));
std::cout << std::endl;
}
return sol::stack::push(lua, description);
}
void GameServer::init(fs::path worldPath) {
// world.json
@@ -1403,32 +1420,75 @@ void GameServer::init(fs::path worldPath) {
LoadedMods = mlt.LoadChain;
LuaMainState.open_libraries();
LuaMainState.set_exception_handler(&my_exception_handler);
for(const ModInfo& info : mlt.LoadChain) {
LOG.info() << info.Id;
CurrentModId = info.Id;
sol::load_result res = LuaMainState.load_file(info.Path / "init.lua");
ModInstances.emplace_back(info.Id, res.call<sol::table>());
}
LOG.info() << "Пре Инициализация";
initLuaPre();
for(auto& [id, core] : ModInstances) {
sol::function func = core.get_or<sol::function>("preInit", {});
func();
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());
}
}
}
LOG.info() << "Инициализация";
initLua();
for(auto& [id, core] : ModInstances) {
sol::function func = core.get_or<sol::function>("init", {});
func();
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() << "Пост Инициализация";
initLuaPost();
for(auto& [id, core] : ModInstances) {
sol::function func = core.get_or<sol::function>("postInit", {});
func();
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());
}
}
}
// Загрузить миры с существующими профилями
@@ -1537,6 +1597,43 @@ void GameServer::run() {
LOG.info() << "Сервер завершил работу";
}
void GameServer::initLuaPre() {
auto &lua = LuaMainState;
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_]+)$");
if(!result_o) {
MAKE_ERROR("Недействительный идентификатор ноды: " << id);
}
auto &result = *result_o;
if(result[1])
Content.registerContent(id, EnumDefContent::Node);
else
Content.registerContent(CurrentModId+":"+*result[2], EnumDefContent::Node);
});
}
void GameServer::initLua() {
auto &lua = LuaMainState;
sol::table core = lua["core"];
auto lambdaError = [](sol::this_state L) {
luaL_error(L.lua_state(), "Данная функция может использоваться только в стадии [preInit]");
};
for(const char* name : {"register_node"})
core.set_function(name, lambdaError);
}
void GameServer::initLuaPost() {
}
void GameServer::stepConnections() {
// Подключить новых игроков
if(!External.NewConnectedPlayers.no_lock_readable().empty()) {

View File

@@ -1,5 +1,7 @@
#pragma once
#define SOL_EXCEPTIONS_SAFE_PROPAGATION 1
#include <Common/Net.hpp>
#include <Common/Lockable.hpp>
#include <boost/asio/any_io_executor.hpp>
@@ -80,8 +82,7 @@ class GameServer : public AsyncObject {
std::unordered_map<DefEntityId_t, DefEntity_t> ContentIdToDef_Entity;
std::unordered_map<DefItemId_t, DefItem_t> ContentIdToDef_Item;
ResourceId_t getContentDefId(const std::string& key, EnumDefContent def) {
ResourceId_t registerContent(const std::string& key, EnumDefContent def) {
int index = int(def);
assert(index < (int) EnumDefContent::MAX_ENUM);
@@ -94,6 +95,19 @@ class GameServer : public AsyncObject {
return nextId;
}
MAKE_ERROR("Повторная регистрация контента: " << key << " тип " << int(def));
}
ResourceId_t getContentDefId(const std::string& key, EnumDefContent def) {
int index = int(def);
assert(index < (int) EnumDefContent::MAX_ENUM);
auto &container = ContentKeyToId[index];
auto iter = container.find(key);
if(iter == container.end()) {
return ResourceId_t(-1);
}
return iter->second;
}
@@ -284,6 +298,12 @@ class GameServer : public AsyncObject {
sol::state LuaMainState;
std::vector<ModInfo> LoadedMods;
std::vector<std::pair<std::string, sol::table>> ModInstances;
// Идентификатор текущегго мода, находящевося в обработке
std::string CurrentModId;
struct {
};
public:
GameServer(asio::io_context &ioc, fs::path worldPath);
@@ -318,6 +338,11 @@ private:
void prerun();
void run();
void initLuaPre();
void initLua();
void initLuaPost();
/*
Подключение/отключение игроков
*/