From 883caff58df232c862de20427e33820f9512e598 Mon Sep 17 00:00:00 2001 From: imre84 Date: Sat, 20 Apr 2024 20:00:41 +0200 Subject: [PATCH] Make //lua work with expressions as well (#243) --- .luacheckrc | 3 ++- WorldEdit API.md | 14 +++++++++++--- worldedit/code.lua | 28 ++++++++++++++++++++-------- worldedit_commands/init.lua | 23 +++++++++++++++++------ 4 files changed, 50 insertions(+), 18 deletions(-) diff --git a/.luacheckrc b/.luacheckrc index 96399b6..139c9e2 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -1,6 +1,7 @@ read_globals = {"minetest", "vector", "VoxelArea", "ItemStack", "table", - "unified_inventory", "sfinv", "smart_inventory", "inventory_plus" + "unified_inventory", "sfinv", "smart_inventory", "inventory_plus", + "dump" } globals = {"worldedit"} -- Ignore these errors until someone decides to fix them diff --git a/WorldEdit API.md b/WorldEdit API.md index fc9cf65..ae27f41 100644 --- a/WorldEdit API.md +++ b/WorldEdit API.md @@ -227,11 +227,19 @@ Code ---- Contained in code.lua, this module allows arbitrary Lua code to be used with WorldEdit. -### error = worldedit.lua(code) +### error = worldedit.lua(code, name) -Executes `code` as a Lua chunk in the global namespace. +the given code gets encapsulated into a function with parameters `name`, `player`, `pos` +where + * `name` is a playername or `nil` + * `player` is the player object of the above player if applicable, otherwise `nil` + * `pos` is the position of the aforementioned player (if applicable, otherwise `nil`) rounded to integers -Returns an error if the code fails or nil otherwise. +the resulting function is then executed as a Lua chunk in the global namespace. + +The return is + * a string in case of an error + * a tuple of `nil` and return of the function converted to a string in case of success ### error = worldedit.luatransform(pos1, pos2, code) diff --git a/worldedit/code.lua b/worldedit/code.lua index eb42e3d..f985d28 100644 --- a/worldedit/code.lua +++ b/worldedit/code.lua @@ -2,17 +2,29 @@ -- @module worldedit.code --- Executes `code` as a Lua chunk in the global namespace. --- @return An error message if the code fails, or nil on success. -function worldedit.lua(code) - local func, err = loadstring(code) - if not func then -- Syntax error +-- the code will be encapsulated into a function with parameters +-- * name (the name of the player issuing the //lua command) +-- * player (the player object of the player) +-- * pos (the position of the player rounded to integers) +-- @return string in case of error, tuple of nil, return of code as string in case of success +function worldedit.lua(code, name) + local factory, err = loadstring("return function(name, player, pos)\n" .. code .. "\nend") + if not factory then -- Syntax error return err end - local good, err = pcall(func) - if not good then -- Runtime error - return err + local func = factory() + local player, pos + if name then + player = minetest.get_player_by_name(name) + if player then + pos = vector.round(player:get_pos()) + end end - return nil + local good, err = pcall(func, name, player, pos) + if not good then -- Runtime error + return tostring(err) + end + return nil, dump(err) end diff --git a/worldedit_commands/init.lua b/worldedit_commands/init.lua index fc67e5a..bf91bce 100644 --- a/worldedit_commands/init.lua +++ b/worldedit_commands/init.lua @@ -1555,16 +1555,27 @@ worldedit.register_command("lua", { description = S("Executes as a Lua chunk in the global namespace"), privs = {worldedit=true, server=true}, parse = function(param) + if param == "" then + return false + end return true, param end, func = function(name, param) - local err = worldedit.lua(param) - if err then - worldedit.player_notify(name, "code error: " .. err) - minetest.log("action", name.." tried to execute "..param) + -- shorthand like in the Lua interpreter + if param:sub(1, 1) == "=" then + param = "return " .. param:sub(2) + end + local err, ret = worldedit.lua(param, name) + if err == nil then + minetest.log("action", name .. " executed " .. param) + if ret ~= "nil" then + worldedit.player_notify(name, "code successfully executed, returned " .. ret) + else + worldedit.player_notify(name, "code successfully executed") + end else - worldedit.player_notify(name, "code successfully executed", false) - minetest.log("action", name.." executed "..param) + minetest.log("action", name .. " tried to execute " .. param) + worldedit.player_notify(name, "code error: " .. err) end end, })