diff --git a/worldeditadditions_core/core/run_command.lua b/worldeditadditions_core/core/run_command.lua index 9ec36c3..9087c61 100644 --- a/worldeditadditions_core/core/run_command.lua +++ b/worldeditadditions_core/core/run_command.lua @@ -5,6 +5,7 @@ local wea_c = worldeditadditions_core local safe_region = dofile(wea_c.modpath.."/core/safe_region.lua") local human_size = wea_c.format.human_size +local safe_function = wea_c.safe_function -- TODO: Reimplement worldedit.player_notify(player_name, msg_text) @@ -34,56 +35,7 @@ local function run_command_stage2(player_name, func, parse_result, tbl_event) wea_c:emit("post-execute", tbl_event) end -local function send_error(player_name, cmdname, msg, stack_trace) - print("DEBUG:HAI SEND_ERROR") - local msg_compiled = table.concat({ - "[//", cmdname, "] Error: ", - msg, - "\n", - "Please report this by opening an issue on GitHub! Bug report link (ctrl + click):\n", - - "https://github.com/sbrl/Minetest-WorldEditAdditions/issues/new?title=", - wea_c.format.escape(stack_trace:match("^[^\n]+")), -- extract 1st line & escape - "&body=", - wea_c.format.escape(table.concat({ - [[## Describe the bug -What's the bug? Be clear and detailed but concise in our explanation. Don't forget to include any context, error messages, logs, and screenshots required to understand the issue if applicable. -## Reproduction steps -Steps to reproduce the behaviour: -1. Go to '...' -2. Click on '....' -3. Enter this command to '....' -4. See error - -## System information (please complete the following information) -- **Operating system and version:** [e.g. iOS] -- **Minetest version:** [e.g. 5.8.0] -- **WorldEdit version:** -- **WorldEditAdditions version:** - -Please add any other additional specific system information here too if you think it would help. - -## Stack trace -- **Command name:** ]], - cmdname, - "\n", - "```\n", - stack_trace, - "```\n", - }, "")), - - "\n", - "-------------------------------------\n", - "*** Stack trace ***\n", - stack_trace, - "\n", - "-------------------------------------\n" - }, "") - - print("DEBUG:player_notify player_name", player_name, "msg_compiled", msg_compiled) - worldedit.player_notify(player_name, msg_compiled) -end --- Command execution pipeline: before `paramtext` parsing but after validation. -- @@ -163,27 +115,12 @@ local function run_command(cmdname, options, player_name, paramtext) wea_c:emit("pre-parse", tbl_event) - local parse_result -- local did_error = false - local success_xpcall, error_message = xpcall(function() - parse_result = { options.parse(paramtext) } - end, debug.traceback + local success_safefn, success, parse_result = safe_function(options.parse, { paramtext }, player_name, "The command crashed when parsing the arguments.", cmdname) + if not success_safefn then return false end -- error already sent to the player above - --[[function(error_raw) - did_error = true - error_message = error_raw - print("DEBUG:parse_result>>error", error_raw, "stack trace", debug.traceback()) - end]]-- - ) + print("DEBUG:run_command success_safefn", success_safefn, "success", success, "parse_result", parse_result) - if not success_xpcall then - print("DEBUG:parse_result EXIT_DUE_TO_ERROR") - send_error(player_name, cmdname, "The command crashed when parsing the arguments.", error_message) - print("DEBUG:parse_result EXIT_DUE_TO_ERROR __final_call__") - return false - end - - local success = table.remove(parse_result, 1) if not success then worldedit.player_notify(player_name, ("[//"..tostring(cmdname).."] "..tostring(parse_result[1])) or "Invalid usage (no further error message was provided by the command. This is probably a bug.)") return false diff --git a/worldeditadditions_core/core/safe_function.lua b/worldeditadditions_core/core/safe_function.lua new file mode 100644 index 0000000..6384d3a --- /dev/null +++ b/worldeditadditions_core/core/safe_function.lua @@ -0,0 +1,88 @@ +local weac = worldeditadditions_core +--- +-- @module worldeditadditions_core + +-- ███████ █████ ███████ ███████ ███████ ███ ██ +-- ██ ██ ██ ██ ██ ██ ████ ██ +-- ███████ ███████ █████ █████ █████ ██ ██ ██ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ███████ ██ ██ ██ ███████ ███████ ██ ██ ████ + + +local function send_error(player_name, cmdname, msg, stack_trace) + print("DEBUG:HAI SEND_ERROR") + local msg_compiled = table.concat({ + "[//", cmdname, "] Error: ", + msg, + "\n", + "Please report this by opening an issue on GitHub! Bug report link (ctrl + click):\n", + "https://github.com/sbrl/Minetest-WorldEditAdditions/issues/new?title=", + weac.format.escape(stack_trace:match("^[^\n]+")), -- extract 1st line & escape + "&body=", + weac.format.escape(table.concat({ + [[## Describe the bug +What's the bug? Be clear and detailed but concise in our explanation. Don't forget to include any context, error messages, logs, and screenshots required to understand the issue if applicable. + +## Reproduction steps +Steps to reproduce the behaviour: +1. Go to '...' +2. Click on '....' +3. Enter this command to '....' +4. See error + +## System information (please complete the following information) +- **Operating system and version:** [e.g. iOS] +- **Minetest version:** [e.g. 5.8.0] +- **WorldEdit version:** +- **WorldEditAdditions version:** + +Please add any other additional specific system information here too if you think it would help. + +## Stack trace +- **Command name:** ]], + cmdname, + "\n", + "```\n", + stack_trace, + "\n", + "```\n", + }, "")), + + "\n", + "-------------------------------------\n", + "*** Stack trace ***\n", + stack_trace, + "\n", + "-------------------------------------\n" + }, "") + + print("DEBUG:player_notify player_name", player_name, "msg_compiled", msg_compiled) + worldedit.player_notify(player_name, msg_compiled) +end + + +--- Calls the given function `fn` with the UNPACKED arguments from `args`, catching errors and sending the calling player a nice error message with a report link. +-- +-- WARNING: Do NOT nest `safe_function()` calls!!! +-- @param fn function The function to call +-- @param args table The table of args to unpack and send to `fn` as arguments +-- @param string|nil player_name The name of the player affected. If nil then no message is sent to the player. +-- @param string error_msg The error message to send when `fn` inevitably crashes. +-- @param string|nil cmdname Optional. The name of the command being run. +-- @returns bool,any,... A success bool (true == success), and then if success == true the rest of the arguments are the (unpacked) return values from the function called. +function safe_function(fn, args, player_name, error_msg, cmdname) + local retvals + local success_xpcall, stack_trace = xpcall(function() + retvals = { fn(weac.table.unpack(args)) } + end, debug.traceback) + + if not success_xpcall then + send_error(player_name, cmdname, error_msg, stack_trace) + return false + end + + return true, weac.table.unpack(retvals) +end + + +return safe_function diff --git a/worldeditadditions_core/init.lua b/worldeditadditions_core/init.lua index c58f545..56af033 100644 --- a/worldeditadditions_core/init.lua +++ b/worldeditadditions_core/init.lua @@ -86,6 +86,7 @@ dofile(wea_c.modpath.."/utils/player.lua") -- Player info functions wea_c.setting_handler = dofile(wea_c.modpath.."/utils/setting_handler.lua") -- AFTER parser wea_c.pos = dofile(modpath.."/core/pos.lua") -- AFTER EventEmitter +wea_c.safe_function = dofile(modpath.."/core/safe_function.lua") wea_c.register_command = dofile(modpath.."/core/register_command.lua") wea_c.command_exists = dofile(modpath.."/core/command_exists.lua") wea_c.fetch_command_def = dofile(modpath.."/core/fetch_command_def.lua")