mirror of
https://github.com/Mr-X-GTA/YimMenu.git
synced 2025-01-04 00:23:27 +08:00
fix(lua): better exception handling (#1734)
This commit is contained in:
parent
8d01f497e7
commit
0417fbf0f9
@ -88,7 +88,7 @@ namespace lua::event
|
||||
// Param: menu_event: menu_event: The menu_event that we want to respond to.
|
||||
// Param: func: function: The function that will be called.
|
||||
// Register a function that will be called each time the corresponding menu_event is triggered.
|
||||
static void register_handler(const menu_event& menu_event, sol::function func, sol::this_state state)
|
||||
static void register_handler(const menu_event& menu_event, sol::protected_function func, sol::this_state state)
|
||||
{
|
||||
const auto module = sol::state_view(state)["!this"].get<big::lua_module*>();
|
||||
|
||||
|
@ -166,7 +166,7 @@ namespace lua::gui
|
||||
// Param: name: string: Text written inside the button.
|
||||
// Param: callback: function: function that will be called when the button is clicked.
|
||||
// Add a button to the gui tab.
|
||||
std::shared_ptr<lua::gui::button> add_button(const std::string& name, sol::function callback, sol::this_state state)
|
||||
std::shared_ptr<lua::gui::button> add_button(const std::string& name, sol::protected_function callback, sol::this_state state)
|
||||
{
|
||||
auto element = std::make_shared<lua::gui::button>(name, callback);
|
||||
add_element(state, m_tab_hash, element);
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
button::button(std::string text, sol::function callback) :
|
||||
button::button(std::string text, sol::protected_function callback) :
|
||||
base_text_element(text),
|
||||
m_callback(callback)
|
||||
{
|
||||
|
@ -10,11 +10,11 @@ namespace lua::gui
|
||||
// Class representing a gui button.
|
||||
class button : public base_text_element
|
||||
{
|
||||
sol::function m_callback;
|
||||
sol::protected_function m_callback;
|
||||
bool m_execute_in_fiber_pool = true;
|
||||
|
||||
public:
|
||||
button(std::string text, sol::function callback);
|
||||
button(std::string text, sol::protected_function callback);
|
||||
|
||||
void draw() override;
|
||||
};
|
||||
|
@ -70,14 +70,13 @@ namespace lua::script
|
||||
// ENTITY.DELETE_ENTITY(spawnedVehicle)
|
||||
// end)
|
||||
// ```
|
||||
static void register_looped(const std::string& name, sol::function func_, sol::this_state state)
|
||||
static void register_looped(const std::string& name, sol::protected_function func_, sol::this_state state)
|
||||
{
|
||||
auto module = sol::state_view(state)["!this"].get<big::lua_module*>();
|
||||
|
||||
std::unique_ptr<big::script> lua_script = std::make_unique<big::script>(
|
||||
[func_, state]() mutable {
|
||||
|
||||
sol::thread t = sol::thread::create(state);
|
||||
sol::thread t = sol::thread::create(state);
|
||||
sol::coroutine func = sol::coroutine(t.state(), func_);
|
||||
|
||||
while (big::g_running)
|
||||
@ -97,8 +96,7 @@ namespace lua::script
|
||||
}
|
||||
}
|
||||
},
|
||||
name
|
||||
);
|
||||
name);
|
||||
|
||||
const auto registered_script = big::g_script_mgr.add_script(std::move(lua_script));
|
||||
|
||||
@ -117,23 +115,23 @@ namespace lua::script
|
||||
// script:yield()
|
||||
//
|
||||
// local ModelHash = joaat("adder")
|
||||
// if not STREAMING.IS_MODEL_IN_CDIMAGE(ModelHash) then return end
|
||||
// STREAMING.REQUEST_MODEL(ModelHash) -- Request the model
|
||||
// while not STREAMING.HAS_MODEL_LOADED(ModelHash) do -- Waits for the model to load
|
||||
// script:yield()
|
||||
// end
|
||||
// local myPed = PLAYER.PLAYER_PED_ID()
|
||||
// local myCoords = ENTITY.GET_ENTITY_COORDS(myPed, true)
|
||||
// -- Spawns a networked vehicle on your current coords
|
||||
// local spawnedVehicle = VEHICLE.CREATE_VEHICLE(ModelHash, myCoords.x, myCoords.y, myCoords.z, ENTITY.GET_ENTITY_HEADING(myPed), true, false)
|
||||
// -- removes model from game memory as we no longer need it
|
||||
// STREAMING.SET_MODEL_AS_NO_LONGER_NEEDED(ModelHash)
|
||||
// if not STREAMING.IS_MODEL_IN_CDIMAGE(ModelHash) then return end
|
||||
// STREAMING.REQUEST_MODEL(ModelHash) -- Request the model
|
||||
// while not STREAMING.HAS_MODEL_LOADED(ModelHash) do -- Waits for the model to load
|
||||
// script:yield()
|
||||
// end
|
||||
// local myPed = PLAYER.PLAYER_PED_ID()
|
||||
// local myCoords = ENTITY.GET_ENTITY_COORDS(myPed, true)
|
||||
// -- Spawns a networked vehicle on your current coords
|
||||
// local spawnedVehicle = VEHICLE.CREATE_VEHICLE(ModelHash, myCoords.x, myCoords.y, myCoords.z, ENTITY.GET_ENTITY_HEADING(myPed), true, false)
|
||||
// -- removes model from game memory as we no longer need it
|
||||
// STREAMING.SET_MODEL_AS_NO_LONGER_NEEDED(ModelHash)
|
||||
// -- sleep for 2s
|
||||
// script:sleep(2000)
|
||||
// ENTITY.DELETE_ENTITY(spawnedVehicle)
|
||||
// script:sleep(2000)
|
||||
// ENTITY.DELETE_ENTITY(spawnedVehicle)
|
||||
// end)
|
||||
// ```
|
||||
static void run_in_fiber(sol::function func_, sol::this_state state)
|
||||
static void run_in_fiber(sol::protected_function func_, sol::this_state state)
|
||||
{
|
||||
auto module = sol::state_view(state)["!this"].get<big::lua_module*>();
|
||||
|
||||
|
@ -157,7 +157,8 @@ namespace big
|
||||
|
||||
void lua_manager::handle_error(const sol::error& error, const sol::state_view& state)
|
||||
{
|
||||
LOG(WARNING) << state["!module_name"].get<std::string_view>() << ": " << error.what();
|
||||
LOG(FATAL) << state["!module_name"].get<std::string_view>() << ": " << error.what();
|
||||
Logger::FlushQueue();
|
||||
}
|
||||
|
||||
void lua_manager::load_all_modules()
|
||||
|
@ -18,30 +18,41 @@
|
||||
|
||||
namespace big
|
||||
{
|
||||
inline int exception_handler(lua_State* L, sol::optional<const std::exception&> exception, std::string_view what)
|
||||
// https://sol2.readthedocs.io/en/latest/exceptions.html
|
||||
int exception_handler(lua_State* L, sol::optional<const std::exception&> maybe_exception, sol::string_view description)
|
||||
{
|
||||
if (exception)
|
||||
LOG(WARNING) << exception->what();
|
||||
// L is the lua state, which you can wrap in a state_view if necessary
|
||||
// maybe_exception will contain exception, if it exists
|
||||
// description will either be the what() of the exception or a description saying that we hit the general-case catch(...)
|
||||
if (maybe_exception)
|
||||
{
|
||||
const std::exception& ex = *maybe_exception;
|
||||
LOG(FATAL) << ex.what();
|
||||
}
|
||||
else
|
||||
LOG(WARNING) << what;
|
||||
{
|
||||
LOG(FATAL) << description;
|
||||
}
|
||||
Logger::FlushQueue();
|
||||
|
||||
lua_pushlstring(L, what.data(), what.size());
|
||||
return 1;
|
||||
// you must push 1 element onto the stack to be
|
||||
// transported through as the error object in Lua
|
||||
// note that Lua -- and 99.5% of all Lua users and libraries -- expects a string
|
||||
// so we push a single string (in our case, the description of the error)
|
||||
return sol::stack::push(L, description);
|
||||
}
|
||||
|
||||
inline int panic_handler(lua_State* L)
|
||||
inline void panic_handler(sol::optional<std::string> maybe_msg)
|
||||
{
|
||||
size_t messagesize;
|
||||
const char* message = lua_tolstring(L, -1, &messagesize);
|
||||
if (message)
|
||||
LOG(FATAL) << "Lua is in a panic state and will now abort() the application";
|
||||
if (maybe_msg)
|
||||
{
|
||||
std::string err(message, messagesize);
|
||||
lua_settop(L, 0);
|
||||
LOG(FATAL) << err;
|
||||
const std::string& msg = maybe_msg.value();
|
||||
LOG(FATAL) << "error message: " << msg;
|
||||
}
|
||||
lua_settop(L, 0);
|
||||
LOG(FATAL) << "An unexpected error occurred and panic has been invoked";
|
||||
return 1;
|
||||
Logger::FlushQueue();
|
||||
|
||||
// When this function exits, Lua will exhibit default behavior and abort()
|
||||
}
|
||||
|
||||
lua_module::lua_module(std::string module_name) :
|
||||
@ -71,20 +82,18 @@ namespace big
|
||||
state["!module_name"] = module_name;
|
||||
state["!this"] = this;
|
||||
|
||||
state.set_exception_handler((sol::exception_handler_function)exception_handler);
|
||||
state.set_panic(panic_handler);
|
||||
state.set_exception_handler(exception_handler);
|
||||
state.set_panic(sol::c_call<decltype(&panic_handler), &panic_handler>);
|
||||
|
||||
const auto script_file_path = g_lua_manager->get_scripts_folder().get_file(module_name).get_path();
|
||||
m_last_write_time = std::filesystem::last_write_time(script_file_path);
|
||||
auto result = state.load_file(script_file_path.string());
|
||||
|
||||
auto result = state.safe_script_file(script_file_path.string(), &sol::script_pass_on_error, sol::load_mode::text);
|
||||
|
||||
if (!result.valid())
|
||||
{
|
||||
LOG(WARNING) << module_name << " failed to load: " << result.get<sol::error>().what();
|
||||
}
|
||||
else
|
||||
{
|
||||
result();
|
||||
LOG(FATAL) << module_name << " failed to load: " << result.get<sol::error>().what();
|
||||
Logger::FlushQueue();
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,6 +166,7 @@ namespace big
|
||||
const auto module = sol::state_view(current_state)["!this"].get<big::lua_module*>();
|
||||
|
||||
LOG(FATAL) << module->module_name() << " tried calling a currently not supported lua function: " << function_name;
|
||||
Logger::FlushQueue();
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ namespace big
|
||||
std::unordered_map<big::tabs, std::vector<big::tabs>> m_tab_to_sub_tabs;
|
||||
|
||||
std::unordered_map<rage::joaat_t, std::vector<std::shared_ptr<lua::gui::gui_element>>> m_gui;
|
||||
std::unordered_map<menu_event, std::vector<sol::function>> m_event_callbacks;
|
||||
std::unordered_map<menu_event, std::vector<sol::protected_function>> m_event_callbacks;
|
||||
std::vector<void*> m_allocated_memory;
|
||||
|
||||
lua_module(std::string module_name);
|
||||
|
Loading…
x
Reference in New Issue
Block a user