turn wea_core into an EventEmitter; emit command execution pipeline events

These are subject to feedback and change - please let me know if they are named sensibly or not!
This commit is contained in:
Starbeamrainbowlabs 2024-09-13 02:52:35 +01:00
parent f09e10ae49
commit 8c4d503f1f
No known key found for this signature in database
GPG Key ID: 1BE5172E637709C2
2 changed files with 91 additions and 9 deletions

@ -8,15 +8,77 @@ local human_size = wea_c.format.human_size
-- TODO: Reimplement worldedit.player_notify(player_name, msg_text) -- TODO: Reimplement worldedit.player_notify(player_name, msg_text)
local function run_command_stage2(player_name, func, parse_result) --- Actually runs the command in question.
-- Unfortunately needed to keep the codebase clena because Lua sucks.
-- @internal
-- @param player_name string The name of the player executing the function.
-- @param func function The function to execute.
-- @param parse_result table The output of the parsing function that was presumably called earlier. Will be unpacked and passed to `func` as arguments.
-- @param tbl_event table Internal event table used when calling `worldeditadditions_core.emit(event_name, tbl_event)`.
-- @returns nil
local function run_command_stage2(player_name, func, parse_result, tbl_event)
wea_c.emit("pre-execute", tbl_event)
local success, result_message = func(player_name, wea_c.table.unpack(parse_result)) local success, result_message = func(player_name, wea_c.table.unpack(parse_result))
if result_message then if result_message then
-- TODO: If we were unsuccessfull, then colour the message red -- TODO: If we were unsuccessful, then colour the message red
worldedit.player_notify(player_name, result_message) worldedit.player_notify(player_name, result_message)
end end
tbl_event.success = success
tbl_event.result = result_message
wea_c.emit("post-execute", tbl_event)
end end
--- Command execution pipeline: before `paramtext` parsing but after validation.
--
-- See `worldeditadditions_core.run_command`
-- @event pre-parse
-- @format { player_name: string, cmddef: table, paramtext: string }
--- Command execution pipeline: directly after `paramtext` parsing
--
-- See `worldeditadditions_core.run_command`
-- @event post-parse
-- @format { player_name: string, cmddef: table, paramtext: string, paramargs: table }
--- Command execution pipeline: after the `nodesneeded` function is called (if provided).
--
-- See `worldeditadditions_core.run_command`
-- @event post-nodesneeded
-- @format { player_name: string, cmddef: table, paramtext: string, paramargs: table, potential_changes: number }
--- Command execution pipeline: directly before the command is invoked.
--
-- See `worldeditadditions_core.run_command`
-- @event pre-execute
-- @format { player_name: string, cmddef: table, paramtext: string, paramargs: table, potential_changes: number }
--- Command execution pipeline: after the command is executed.
--
-- See `worldeditadditions_core.run_command`
-- @event post-execute
-- @format { player_name: string, cmddef: table, paramtext: string, paramargs: table, potential_changes: number, success: boolean, result: any }
--- Runs a command with the given name and options for the given player. --- Runs a command with the given name and options for the given player.
-- Emits several events in the process, in the following order:
-- 1. **`pre-parse`:** Before `paramtext` parsing but after validation.
-- 2. **`post-parse`:** Directly after `paramtext` parsing
-- 3. **`post-nodesneeded`:** If a `nodesneeded` function is provided, this executes after the nodesneeded function is called.
-- 4. **`pre-execute`:** Directly before the command is invoked.
-- 5. **`post-execute`:** After the command is executed.
--
-- Items #4 and #5 here are actually emitted by the private internal function `run_command_stage2`.
--
-- The event object passed has the following properties:
-- - `cmddef` (table): The WEA-registered definition of the command
-- - `cmdname` (string): The name of the command, sans-forward slashes
-- - `paramtext` (string): The unparsed `paramtext` the user passed as argument(s) to the command.
-- - `player_name` (string): The name of the player calling the command.
-- - `paramargs` (table): The parsed arguments returned by the parsing function. Available in `post-parse` and later.
-- - `potential_changes` (number): The number of potential nodes that could be changed as a result of running the command. `post-nodesneeded` and later: remember not all commands have an associated `nodesneeded` function.
-- - `success` (boolean): Whether the command executed successfully or not. Available only in `post-execute`.
-- - `result` (any): The `result` value returned by the command function. Value depends on the command executed. Available only in `post-execute`.
-- @param cmdname string The name of the command to run. -- @param cmdname string The name of the command to run.
-- @param options table The table of options associated with the command. See worldeditadditions_core.register_command for more information. -- @param options table The table of options associated with the command. See worldeditadditions_core.register_command for more information.
-- @param player_name string The name of the player to execute the command for. -- @param player_name string The name of the player to execute the command for.
@ -36,6 +98,15 @@ local function run_command(cmdname, options, player_name, paramtext)
return false return false
end end
local tbl_event = {
cmddef = options,
cmdname = cmdname,
paramtext = paramtext,
player_name = player_name
}
wea_c.emit("pre-parse", tbl_event)
local parse_result = { options.parse(paramtext) } local parse_result = { options.parse(paramtext) }
local success = table.remove(parse_result, 1) local success = table.remove(parse_result, 1)
if not success then if not success then
@ -43,8 +114,16 @@ local function run_command(cmdname, options, player_name, paramtext)
return false return false
end end
tbl_event.paramargs = parse_result
weac.emit("post-parse", tbl_event)
if options.nodes_needed then if options.nodes_needed then
local potential_changes = options.nodes_needed(player_name, wea_c.table.unpack(parse_result)) local potential_changes = options.nodes_needed(player_name, wea_c.table.unpack(parse_result))
tbl_event.potential_changes = potential_changes
wea_c.emit("post-nodesneeded", tbl_event)
if type(potential_changes) ~= "number" then if type(potential_changes) ~= "number" then
worldedit.player_notify(player_name, "Error: The command '"..cmdname.."' returned a "..type(potential_changes).." instead of a number when asked how many nodes might be changed. Abort. This is a bug.") worldedit.player_notify(player_name, "Error: The command '"..cmdname.."' returned a "..type(potential_changes).." instead of a number when asked how many nodes might be changed. Abort. This is a bug.")
return return
@ -59,13 +138,13 @@ local function run_command(cmdname, options, player_name, paramtext)
elseif potential_changes > limit then elseif potential_changes > limit then
worldedit.player_notify(player_name, "/"..cmdname.." "..paramtext.." may affect up to "..human_size(potential_changes).." nodes. Type //y to continue, or //n to cancel (see the //saferegion command to control when this message appears).") worldedit.player_notify(player_name, "/"..cmdname.." "..paramtext.." may affect up to "..human_size(potential_changes).." nodes. Type //y to continue, or //n to cancel (see the //saferegion command to control when this message appears).")
safe_region(player_name, cmdname, function() safe_region(player_name, cmdname, function()
run_command_stage2(player_name, options.func, parse_result) run_command_stage2(player_name, options.func, parse_result, tbl_event)
end) end)
else else
run_command_stage2(player_name, options.func, parse_result) run_command_stage2(player_name, options.func, parse_result, tbl_event)
end end
else else
run_command_stage2(player_name, options.func, parse_result) run_command_stage2(player_name, options.func, parse_result, tbl_event)
end end
end end

