chatcommands.lua 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. ------------------------------------------------------------------------------
  2. -- This file is registered as reloadable.
  3. ------------------------------------------------------------------------------
  4. if not minetest.global_exists("reload") then reload = {} end
  5. reload.impl = reload.impl or {}
  6. -- This function expects only to be called from the chatcommands that this mod registers!
  7. reload.impl.dofile = function(name, path)
  8. local PREFIX = reload.chat_prefix
  9. local FILEPATH = path
  10. if type(path) == "string" and type(name) == "string" then
  11. if path == "" then
  12. reload.chat_send_player(name, PREFIX .. "No filepath provided.")
  13. return false
  14. end
  15. -- Log this action.
  16. reload.log("action", "[Mod Reload] Player <" .. name .. "> attempts to execute Lua source file '" .. FILEPATH .. "'.")
  17. -- A bit of security.
  18. if string.find(path, "%.%.") then
  19. reload.chat_send_player(name, PREFIX .. "Filepath cannot include '..' tokens.")
  20. return false
  21. end
  22. -- Attempt to load and execute the Lua file.
  23. local func, err = loadfile(FILEPATH)
  24. if not func then -- Syntax error.
  25. reload.chat_send_player(name, PREFIX .. "Could not load file. Received error message: '" .. err .. "'.")
  26. return false
  27. end
  28. local good, err = pcall(func)
  29. if not good then -- Runtime error.
  30. reload.chat_send_player(name, PREFIX .. "Could not execute file. Received error message: '" .. err .. "'.")
  31. return false
  32. end
  33. reload.chat_send_player(name, PREFIX .. "File '" .. FILEPATH .. "' successfully executed.")
  34. return true
  35. else
  36. reload.chat_send_player(name, PREFIX .. "Invalid arguments.")
  37. return false
  38. end
  39. end
  40. -- This function expects only to be called from the chatcommands that this mod registers!
  41. reload.impl.reload = function(name, param)
  42. local PREFIX = reload.chat_prefix
  43. local ROOT = reload.root_path .. "/"
  44. local sparams = string.split(param, " ")
  45. local sfind = nil
  46. -- total files count
  47. local itotal = 0
  48. -- search result count
  49. local ifound = 0
  50. if sparams[1] == "list" then
  51. if type(sparams[2]) == "string" then
  52. sfind = sparams[2]
  53. end
  54. for k, v in pairs(reload.impl.files) do
  55. -- counting reloadable files
  56. itotal = itotal + 1
  57. local found = true
  58. if sfind then
  59. found = string.find(k, sfind, 1, false)
  60. end
  61. if found then
  62. -- counting search results
  63. ifound = ifound + 1
  64. -- get root relative path
  65. local srelpath = string.gsub(v, "^" .. ROOT, "")
  66. local sfmt = "%s %-32s '%s'."
  67. local sfileid = "<" .. k .. ">"
  68. local smsg = string.format(sfmt, PREFIX, sfileid, srelpath)
  69. reload.chat_send_player(name, smsg)
  70. end
  71. end
  72. local smsg = string.format("%s Listed %d of %d reloadable files.",
  73. PREFIX, ifound, itotal)
  74. reload.chat_send_player(name, smsg)
  75. reload.chat_send_player(name, PREFIX .. "End of list.")
  76. return true
  77. else
  78. if not param or param == "" then
  79. reload.chat_send_player(name, PREFIX .. "No file ID provided.")
  80. return false
  81. end
  82. local file = reload.impl.files[param]
  83. if file then
  84. return reload.impl.dofile(name, file)
  85. end
  86. reload.chat_send_player(name, PREFIX .. "Invalid file ID.")
  87. return false
  88. end
  89. end
  90. reload.impl.execute = function(name, path)
  91. local path2 = reload.root_path .. "/" .. path
  92. return reload.impl.dofile(name, path2)
  93. end
  94. reload.impl.dostring = function(name, str)
  95. local PREFIX = reload.chat_prefix
  96. if not str or str == "" then
  97. reload.chat_send_player(name, PREFIX .. "No argument provided.")
  98. reload.chat_send_player(name, PREFIX .. "Note: available custom variables are: me, mypos, player(name), print(text).")
  99. return false
  100. end
  101. -- Code injection.
  102. local ci = "do " .. -- Begin new block.
  103. "local me=minetest.get_player_by_name(\"" .. name .. "\") " ..
  104. "local mypos=me:get_pos() " ..
  105. "local myname=me:get_player_name() " ..
  106. "local held=me:get_wielded_item()" ..
  107. "local function player(pname) return minetest.get_player_by_name(pname) end " ..
  108. "local function print(text) minetest.chat_send_player(\"" .. name .. "\", \"# Server: \" .. text) end " ..
  109. str .. " end" -- User code & end of block.
  110. local func, err = loadstring(ci)
  111. if not func then -- Syntax error.
  112. reload.chat_send_player(name, PREFIX .. "Could not compile string. Received error message: '" .. err .. "'.")
  113. return false
  114. end
  115. local good, err = pcall(func)
  116. if not good then -- Runtime error.
  117. reload.chat_send_player(name, PREFIX .. "Could not execute string. Received error message: '" .. err .. "'.")
  118. return false
  119. end
  120. reload.chat_send_player(name, PREFIX .. "Code executed successfully!")
  121. return true
  122. end
  123. -- Don't register the chat commands more than once, even if this file is reloaded.
  124. if not reload.chat_registered then
  125. minetest.register_chatcommand("reload", {
  126. params = "<fileid> | list [search]",
  127. description = "Reload a registered source file at runtime.",
  128. -- Player must have server priviliges.
  129. privs = {server=true},
  130. func = function(...) reload.impl.reload(...) end,
  131. })
  132. minetest.register_chatcommand("exec", {
  133. params = "<filepath>",
  134. description = "Load and execute an arbitrary Lua source file.",
  135. -- Player must have server priviliges.
  136. privs = {server=true},
  137. func = function(...) reload.impl.execute(...) end,
  138. })
  139. minetest.register_chatcommand("run", {
  140. params = "<filepath>",
  141. description = "Load and execute an arbitrary Lua source file.",
  142. -- Player must have server priviliges.
  143. privs = {server=true},
  144. func = function(...) reload.impl.execute(...) end,
  145. })
  146. minetest.register_chatcommand("dofile", {
  147. params = "<filepath>",
  148. description = "Load and execute an arbitrary Lua source file.",
  149. -- Player must have server priviliges.
  150. privs = {server=true},
  151. func = function(...) reload.impl.execute(...) end,
  152. })
  153. -- Alias name. Some people (like me) keep wanting to spell it out.
  154. minetest.register_chatcommand("execute", {
  155. params = "<filepath>",
  156. description = "Load and execute an arbitrary Lua source file.",
  157. -- Player must have server priviliges.
  158. privs = {server=true},
  159. func = function(...) reload.impl.execute(...) end,
  160. })
  161. minetest.register_chatcommand("dostring", {
  162. params = "<code>",
  163. description = "Execute a statement in Lua.",
  164. -- Player must have server priviliges.
  165. privs = {server=true},
  166. func = function(...) reload.impl.dostring(...) end,
  167. })
  168. minetest.register_chatcommand("lua", {
  169. params = "<code>",
  170. description = "Execute a statement in Lua.",
  171. -- Player must have server priviliges.
  172. privs = {server=true},
  173. func = function(...) reload.impl.dostring(...) end,
  174. })
  175. minetest.register_chatcommand("dolua", {
  176. params = "<code>",
  177. description = "Execute a statement in Lua.",
  178. -- Player must have server priviliges.
  179. privs = {server=true},
  180. func = function(...) reload.impl.dostring(...) end,
  181. })
  182. reload.chat_registered = true
  183. end