chatcommands.lua 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. ------------------------------------------------------------------------------
  2. -- This file is registered as reloadable.
  3. ------------------------------------------------------------------------------
  4. reload = reload or {}
  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. if param == "list" then
  45. for k, v in pairs(reload.impl.files) do
  46. local count = 30
  47. count = count - string.len(k)
  48. if count < 0 then count = 0 end
  49. local spaces = string.rep(" ", count)
  50. local len = string.len(ROOT)
  51. local p = string.sub(v, len+1)
  52. reload.chat_send_player(name, PREFIX .. "<" .. k .. ">, " .. spaces .. "'" .. p .. "'.")
  53. end
  54. reload.chat_send_player(name, PREFIX .. "End of list.")
  55. return true
  56. else
  57. if not param or param == "" then
  58. reload.chat_send_player(name, PREFIX .. "No file ID provided.")
  59. return false
  60. end
  61. local file = reload.impl.files[param]
  62. if file then
  63. return reload.impl.dofile(name, file)
  64. end
  65. reload.chat_send_player(name, PREFIX .. "Invalid file ID.")
  66. return false
  67. end
  68. end
  69. reload.impl.execute = function(name, path)
  70. local path2 = reload.root_path .. "/" .. path
  71. return reload.impl.dofile(name, path2)
  72. end
  73. reload.impl.dostring = function(name, str)
  74. local PREFIX = reload.chat_prefix
  75. if not str or str == "" then
  76. reload.chat_send_player(name, PREFIX .. "No argument provided.")
  77. reload.chat_send_player(name, PREFIX .. "Note: available custom variables are: me, mypos, player(name), print(text).")
  78. return false
  79. end
  80. -- Code injection.
  81. local ci = "do " .. -- Begin new block.
  82. "local me=minetest.get_player_by_name(\"" .. name .. "\") " ..
  83. "local mypos=me:get_pos() " ..
  84. "local myname=me:get_player_name() " ..
  85. "local function player(pname) return minetest.get_player_by_name(pname) end " ..
  86. "local function print(text) minetest.chat_send_player(\"" .. name .. "\", \"# Server: \" .. text) end " ..
  87. str .. " end" -- User code & end of block.
  88. local func, err = loadstring(ci)
  89. if not func then -- Syntax error.
  90. reload.chat_send_player(name, PREFIX .. "Could not compile string. Received error message: '" .. err .. "'.")
  91. return false
  92. end
  93. local good, err = pcall(func)
  94. if not good then -- Runtime error.
  95. reload.chat_send_player(name, PREFIX .. "Could not execute string. Received error message: '" .. err .. "'.")
  96. return false
  97. end
  98. reload.chat_send_player(name, PREFIX .. "Code executed successfully!")
  99. return true
  100. end
  101. -- Don't register the chat commands more than once, even if this file is reloaded.
  102. if not reload.chat_registered then
  103. minetest.register_chatcommand("reload", {
  104. params = "<fileid> | list",
  105. description = "Reload a registered source file at runtime.",
  106. -- Player must have server priviliges.
  107. privs = {server=true},
  108. func = function(...) reload.impl.reload(...) end,
  109. })
  110. minetest.register_chatcommand("exec", {
  111. params = "<filepath>",
  112. description = "Load and execute an arbitrary Lua source file.",
  113. -- Player must have server priviliges.
  114. privs = {server=true},
  115. func = function(...) reload.impl.execute(...) end,
  116. })
  117. minetest.register_chatcommand("run", {
  118. params = "<filepath>",
  119. description = "Load and execute an arbitrary Lua source file.",
  120. -- Player must have server priviliges.
  121. privs = {server=true},
  122. func = function(...) reload.impl.execute(...) end,
  123. })
  124. minetest.register_chatcommand("dofile", {
  125. params = "<filepath>",
  126. description = "Load and execute an arbitrary Lua source file.",
  127. -- Player must have server priviliges.
  128. privs = {server=true},
  129. func = function(...) reload.impl.execute(...) end,
  130. })
  131. -- Alias name. Some people (like me) keep wanting to spell it out.
  132. minetest.register_chatcommand("execute", {
  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("dostring", {
  140. params = "<code>",
  141. description = "Execute a statement in Lua.",
  142. -- Player must have server priviliges.
  143. privs = {server=true},
  144. func = function(...) reload.impl.dostring(...) end,
  145. })
  146. minetest.register_chatcommand("lua", {
  147. params = "<code>",
  148. description = "Execute a statement in Lua.",
  149. -- Player must have server priviliges.
  150. privs = {server=true},
  151. func = function(...) reload.impl.dostring(...) end,
  152. })
  153. minetest.register_chatcommand("dolua", {
  154. params = "<code>",
  155. description = "Execute a statement in Lua.",
  156. -- Player must have server priviliges.
  157. privs = {server=true},
  158. func = function(...) reload.impl.dostring(...) end,
  159. })
  160. reload.chat_registered = true
  161. end