chatcommands.lua 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. -- Minetest: builtin/chatcommands.lua
  2. --
  3. -- Chat command handler
  4. --
  5. minetest.chatcommands = {}
  6. function minetest.register_chatcommand(cmd, def)
  7. def = def or {}
  8. def.params = def.params or ""
  9. def.description = def.description or ""
  10. def.privs = def.privs or {}
  11. minetest.chatcommands[cmd] = def
  12. end
  13. minetest.register_on_chat_message(function(name, message)
  14. local cmd, param = string.match(message, "^/([^ ]+) *(.*)")
  15. if not param then
  16. param = ""
  17. end
  18. local cmd_def = minetest.chatcommands[cmd]
  19. if cmd_def then
  20. if not cmd_def.func then
  21. -- This is a C++ command
  22. return false
  23. else
  24. local has_privs, missing_privs = minetest.check_player_privs(name, cmd_def.privs)
  25. if has_privs then
  26. cmd_def.func(name, param)
  27. else
  28. minetest.chat_send_player(name, "You don't have permission to run this command (missing privileges: "..table.concat(missing_privs, ", ")..")")
  29. end
  30. return true -- handled chat message
  31. end
  32. end
  33. return false
  34. end)
  35. --
  36. -- Chat commands
  37. --
  38. -- Register C++ commands without functions
  39. minetest.register_chatcommand("me", {params = nil, description = "chat action (eg. /me orders a pizza)"})
  40. minetest.register_chatcommand("status", {description = "print server status line"})
  41. minetest.register_chatcommand("shutdown", {params = "", description = "shutdown server", privs = {server=true}})
  42. minetest.register_chatcommand("clearobjects", {params = "", description = "clear all objects in world", privs = {server=true}})
  43. minetest.register_chatcommand("time", {params = "<0...24000>", description = "set time of day", privs = {settime=true}})
  44. minetest.register_chatcommand("ban", {params = "<name>", description = "ban IP of player", privs = {ban=true}})
  45. minetest.register_chatcommand("unban", {params = "<name/ip>", description = "remove IP ban", privs = {ban=true}})
  46. -- Register other commands
  47. minetest.register_chatcommand("help", {
  48. privs = {},
  49. params = "(nothing)/all/privs/<cmd>",
  50. description = "Get help for commands or list privileges",
  51. func = function(name, param)
  52. local format_help_line = function(cmd, def)
  53. local msg = "/"..cmd
  54. if def.params and def.params ~= "" then msg = msg .. " " .. def.params end
  55. if def.description and def.description ~= "" then msg = msg .. ": " .. def.description end
  56. return msg
  57. end
  58. if param == "" then
  59. local msg = ""
  60. cmds = {}
  61. for cmd, def in pairs(minetest.chatcommands) do
  62. if minetest.check_player_privs(name, def.privs) then
  63. table.insert(cmds, cmd)
  64. end
  65. end
  66. minetest.chat_send_player(name, "Available commands: "..table.concat(cmds, " "))
  67. minetest.chat_send_player(name, "Use '/help <cmd>' to get more information, or '/help all' to list everything.")
  68. elseif param == "all" then
  69. minetest.chat_send_player(name, "Available commands:")
  70. for cmd, def in pairs(minetest.chatcommands) do
  71. if minetest.check_player_privs(name, def.privs) then
  72. minetest.chat_send_player(name, format_help_line(cmd, def))
  73. end
  74. end
  75. elseif param == "privs" then
  76. minetest.chat_send_player(name, "Available privileges:")
  77. for priv, def in pairs(minetest.registered_privileges) do
  78. minetest.chat_send_player(name, priv..": "..def.description)
  79. end
  80. else
  81. local cmd = param
  82. def = minetest.chatcommands[cmd]
  83. if not def then
  84. minetest.chat_send_player(name, "Command not available: "..cmd)
  85. else
  86. minetest.chat_send_player(name, format_help_line(cmd, def))
  87. end
  88. end
  89. end,
  90. })
  91. minetest.register_chatcommand("privs", {
  92. params = "<name>",
  93. description = "print out privileges of player",
  94. func = function(name, param)
  95. if param == "" then
  96. param = name
  97. else
  98. --[[if not minetest.check_player_privs(name, {privs=true}) then
  99. minetest.chat_send_player(name, "Privileges of "..param.." are hidden from you.")
  100. return
  101. end]]
  102. end
  103. minetest.chat_send_player(name, "Privileges of "..param..": "..minetest.privs_to_string(minetest.get_player_privs(param), ' '))
  104. end,
  105. })
  106. minetest.register_chatcommand("grant", {
  107. params = "<name> <privilege>|all",
  108. description = "Give privilege to player",
  109. privs = {},
  110. func = function(name, param)
  111. if not minetest.check_player_privs(name, {privs=true}) and
  112. not minetest.check_player_privs(name, {basic_privs=true}) then
  113. minetest.chat_send_player(name, "Your privileges are insufficient.")
  114. return
  115. end
  116. local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
  117. if not grantname or not grantprivstr then
  118. minetest.chat_send_player(name, "Invalid parameters (see /help grant)")
  119. return
  120. end
  121. local grantprivs = minetest.string_to_privs(grantprivstr)
  122. if grantprivstr == "all" then
  123. grantprivs = minetest.registered_privileges
  124. end
  125. local privs = minetest.get_player_privs(grantname)
  126. local privs_known = true
  127. for priv, _ in pairs(grantprivs) do
  128. if priv ~= "interact" and priv ~= "shout" and priv ~= "interact_extra" and not minetest.check_player_privs(name, {privs=true}) then
  129. minetest.chat_send_player(name, "Your privileges are insufficient.")
  130. return
  131. end
  132. if not minetest.registered_privileges[priv] then
  133. minetest.chat_send_player(name, "Unknown privilege: "..priv)
  134. privs_known = false
  135. end
  136. privs[priv] = true
  137. end
  138. if not privs_known then
  139. return
  140. end
  141. minetest.set_player_privs(grantname, privs)
  142. minetest.chat_send_player(name, "Privileges of "..grantname..": "..minetest.privs_to_string(minetest.get_player_privs(grantname), ' '))
  143. if grantname ~= name then
  144. minetest.chat_send_player(grantname, name.." granted you privileges: "..minetest.privs_to_string(grantprivs, ' '))
  145. end
  146. end,
  147. })
  148. minetest.register_chatcommand("revoke", {
  149. params = "<name> <privilege>|all",
  150. description = "Remove privilege from player",
  151. privs = {},
  152. func = function(name, param)
  153. if not minetest.check_player_privs(name, {privs=true}) and
  154. not minetest.check_player_privs(name, {basic_privs=true}) then
  155. minetest.chat_send_player(name, "Your privileges are insufficient.")
  156. return
  157. end
  158. local revokename, revokeprivstr = string.match(param, "([^ ]+) (.+)")
  159. if not revokename or not revokeprivstr then
  160. minetest.chat_send_player(name, "Invalid parameters (see /help revoke)")
  161. return
  162. end
  163. local revokeprivs = minetest.string_to_privs(revokeprivstr)
  164. local privs = minetest.get_player_privs(revokename)
  165. for priv, _ in pairs(revokeprivs) do
  166. if priv ~= "interact" and priv ~= "shout" and priv ~= "interact_extra" and not minetest.check_player_privs(name, {privs=true}) then
  167. minetest.chat_send_player(name, "Your privileges are insufficient.")
  168. return
  169. end
  170. end
  171. if revokeprivstr == "all" then
  172. privs = {}
  173. else
  174. for priv, _ in pairs(revokeprivs) do
  175. privs[priv] = nil
  176. end
  177. end
  178. minetest.set_player_privs(revokename, privs)
  179. minetest.chat_send_player(name, "Privileges of "..revokename..": "..minetest.privs_to_string(minetest.get_player_privs(revokename), ' '))
  180. if revokename ~= name then
  181. minetest.chat_send_player(revokename, name.." revoked privileges from you: "..minetest.privs_to_string(revokeprivs, ' '))
  182. end
  183. end,
  184. })
  185. minetest.register_chatcommand("setpassword", {
  186. params = "<name> <password>",
  187. description = "set given password",
  188. privs = {password=true},
  189. func = function(name, param)
  190. if param == "" then
  191. minetest.chat_send_player(name, "Password field required")
  192. return
  193. end
  194. minetest.set_player_password(name, param)
  195. minetest.chat_send_player(name, "Password set")
  196. end,
  197. })
  198. minetest.register_chatcommand("clearpassword", {
  199. params = "<name>",
  200. description = "set empty password",
  201. privs = {password=true},
  202. func = function(name, param)
  203. minetest.set_player_password(name, '')
  204. minetest.chat_send_player(name, "Password cleared")
  205. end,
  206. })
  207. minetest.register_chatcommand("auth_reload", {
  208. params = "",
  209. description = "reload authentication data",
  210. privs = {server=true},
  211. func = function(name, param)
  212. local done = minetest.auth_reload()
  213. if done then
  214. minetest.chat_send_player(name, "Done.")
  215. else
  216. minetest.chat_send_player(name, "Failed.")
  217. end
  218. end,
  219. })
  220. minetest.register_chatcommand("teleport", {
  221. params = "<X>,<Y>,<Z> | <to_name> | <name> <X>,<Y>,<Z> | <name> <to_name>",
  222. description = "teleport to given position",
  223. privs = {teleport=true},
  224. func = function(name, param)
  225. -- Returns (pos, true) if found, otherwise (pos, false)
  226. local function find_free_position_near(pos)
  227. local tries = {
  228. {x=1,y=0,z=0},
  229. {x=-1,y=0,z=0},
  230. {x=0,y=0,z=1},
  231. {x=0,y=0,z=-1},
  232. }
  233. for _, d in ipairs(tries) do
  234. local p = {x = pos.x+d.x, y = pos.y+d.y, z = pos.z+d.z}
  235. local n = minetest.env:get_node(p)
  236. if not minetest.registered_nodes[n.name].walkable then
  237. return p, true
  238. end
  239. end
  240. return pos, false
  241. end
  242. local teleportee = nil
  243. local p = {}
  244. p.x, p.y, p.z = string.match(param, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
  245. teleportee = minetest.env:get_player_by_name(name)
  246. if teleportee and p.x and p.y and p.z then
  247. minetest.chat_send_player(name, "Teleporting to ("..p.x..", "..p.y..", "..p.z..")")
  248. teleportee:setpos(p)
  249. return
  250. end
  251. local teleportee = nil
  252. local p = nil
  253. local target_name = nil
  254. target_name = string.match(param, "^([^ ]+)$")
  255. teleportee = minetest.env:get_player_by_name(name)
  256. if target_name then
  257. local target = minetest.env:get_player_by_name(target_name)
  258. if target then
  259. p = target:getpos()
  260. end
  261. end
  262. if teleportee and p then
  263. p = find_free_position_near(p)
  264. minetest.chat_send_player(name, "Teleporting to "..target_name.." at ("..p.x..", "..p.y..", "..p.z..")")
  265. teleportee:setpos(p)
  266. return
  267. end
  268. if minetest.check_player_privs(name, {bring=true}) then
  269. local teleportee = nil
  270. local p = {}
  271. local teleportee_name = nil
  272. teleportee_name, p.x, p.y, p.z = string.match(param, "^([^ ]+) +([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
  273. if teleportee_name then
  274. teleportee = minetest.env:get_player_by_name(teleportee_name)
  275. end
  276. if teleportee and p.x and p.y and p.z then
  277. minetest.chat_send_player(name, "Teleporting "..teleportee_name.." to ("..p.x..", "..p.y..", "..p.z..")")
  278. teleportee:setpos(p)
  279. return
  280. end
  281. local teleportee = nil
  282. local p = nil
  283. local teleportee_name = nil
  284. local target_name = nil
  285. teleportee_name, target_name = string.match(param, "^([^ ]+) +([^ ]+)$")
  286. if teleportee_name then
  287. teleportee = minetest.env:get_player_by_name(teleportee_name)
  288. end
  289. if target_name then
  290. local target = minetest.env:get_player_by_name(target_name)
  291. if target then
  292. p = target:getpos()
  293. end
  294. end
  295. if teleportee and p then
  296. p = find_free_position_near(p)
  297. minetest.chat_send_player(name, "Teleporting "..teleportee_name.." to "..target_name.." at ("..p.x..", "..p.y..", "..p.z..")")
  298. teleportee:setpos(p)
  299. return
  300. end
  301. end
  302. minetest.chat_send_player(name, "Invalid parameters (\""..param.."\") or player not found (see /help teleport)")
  303. return
  304. end,
  305. })
  306. minetest.register_chatcommand("set", {
  307. params = "[-n] <name> <value> | <name>",
  308. description = "set or read server configuration setting",
  309. privs = {server=true},
  310. func = function(name, param)
  311. local arg, setname, setvalue = string.match(param, "(-[n]) ([^ ]+) (.+)")
  312. if arg and arg == "-n" and setname and setvalue then
  313. minetest.setting_set(setname, setvalue)
  314. minetest.chat_send_player(name, setname.." = "..setvalue)
  315. return
  316. end
  317. local setname, setvalue = string.match(param, "([^ ]+) (.+)")
  318. if setname and setvalue then
  319. if not minetest.setting_get(setname) then
  320. minetest.chat_send_player(name, "Failed. Use '/set -n <name> <value>' to create a new setting.")
  321. return
  322. end
  323. minetest.setting_set(setname, setvalue)
  324. minetest.chat_send_player(name, setname.." = "..setvalue)
  325. return
  326. end
  327. local setname = string.match(param, "([^ ]+)")
  328. if setname then
  329. local setvalue = minetest.setting_get(setname)
  330. if not setvalue then
  331. setvalue = "<not set>"
  332. end
  333. minetest.chat_send_player(name, setname.." = "..setvalue)
  334. return
  335. end
  336. minetest.chat_send_player(name, "Invalid parameters (see /help set)")
  337. end,
  338. })