A rewrite of the node_ownership Minetest mod with many new features. https://content.minetest.net/packages/ShadowNinja/areas/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

422 lines
12KB

  1. local S = minetest.get_translator("areas")
  2. minetest.register_chatcommand("protect", {
  3. params = S("<AreaName>"),
  4. description = S("Protect your own area"),
  5. privs = {[areas.config.self_protection_privilege]=true},
  6. func = function(name, param)
  7. if param == "" then
  8. return false, S("Invalid usage, see /help @1.", "protect")
  9. end
  10. local pos1, pos2 = areas:getPos(name)
  11. if not (pos1 and pos2) then
  12. return false, S("You need to select an area first.")
  13. end
  14. minetest.log("action", "/protect invoked, owner="..name..
  15. " AreaName="..param..
  16. " StartPos="..minetest.pos_to_string(pos1)..
  17. " EndPos=" ..minetest.pos_to_string(pos2))
  18. local canAdd, errMsg = areas:canPlayerAddArea(pos1, pos2, name)
  19. if not canAdd then
  20. return false, S("You can't protect that area: @1", errMsg)
  21. end
  22. local id = areas:add(name, param, pos1, pos2, nil)
  23. areas:save()
  24. return true, S("Area protected. ID: @1", id)
  25. end
  26. })
  27. minetest.register_chatcommand("set_owner", {
  28. params = S("<PlayerName>").." "..S("<AreaName>"),
  29. description = S("Protect an area between two positions and give"
  30. .." a player access to it without setting the parent of the"
  31. .." area to any existing area"),
  32. privs = areas.adminPrivs,
  33. func = function(name, param)
  34. local ownerName, areaName = param:match('^(%S+)%s(.+)$')
  35. if not ownerName then
  36. return false, S("Invalid usage, see /help @1.", "set_owner")
  37. end
  38. local pos1, pos2 = areas:getPos(name)
  39. if not (pos1 and pos2) then
  40. return false, S("You need to select an area first.")
  41. end
  42. if not areas:player_exists(ownerName) then
  43. return false, S("The player \"@1\" does not exist.", ownerName)
  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. S("You have been granted control over area #@1. "..
  53. "Type /list_areas to show your areas.", id))
  54. return true, S("Area protected. ID: @1", id)
  55. end
  56. })
  57. minetest.register_chatcommand("add_owner", {
  58. params = S("<ParentID>").." "..S("<PlayerName>").." "..S("<AreaName>"),
  59. description = S("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, S("Invalid usage, see /help @1.", "add_owner"))
  67. return
  68. end
  69. local pos1, pos2 = areas:getPos(name)
  70. if not (pos1 and pos2) then
  71. return false, S("You need to select an area first.")
  72. end
  73. if not areas:player_exists(ownerName) then
  74. return false, S("The player \"@1\" does not exist.", ownerName)
  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, S("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. S("You have been granted control over area #@1. "..
  90. "Type /list_areas to show your areas.", id))
  91. return true, S("Area protected. ID: @1", id)
  92. end
  93. })
  94. minetest.register_chatcommand("rename_area", {
  95. params = S("<ID>").." "..S("<newName>"),
  96. description = S("Rename an 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, S("Invalid usage, see /help @1.", "rename_area")
  101. end
  102. id = tonumber(id)
  103. if not id then
  104. return false, S("That area doesn't exist.")
  105. end
  106. if not areas:isAreaOwner(id, name) then
  107. return true, S("You don't own that area.")
  108. end
  109. areas.areas[id].name = newName
  110. areas:save()
  111. return true, S("Area renamed.")
  112. end
  113. })
  114. minetest.register_chatcommand("find_areas", {
  115. params = "<regexp>",
  116. description = S("Find areas using a Lua regular expression"),
  117. privs = areas.adminPrivs,
  118. func = function(name, param)
  119. if param == "" then
  120. return false, S("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, S("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, S("No matches found.")
  140. end
  141. end
  142. })
  143. minetest.register_chatcommand("list_areas", {
  144. description = S("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, S("No visible areas.")
  155. end
  156. return true, table.concat(areaStrings, "\n")
  157. end
  158. })
  159. minetest.register_chatcommand("recursive_remove_areas", {
  160. params = S("<ID>"),
  161. description = S("Recursively remove areas using an ID"),
  162. func = function(name, param)
  163. local id = tonumber(param)
  164. if not id then
  165. return false, S("Invalid usage, see"
  166. .." /help @1.", "recursive_remove_areas")
  167. end
  168. if not areas:isAreaOwner(id, name) then
  169. return false, S("Area @1 does not exist or is"
  170. .." not owned by you.", id)
  171. end
  172. areas:remove(id, true)
  173. areas:save()
  174. return true, S("Removed area @1 and it's sub areas.", id)
  175. end
  176. })
  177. minetest.register_chatcommand("remove_area", {
  178. params = S("<ID>"),
  179. description = S("Remove an area using an ID"),
  180. func = function(name, param)
  181. local id = tonumber(param)
  182. if not id then
  183. return false, S("Invalid usage, see /help @1.", "remove_area")
  184. end
  185. if not areas:isAreaOwner(id, name) then
  186. return false, S("Area @1 does not exist or"
  187. .." is not owned by you.", id)
  188. end
  189. areas:remove(id)
  190. areas:save()
  191. return true, S("Removed area @1", id)
  192. end
  193. })
  194. minetest.register_chatcommand("change_owner", {
  195. params = S("<ID>").." "..S("<NewOwner>"),
  196. description = S("Change the owner of an area using its ID"),
  197. func = function(name, param)
  198. local id, newOwner = param:match("^(%d+)%s(%S+)$")
  199. if not id then
  200. return false, S("Invalid usage, see"
  201. .." /help @1.", "change_owner")
  202. end
  203. if not areas:player_exists(newOwner) then
  204. return false, S("The player \"@1\" does not exist.", newOwner)
  205. end
  206. id = tonumber(id)
  207. if not areas:isAreaOwner(id, name) then
  208. return false, S("Area @1 does not exist"
  209. .." or is not owned by you.", id)
  210. end
  211. areas.areas[id].owner = newOwner
  212. areas:save()
  213. minetest.chat_send_player(newOwner,
  214. S("@1 has given you control over the area \"@2\" (ID @3).",
  215. name, areas.areas[id].name, id))
  216. return true, S("Owner changed.")
  217. end
  218. })
  219. minetest.register_chatcommand("area_open", {
  220. params = S("<ID>"),
  221. description = S("Toggle an area open (anyone can interact) or closed"),
  222. func = function(name, param)
  223. local id = tonumber(param)
  224. if not id then
  225. return false, S("Invalid usage, see /help @1.", "area_open")
  226. end
  227. if not areas:isAreaOwner(id, name) then
  228. return false, S("Area @1 does not exist"
  229. .." or is not owned by you.", id)
  230. end
  231. local open = not areas.areas[id].open
  232. -- Save false as nil to avoid inflating the DB.
  233. areas.areas[id].open = open or nil
  234. areas:save()
  235. return true, open and S("Area opened.") or S("Area closed.")
  236. end
  237. })
  238. if areas.factions_available then
  239. minetest.register_chatcommand("area_faction_open", {
  240. params = S("<ID>"),
  241. description = S("Toggle an area open/closed for members in your faction."),
  242. func = function(name, param)
  243. local id = tonumber(param)
  244. if not id then
  245. return false, S("Invalid usage, see /help @1.", "area_faction_open")
  246. end
  247. if not areas:isAreaOwner(id, name) then
  248. return false, S("Area @1 does not exist"
  249. .." or is not owned by you.", id)
  250. end
  251. local open = not areas.areas[id].faction_open
  252. -- Save false as nil to avoid inflating the DB.
  253. areas.areas[id].faction_open = open or nil
  254. areas:save()
  255. return true, open and S("Area opened for faction members.")
  256. or S("Area closed for faction members.")
  257. end
  258. })
  259. end
  260. minetest.register_chatcommand("move_area", {
  261. params = S("<ID>"),
  262. description = S("Move (or resize) an area to the current positions."),
  263. privs = areas.adminPrivs,
  264. func = function(name, param)
  265. local id = tonumber(param)
  266. if not id then
  267. return false, S("Invalid usage, see /help @1.", "move_area")
  268. end
  269. local area = areas.areas[id]
  270. if not area then
  271. return false, S("Area does not exist.")
  272. end
  273. local pos1, pos2 = areas:getPos(name)
  274. if not pos1 then
  275. return false, S("You need to select an area first.")
  276. end
  277. areas:move(id, area, pos1, pos2)
  278. areas:save()
  279. return true, S("Area successfully moved.")
  280. end,
  281. })
  282. minetest.register_chatcommand("area_info", {
  283. description = S("Get information about area configuration and usage."),
  284. func = function(name, param)
  285. local lines = {}
  286. local privs = minetest.get_player_privs(name)
  287. -- Short (and fast to access) names
  288. local cfg = areas.config
  289. local self_prot = cfg.self_protection
  290. local prot_priv = cfg.self_protection_privilege
  291. local limit = cfg.self_protection_max_areas
  292. local limit_high = cfg.self_protection_max_areas_high
  293. local size_limit = cfg.self_protection_max_size
  294. local size_limit_high = cfg.self_protection_max_size_high
  295. local has_high_limit = privs.areas_high_limit
  296. local has_prot_priv = not prot_priv or privs[prot_priv]
  297. local can_prot = privs.areas or (self_prot and has_prot_priv)
  298. local max_count = can_prot and
  299. (has_high_limit and limit_high or limit) or 0
  300. local max_size = has_high_limit and
  301. size_limit_high or size_limit
  302. -- Self protection information
  303. local self_prot_line = self_prot and S("Self protection is enabled.") or
  304. S("Self protection is disabled.")
  305. table.insert(lines, self_prot_line)
  306. -- Privilege information
  307. local priv_line = has_prot_priv and
  308. S("You have the necessary privilege (\"@1\").", prot_priv) or
  309. S("You don't have the necessary privilege (\"@1\").", prot_priv)
  310. table.insert(lines, priv_line)
  311. if privs.areas then
  312. table.insert(lines, S("You are an area"..
  313. " administrator (\"areas\" privilege)."))
  314. elseif has_high_limit then
  315. table.insert(lines,
  316. S("You have extended area protection"..
  317. " limits (\"areas_high_limit\" privilege)."))
  318. end
  319. -- Area count
  320. local area_num = 0
  321. for id, area in pairs(areas.areas) do
  322. if area.owner == name then
  323. area_num = area_num + 1
  324. end
  325. end
  326. table.insert(lines, S("You have @1 areas.", area_num))
  327. -- Area limit
  328. local area_limit_line = privs.areas and
  329. S("Limit: no area count limit") or
  330. S("Limit: @1 areas", max_count)
  331. table.insert(lines, area_limit_line)
  332. -- Area size limits
  333. local function size_info(str, size)
  334. table.insert(lines, S("@1 spanning up to @2x@3x@4.",
  335. str, size.x, size.y, size.z))
  336. end
  337. local function priv_limit_info(lpriv, lmax_count, lmax_size)
  338. size_info(S("Players with the \"@1\" privilege"..
  339. " can protect up to @2 areas", lpriv, lmax_count),
  340. lmax_size)
  341. end
  342. if self_prot then
  343. if privs.areas then
  344. priv_limit_info(prot_priv,
  345. limit, size_limit)
  346. priv_limit_info("areas_high_limit",
  347. limit_high, size_limit_high)
  348. elseif has_prot_priv then
  349. size_info(S("You can protect areas"), max_size)
  350. end
  351. end
  352. return true, table.concat(lines, "\n")
  353. end,
  354. })