2020-11-18 06:31:57 -08:00
local S = minetest.get_translator ( " cmdtool " )
local F = minetest.formspec_escape
2018-01-16 11:47:53 -08:00
local NEWLINE = " \n "
2020-11-18 06:31:57 -08:00
local DESCRIPTION = S ( " Command Tool " )
2018-01-16 12:19:59 -08:00
local MAX_CMD_TOOLTIP_LEN = 48
2020-11-18 06:53:55 -08:00
local print_result = minetest.settings : get_bool ( " cmdtool_print_result " , true )
2018-01-16 12:19:59 -08:00
local split_commands = function ( commands_string )
return string.split ( commands_string , NEWLINE )
end
2018-01-16 11:47:53 -08:00
local set_commands = function ( itemstack , commands_string )
local meta = itemstack : get_meta ( )
meta : set_string ( " cmd " , commands_string )
2018-01-16 12:19:59 -08:00
local cmds = split_commands ( commands_string )
local first_cmd
if # cmds >= 1 then
first_cmd = cmds [ 1 ]
if string.len ( first_cmd ) > MAX_CMD_TOOLTIP_LEN then
first_cmd = string.sub ( first_cmd , 1 , MAX_CMD_TOOLTIP_LEN ) .. " (…) "
end
local tooltip = DESCRIPTION .. NEWLINE .. first_cmd
if # cmds == 2 then
2020-11-18 06:31:57 -08:00
tooltip = tooltip .. NEWLINE .. S ( " … and 1 more command " )
2018-01-16 12:19:59 -08:00
elseif # cmds > 2 then
2020-11-18 06:31:57 -08:00
tooltip = tooltip .. NEWLINE .. S ( " … and @1 more command(s) " , # cmds - 1 )
2018-01-16 12:19:59 -08:00
end
meta : set_string ( " description " , tooltip )
else
meta : set_string ( " description " , " " )
end
2018-01-16 11:47:53 -08:00
return itemstack
end
-- Returns a table of commands in a command tool itemstack
local get_commands = function ( itemstack )
local meta = itemstack : get_meta ( )
local cmd_str = meta : get_string ( " cmd " )
2018-01-16 12:19:59 -08:00
local cmds = split_commands ( cmd_str )
2018-01-16 11:47:53 -08:00
return cmds
end
2018-01-16 13:04:19 -08:00
--[[ Takes a command and substitutes placeholders like “@playername” with the actual values.
This operation might fail .
Returns the substituted command on success .
Returns false on failure . ] ]
local substitute_placeholders = function ( command , itemstack , player , pointed_thing )
local pos_pt , pos_pl
pos_pl = player : get_pos ( )
if pointed_thing.type == " node " then
pos_pt = pointed_thing.under
command = string.gsub ( command , " @ptx " , pos_pt.x )
command = string.gsub ( command , " @pty " , pos_pt.y )
command = string.gsub ( command , " @ptz " , pos_pt.z )
local node = minetest.get_node ( pos_pt )
command = string.gsub ( command , " @nodename " , node.name )
command = string.gsub ( command , " @param2 " , node.param2 )
else
-- If one of the coordinate parameters is in the command, but
-- the pointed thing is not a node, we have to fail as the placeholders
-- are meaningless.
local coord = { " @ptx " , " @pty " , " @ptz " , " @nodename " , " @param2 " , " @light " }
for c = 1 , # coord do
if string.find ( command , coord [ c ] ) ~= nil then
return false
end
end
end
command = string.gsub ( command , " @plx " , pos_pl.x )
command = string.gsub ( command , " @ply " , pos_pl.y )
command = string.gsub ( command , " @plz " , pos_pl.z )
command = string.gsub ( command , " @playername " , player : get_player_name ( ) )
command = string.gsub ( command , " @@ " , " @ " )
return command
end
2018-01-16 11:47:53 -08:00
local execute_command = function ( itemstack , player , pointed_thing )
local player_name = player : get_player_name ( )
local cmds = get_commands ( itemstack )
if not cmds then
return
end
local player_privs = minetest.get_player_privs ( player_name )
for c = 1 , # cmds do
2020-11-23 10:43:49 -08:00
local cmd = cmds [ c ]
2018-01-16 13:04:19 -08:00
-- Substitution successful?
2018-01-16 11:47:53 -08:00
-- Split command string into command name and parameters
local cmd_split = string.split ( cmd , " " , false , 1 )
local cmd_name
-- Perform some checks:
-- 1. Command exists
-- 2. Player has all required privileges
if cmd_split then
-- Get command name
cmd_name = cmd_split [ 1 ]
local cmd_params = " "
if cmd_split [ 2 ] then
cmd_params = cmd_split [ 2 ]
end
2018-01-16 13:04:19 -08:00
cmd_params = substitute_placeholders ( cmd_params , itemstack , player , pointed_thing )
2018-01-16 11:47:53 -08:00
local def = minetest.registered_chatcommands [ cmd_name ]
2018-01-16 13:04:19 -08:00
-- Command exists? Placeholder substitution successful?
2018-01-16 11:47:53 -08:00
if def then
2018-01-16 13:04:19 -08:00
if cmd_params then
local required_privs = def.privs
for priv , _ in pairs ( required_privs ) do
if player_privs [ priv ] ~= true then
2020-11-18 06:31:57 -08:00
minetest.chat_send_player ( player_name , minetest.colorize ( " #FF0000 " , S ( " Insufficient privileges for command “@1”! You need the “@2” privilege. " , cmd_name , priv ) ) )
2018-01-16 13:04:19 -08:00
return
end
2018-01-16 11:47:53 -08:00
end
2018-01-16 13:04:19 -08:00
-- All tests survived!
-- Call the command
2020-11-18 06:31:57 -08:00
local retval , msg = def.func ( player_name , cmd_params )
-- Print return value and message
2020-11-18 06:53:55 -08:00
if print_result then
if retval == true then
-- Command successfull
minetest.chat_send_player ( player_name , minetest.colorize ( " #00FF00 " , " [ " .. S ( " OK " ) .. " ] " .. cmd ) )
elseif retval == false then
-- Command failed
minetest.chat_send_player ( player_name , minetest.colorize ( " #FF0000 " , " [ " .. S ( " FAIL " ) .. " ] " .. cmd ) )
elseif retval == nil then
-- Command result unknown
minetest.chat_send_player ( player_name , minetest.colorize ( " #FF8800 " , " [ " .. S ( " UNKN " ) .. " ] " .. cmd ) )
end
2020-11-18 06:31:57 -08:00
end
if msg ~= nil and msg ~= " " then
2020-11-18 06:53:55 -08:00
local out = msg
if print_result then
local out = " > " .. msg
end
minetest.chat_send_player ( player_name , out )
2020-11-18 06:31:57 -08:00
end
2018-01-16 13:04:19 -08:00
else
2020-11-18 06:31:57 -08:00
minetest.chat_send_player ( player_name , minetest.colorize ( " #FF0000 " , S ( " Nothing pointed! " ) ) )
2018-01-16 11:47:53 -08:00
end
else
2020-11-18 06:31:57 -08:00
minetest.chat_send_player ( player_name , minetest.colorize ( " #FF0000 " , S ( " The command “@1” does not exist! " , cmd_name ) ) )
2018-01-16 11:47:53 -08:00
return
end
else
2020-11-18 06:31:57 -08:00
minetest.chat_send_player ( player_name , minetest.colorize ( " #FF0000 " , S ( " Invalid command! " ) ) )
2018-01-16 11:47:53 -08:00
return
end
-- One iteration is done. We continue with the next command.
end
end
local open_command_configuration = function ( itemstack , player , pointed_thing )
local player_name = player : get_player_name ( )
local commands = get_commands ( itemstack )
local commands_str = " "
if commands then
for c = 1 , # commands do
commands_str = commands_str .. commands [ c ]
if c < # commands then
commands_str = commands_str .. " \n "
end
end
end
local formspec =
2020-11-18 06:39:09 -08:00
" size[12,6] " ..
" textarea[0.25,0.25;12,5;commands; " .. F ( S ( " Commands: " ) ) .. " ; " .. F ( commands_str ) .. " ] " ..
2020-11-18 06:31:57 -08:00
" button_exit[0.5,5;2,1;ok; " .. F ( S ( " OK " ) ) .. " ] " ..
" button_exit[3.5,5;2,1;cancel; " .. F ( S ( " Cancel " ) ) .. " ] "
2018-01-16 11:47:53 -08:00
minetest.show_formspec ( player_name , " cmdtool " , formspec )
end
minetest.register_tool ( " cmdtool:cmdtool " , {
2018-01-16 12:19:59 -08:00
description = DESCRIPTION ,
2020-11-18 06:31:57 -08:00
_doc_items_longdesc = S ( " This is a programmable tool which can be used to run server commands. " ) ,
_doc_items_usagehelp = S ( " This tool is very mighty, so handle with care! " ) .. " \n " ..
2020-11-18 06:33:03 -08:00
S ( " Use the [Place] key to set the commands. Write a list of server commands you wish to execute (with one command per line), in that order, but without the trailing slash like in the chat. Confirm with the OK button. " ) .. " \n " ..
2020-11-18 06:31:57 -08:00
S ( " To run the commands, use the attack key. Note that commands might fail if you lack the required privileges or you made a mistake. " ) .. " \n \n " ..
2018-01-16 13:25:17 -08:00
2020-11-18 06:31:57 -08:00
S ( " Optionally, you can use the following placeholders to insert variable values into your commands: " ) .. " \n " ..
S ( " • @playername: Your player name " ) .. " \n " ..
S ( " • @plx, @ply and @plz: Your player coordinates " ) .. " \n " ..
S ( " • @@: Literal at sign " ) .. " \n \n " ..
2018-01-16 13:25:17 -08:00
2020-11-18 06:31:57 -08:00
S ( " These placeholders only work when you use the tool on a block. " ) .. " \n " ..
S ( " • @ptx, @pty and @ptz: Coordinates of the pointed node (i.e. block) " ) .. " \n " ..
S ( " • @nodename: Itemstring of the pointed node " ) .. " \n " ..
S ( " • @param2: param2 of the pointed node " ) .. " \n \n " ..
2018-01-16 13:25:17 -08:00
2020-11-18 06:31:57 -08:00
S ( " Refer to “Advancd usage > Server commands” to learn more about server commands. " ) .. " \n \n \n " ..
2018-01-16 13:25:17 -08:00
2020-11-18 06:31:57 -08:00
S ( [ [ Example 1 :
2018-01-16 13:25:17 -08:00
time 12000
2020-11-18 06:31:57 -08:00
→ Sets time to midday . ] ] ) .. " \n \n " ..
2018-01-16 13:25:17 -08:00
2020-11-18 06:31:57 -08:00
S ( [ [ Example 2 :
2018-01-16 13:25:17 -08:00
teleport @ plx 9 @ plz
giveme default : apple
2020-11-18 06:31:57 -08:00
→ Teleports you to Y = 9 without changing the X and Z coordinates , then gives you an apple . ] ] ) ,
2018-01-16 11:47:53 -08:00
inventory_image = " cmdtool_cmdtool.png " ,
wield_imagee = " cmdtool_cmdtool.png " ,
2020-11-18 06:34:06 -08:00
groups = { disable_repair = 1 } ,
2018-01-16 12:05:18 -08:00
on_use = execute_command ,
on_place = open_command_configuration ,
on_secondary_use = open_command_configuration ,
2018-01-16 11:47:53 -08:00
} )
-- Set commands
minetest.register_on_player_receive_fields ( function ( player , formname , fields )
if formname == " cmdtool " and fields.ok and fields.commands ~= nil then
local wield_tool = player : get_wielded_item ( )
if wield_tool : get_name ( ) == " cmdtool:cmdtool " then
local updated_tool = set_commands ( wield_tool , fields.commands )
player : set_wielded_item ( updated_tool )
end
end
end )