@ -1,4 +1,5 @@
--- WorldEditAdditions-Core --- WorldEditAdditions core engine
-- This namespace contains the core command processing engine used by WorldEditAdditions and associated parsing, formatting, and utility functions. It does not contain any of the commands themselves - see the namespace/'mod' simply called 'worldeditadditions' for that.
-- @namespace worldeditadditions_core -- @namespace worldeditadditions_core
-- @release 1.14.5 -- @release 1.14.5
-- @copyright 2021 Starbeamrainbowlabs and VorTechnix -- @copyright 2021 Starbeamrainbowlabs and VorTechnix
@ -8,7 +9,9 @@
local modpath = minetest.get_modpath("worldeditadditions_core") local modpath = minetest.get_modpath("worldeditadditions_core")
worldeditadditions_core = { local EventEmitter = dofile(modpath .. "/utils/EventEmitter.lua")
worldeditadditions_core = EventEmitter.new({
version = "1.15-dev", version = "1.15-dev",
modpath = modpath, modpath = modpath,
registered_commands = {}, registered_commands = {},
@ -17,9 +20,9 @@ worldeditadditions_core = {
safe_region_limits = {}, safe_region_limits = {},
-- The default limit for new players on the number of potential nodes changed before safe_region kicks in. -- The default limit for new players on the number of potential nodes changed before safe_region kicks in.
safe_region_limit_default = 100000, safe_region_limit_default = 100000,
} })
local wea_c = worldeditadditions_core local wea_c = worldeditadditions_core
wea_c.EventEmitter = dofile(modpath.."/utils/EventEmitter.lua") wea_c.EventEmitter = EventEmitter
wea_c.Set = dofile(wea_c.modpath.."/utils/set.lua") wea_c.Set = dofile(wea_c.modpath.."/utils/set.lua")