/
d.vision
/
division_engine_cpp
Обзор
Документация
Войти
/
d.vision
/
division_engine_cpp
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/lua/lua_manager.cpp
177 строк
5 KB
den163
Added texture loading
02 дек 2024, 12:55
02 дек 2024, 12:55
272b195
Код
Авторство
О чём код?
#include "division_engine/lua/lua_manager.hpp" #include "lauxlib.h" #include "lua.h" #include <cstdlib> #include <filesystem> #include <functional> #include <iostream> #include <stdexcept> #include <string> #include <tuple> #include <type_traits> #include <lua.hpp> constexpr const char* DIVISION_LUA_ON_DESTROY = "__ON_DESTROY__"; constexpr const char* DIVISION_LUA_ON_UPDATE = "__ON_UPDATE__"; namespace division_engine::lua { static void load_and_run_script(const std::filesystem::path& path, lua_State* state); static void run_event_function(const char* function_name, lua_State* state); static int pcall_error_handler(lua_State* state); LuaManager::LuaManager() noexcept : _state(luaL_newstate()) { luaL_openlibs(_state.c_state()); } LuaManager::~LuaManager() { run_event_function(DIVISION_LUA_ON_DESTROY, _state.c_state()); lua_close(_state.c_state()); } LuaManager LuaManager::with_search_script_path(const std::filesystem::path& path) { char* lua_path = getenv("LUA_PATH"); std::filesystem::path abs_path = std::filesystem::absolute(path); std::filesystem::path new_path = abs_path / "?.lua"; std::filesystem::path new_rec_path = abs_path / "?" / "?.lua"; std::string new_lua_path = (lua_path ? std::string { lua_path } + std::string { ";" } : "") + std::string { new_path } + ";" + std::string { new_rec_path }; setenv("LUA_PATH", new_lua_path.c_str(), true); return {}; } void LuaManager::set_watch_file(const std::filesystem::path& main_script_path) { _last_write_time = std::filesystem::last_write_time(main_script_path); _main_script_path = main_script_path; load_and_run_script(main_script_path, _state.c_state()); } void LuaManager::update() { if (!_main_script_path.has_value()) { return; } auto* c_state = _state.c_state(); const auto script_path = _main_script_path.value(); if (check_script_changes(script_path)) { run_event_function(DIVISION_LUA_ON_DESTROY, c_state); load_and_run_script(script_path, c_state); } else { run_event_function(DIVISION_LUA_ON_UPDATE, c_state); } } bool LuaManager::check_script_changes(const std::filesystem::path& script_path) { if (!std::filesystem::exists(script_path)) { return false; } const auto& last_write_time = std::filesystem::last_write_time(script_path); if (last_write_time == _last_write_time) { return false; } _last_write_time = last_write_time; return true; } static void load_and_run_script(const std::filesystem::path& path, lua_State* c_state) { if (!std::filesystem::exists(path)) { throw std::runtime_error { "There is no the lua script by path: " + std::string { path } }; } lua_pushcfunction(c_state, pcall_error_handler); if (luaL_loadfile(c_state, path.c_str())) { lua_pop(c_state, 1); throw std::runtime_error { "Error while loading the lua script by path: " + path.string() }; } int error_code = lua_pcall(c_state, 0, 0, -2); if (error_code) { const auto lua_error_msg = lua_isstring(c_state, -1) ? std::string { lua_tostring(c_state, -1) } : "Unknown"; lua_pop(c_state, 1); throw std::runtime_error { std::string { "Error while calling lua script. Reason: " } + lua_error_msg }; } lua_pop(c_state, 1); } static void run_event_function(const char* function_name, lua_State* c_state) { lua_pushcfunction(c_state, pcall_error_handler); lua_getglobal(c_state, function_name); if (!lua_isfunction(c_state, -1)) { lua_pop(c_state, 2); throw std::runtime_error { std::string { "The global function '" } + function_name + "' is not exist", }; } int error_code = lua_pcall(c_state, 0, 0, -2); if (error_code) { const auto lua_error_msg = lua_isstring(c_state, -1) ? std::string { lua_tostring(c_state, -1) } : "Unknown"; lua_pop(c_state, 1); throw std::runtime_error { std::string { "Error while running the lua function. Reason: " } + lua_error_msg }; } lua_pop(c_state, 1); } static int pcall_error_handler(lua_State* state) { const std::string err_msg { lua_tostring(state, -1) }; lua_getglobal(state, "debug"); lua_getfield(state, -1, "traceback"); std::string traceback_msg { "" }; if (lua_pcall(state, 0, 1, 0)) { traceback_msg += "There is an error occured while call debug.traceback(): "; } traceback_msg += std::string { lua_tostring(state, -1) }; lua_pop(state, 4); std::cerr << "There is an error occured in the lua script:" << std::endl << err_msg << std::endl << traceback_msg << std::endl; return 1; } }