chatcommands.lua 12 KB

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