chatcommands.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. minetest.register_chatcommand("protect", {
  2. params = "<AreaName>",
  3. description = "Protect your own area",
  4. privs = {[areas.config.self_protection_privilege]=true},
  5. func = function(name, param)
  6. if param == "" then
  7. return false, "Invalid usage, see /help protect."
  8. end
  9. local pos1, pos2 = areas:getPos(name)
  10. if not (pos1 and pos2) then
  11. return false, "You need to select an area first."
  12. end
  13. minetest.log("action", "/protect invoked, owner="..name..
  14. " AreaName="..param..
  15. " StartPos="..minetest.pos_to_string(pos1)..
  16. " EndPos=" ..minetest.pos_to_string(pos2))
  17. local canAdd, errMsg = areas:canPlayerAddArea(pos1, pos2, name)
  18. if not canAdd then
  19. return false, "You can't protect that area: "..errMsg
  20. end
  21. local id = areas:add(name, param, pos1, pos2, nil)
  22. areas:save()
  23. return true, "Area protected. ID: "..id
  24. end
  25. })
  26. minetest.register_chatcommand("set_owner", {
  27. params = "<PlayerName> <AreaName>",
  28. description = "Protect an area beetween two positions and give"
  29. .." a player access to it without setting the parent of the"
  30. .." area to any existing area",
  31. privs = areas.adminPrivs,
  32. func = function(name, param)
  33. local ownerName, areaName = param:match('^(%S+)%s(.+)$')
  34. if not ownerName then
  35. return false, "Incorrect usage, see /help set_owner."
  36. end
  37. local pos1, pos2 = areas:getPos(name)
  38. if not (pos1 and pos2) then
  39. return false, "You need to select an area first."
  40. end
  41. if not areas:player_exists(ownerName) then
  42. return false, "The player \""
  43. ..ownerName.."\" does not exist."
  44. end
  45. minetest.log("action", name.." runs /set_owner. Owner = "..ownerName..
  46. " AreaName = "..areaName..
  47. " StartPos = "..minetest.pos_to_string(pos1)..
  48. " EndPos = " ..minetest.pos_to_string(pos2))
  49. local id = areas:add(ownerName, areaName, pos1, pos2, nil)
  50. areas:save()
  51. minetest.chat_send_player(ownerName,
  52. "You have been granted control over area #"..
  53. id..". Type /list_areas to show your areas.")
  54. return true, "Area protected. ID: "..id
  55. end
  56. })
  57. minetest.register_chatcommand("add_owner", {
  58. params = "<ParentID> <Player> <AreaName>",
  59. description = "Give a player access to a sub-area beetween two"
  60. .." positions that have already been protected,"
  61. .." Use set_owner if you don't want the parent to be set.",
  62. func = function(name, param)
  63. local pid, ownerName, areaName
  64. = param:match('^(%d+) ([^ ]+) (.+)$')
  65. if not pid then
  66. minetest.chat_send_player(name, "Incorrect usage, see /help add_owner")
  67. return
  68. end
  69. local pos1, pos2 = areas:getPos(name)
  70. if not (pos1 and pos2) then
  71. return false, "You need to select an area first."
  72. end
  73. if not areas:player_exists(ownerName) then
  74. return false, "The player \""..ownerName.."\" does not exist."
  75. end
  76. minetest.log("action", name.." runs /add_owner. Owner = "..ownerName..
  77. " AreaName = "..areaName.." ParentID = "..pid..
  78. " StartPos = "..pos1.x..","..pos1.y..","..pos1.z..
  79. " EndPos = " ..pos2.x..","..pos2.y..","..pos2.z)
  80. -- Check if this new area is inside an area owned by the player
  81. pid = tonumber(pid)
  82. if (not areas:isAreaOwner(pid, name)) or
  83. (not areas:isSubarea(pos1, pos2, pid)) then
  84. return false, "You can't protect that area."
  85. end
  86. local id = areas:add(ownerName, areaName, pos1, pos2, pid)
  87. areas:save()
  88. minetest.chat_send_player(ownerName,
  89. "You have been granted control over area #"..
  90. id..". Type /list_areas to show your areas.")
  91. return true, "Area protected. ID: "..id
  92. end
  93. })
  94. minetest.register_chatcommand("rename_area", {
  95. params = "<ID> <newName>",
  96. description = "Rename a area that you own",
  97. func = function(name, param)
  98. local id, newName = param:match("^(%d+)%s(.+)$")
  99. if not id then
  100. return false, "Invalid usage, see /help rename_area."
  101. end
  102. id = tonumber(id)
  103. if not id then
  104. return false, "That area doesn't exist."
  105. end
  106. if not areas:isAreaOwner(id, name) then
  107. return true, "You don't own that area."
  108. end
  109. areas.areas[id].name = newName
  110. areas:save()
  111. return true, "Area renamed."
  112. end
  113. })
  114. minetest.register_chatcommand("find_areas", {
  115. params = "<regexp>",
  116. description = "Find areas using a Lua regular expression",
  117. privs = areas.adminPrivs,
  118. func = function(name, param)
  119. if param == "" then
  120. return false, "A regular expression is required."
  121. end
  122. -- Check expression for validity
  123. local function testRegExp()
  124. ("Test [1]: Player (0,0,0) (0,0,0)"):find(param)
  125. end
  126. if not pcall(testRegExp) then
  127. return false, "Invalid regular expression."
  128. end
  129. local matches = {}
  130. for id, area in pairs(areas.areas) do
  131. local str = areas:toString(id)
  132. if str:find(param) then
  133. table.insert(matches, str)
  134. end
  135. end
  136. if #matches > 0 then
  137. return true, table.concat(matches, "\n")
  138. else
  139. return true, "No matches found."
  140. end
  141. end
  142. })
  143. minetest.register_chatcommand("list_areas", {
  144. description = "List your areas, or all areas if you are an admin.",
  145. func = function(name, param)
  146. local admin = minetest.check_player_privs(name, areas.adminPrivs)
  147. local areaStrings = {}
  148. for id, area in pairs(areas.areas) do
  149. if admin or areas:isAreaOwner(id, name) then
  150. table.insert(areaStrings, areas:toString(id))
  151. end
  152. end
  153. if #areaStrings == 0 then
  154. return true, "No visible areas."
  155. end
  156. return true, table.concat(areaStrings, "\n")
  157. end
  158. })
  159. minetest.register_chatcommand("recursive_remove_areas", {
  160. params = "<id>",
  161. description = "Recursively remove areas using an id",
  162. func = function(name, param)
  163. local id = tonumber(param)
  164. if not id then
  165. return false, "Invalid usage, see"
  166. .." /help recursive_remove_areas"
  167. end
  168. if not areas:isAreaOwner(id, name) then
  169. return false, "Area "..id.." does not exist or is"
  170. .." not owned by you."
  171. end
  172. areas:remove(id, true)
  173. areas:save()
  174. return true, "Removed area "..id.." and it's sub areas."
  175. end
  176. })
  177. minetest.register_chatcommand("remove_area", {
  178. params = "<id>",
  179. description = "Remove an area using an id",
  180. func = function(name, param)
  181. local id = tonumber(param)
  182. if not id then
  183. return false, "Invalid usage, see /help remove_area"
  184. end
  185. if not areas:isAreaOwner(id, name) then
  186. return false, "Area "..id.." does not exist or"
  187. .." is not owned by you."
  188. end
  189. areas:remove(id)
  190. areas:save()
  191. return true, "Removed area "..id
  192. end
  193. })
  194. minetest.register_chatcommand("change_owner", {
  195. params = "<ID> <NewOwner>",
  196. description = "Change the owner of an area using it's ID",
  197. func = function(name, param)
  198. local id, newOwner = param:match("^(%d+)%s(%S+)$")
  199. if not id then
  200. return false, "Invalid usage, see"
  201. .." /help change_owner."
  202. end
  203. if not areas:player_exists(newOwner) then
  204. return false, "The player \""..newOwner
  205. .."\" does not exist."
  206. end
  207. id = tonumber(id)
  208. if not areas:isAreaOwner(id, name) then
  209. return false, "Area "..id.." does not exist"
  210. .." or is not owned by you."
  211. end
  212. areas.areas[id].owner = newOwner
  213. areas:save()
  214. minetest.chat_send_player(newOwner,
  215. ("%s has given you control over the area %q (ID %d).")
  216. :format(name, areas.areas[id].name, id))
  217. return true, "Owner changed."
  218. end
  219. })
  220. minetest.register_chatcommand("area_open", {
  221. params = "<ID>",
  222. description = "Toggle an area open (anyone can interact) or closed",
  223. func = function(name, param)
  224. local id = tonumber(param)
  225. if not id then
  226. return false, "Invalid usage, see /help area_open."
  227. end
  228. if not areas:isAreaOwner(id, name) then
  229. return false, "Area "..id.." does not exist"
  230. .." or is not owned by you."
  231. end
  232. local open = not areas.areas[id].open
  233. -- Save false as nil to avoid inflating the DB.
  234. areas.areas[id].open = open or nil
  235. areas:save()
  236. return true, ("Area %s."):format(open and "opened" or "closed")
  237. end
  238. })
  239. minetest.register_chatcommand("move_area", {
  240. params = "<ID>",
  241. description = "Move (or resize) an area to the current positions.",
  242. privs = areas.adminPrivs,
  243. func = function(name, param)
  244. local id = tonumber(param)
  245. if not id then
  246. return false, "Invalid usage, see /help move_area."
  247. end
  248. local area = areas.areas[id]
  249. if not area then
  250. return false, "Area does not exist."
  251. end
  252. local pos1, pos2 = areas:getPos(name)
  253. if not pos1 then
  254. return false, "You need to select an area first."
  255. end
  256. areas:move(id, area, pos1, pos2)
  257. areas:save()
  258. return true, "Area successfully moved."
  259. end,
  260. })
  261. minetest.register_chatcommand("area_info", {
  262. description = "Get information about area configuration and usage.",
  263. func = function(name, param)
  264. local lines = {}
  265. local privs = minetest.get_player_privs(name)
  266. -- Short (and fast to access) names
  267. local cfg = areas.config
  268. local self_prot = cfg.self_protection
  269. local prot_priv = cfg.self_protection_privilege
  270. local limit = cfg.self_protection_max_areas
  271. local limit_high = cfg.self_protection_max_areas_high
  272. local size_limit = cfg.self_protection_max_size
  273. local size_limit_high = cfg.self_protection_max_size_high
  274. local has_high_limit = privs.areas_high_limit
  275. local has_prot_priv = not prot_priv or privs[prot_priv]
  276. local can_prot = privs.areas or (self_prot and has_prot_priv)
  277. local max_count = can_prot and
  278. (has_high_limit and limit_high or limit) or 0
  279. local max_size = has_high_limit and
  280. size_limit_high or size_limit
  281. -- Privilege information
  282. local self_prot_line = ("Self protection is %sabled"):format(
  283. self_prot and "en" or "dis")
  284. if self_prot and prot_priv then
  285. self_prot_line = self_prot_line..
  286. (" %s have the neccessary privilege (%q).")
  287. :format(
  288. has_prot_priv and "and you" or
  289. "but you don't",
  290. prot_priv)
  291. else
  292. self_prot_line = self_prot_line.."."
  293. end
  294. table.insert(lines, self_prot_line)
  295. if privs.areas then
  296. table.insert(lines, "You are an area"..
  297. " administrator (\"areas\" privilege).")
  298. elseif has_high_limit then
  299. table.insert(lines,
  300. "You have extended area protection"..
  301. " limits (\"areas_high_limit\" privilege).")
  302. end
  303. -- Area count
  304. local area_num = 0
  305. for id, area in pairs(areas.areas) do
  306. if area.owner == name then
  307. area_num = area_num + 1
  308. end
  309. end
  310. local count_line = ("You have %d area%s"):format(
  311. area_num, area_num == 1 and "" or "s")
  312. if privs.areas then
  313. count_line = count_line..
  314. " and have no area protection limits."
  315. elseif can_prot then
  316. count_line = count_line..(", out of a maximum of %d.")
  317. :format(max_count)
  318. end
  319. table.insert(lines, count_line)
  320. -- Area size limits
  321. local function size_info(str, size)
  322. table.insert(lines, ("%s spanning up to %dx%dx%d.")
  323. :format(str, size.x, size.y, size.z))
  324. end
  325. local function priv_limit_info(priv, max_count, max_size)
  326. size_info(("Players with the %q privilege"..
  327. " can protect up to %d areas"):format(
  328. priv, max_count), max_size)
  329. end
  330. if self_prot then
  331. if privs.areas then
  332. priv_limit_info(prot_priv,
  333. limit, size_limit)
  334. priv_limit_info("areas_high_limit",
  335. limit_high, size_limit_high)
  336. elseif has_prot_priv then
  337. size_info("You can protect areas", max_size)
  338. end
  339. end
  340. return true, table.concat(lines, "\n")
  341. end,
  342. })