pos.lua 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. local S = minetest.get_translator("areas")
  2. -- I could depend on WorldEdit for this, but you need to have the 'worldedit'
  3. -- permission to use those commands and you don't have
  4. -- /area_pos{1,2} [X Y Z|X,Y,Z].
  5. -- Since this is mostly copied from WorldEdit it is mostly
  6. -- licensed under the AGPL. (select_area is a exception)
  7. areas.marker1 = {}
  8. areas.marker2 = {}
  9. areas.set_pos = {}
  10. areas.pos1 = {}
  11. areas.pos2 = {}
  12. local LIMIT = 30992 -- this is due to MAPBLOCK_SIZE=16!
  13. local function posLimit(pos)
  14. return {
  15. x = math.max(math.min(pos.x, LIMIT), -LIMIT),
  16. y = math.max(math.min(pos.y, LIMIT), -LIMIT),
  17. z = math.max(math.min(pos.z, LIMIT), -LIMIT)
  18. }
  19. end
  20. minetest.register_chatcommand("select_area", {
  21. params = S("<ID>"),
  22. description = S("Select an area by ID."),
  23. func = function(name, param)
  24. local id = tonumber(param)
  25. if not id then
  26. return false, S("Invalid usage, see /help @1.", "select_area")
  27. end
  28. if not areas.areas[id] then
  29. return false, S("The area @1 does not exist.", id)
  30. end
  31. areas:setPos1(name, areas.areas[id].pos1)
  32. areas:setPos2(name, areas.areas[id].pos2)
  33. return true, S("Area @1 selected.", id)
  34. end,
  35. })
  36. minetest.register_chatcommand("area_pos1", {
  37. params = "[X Y Z|X,Y,Z]",
  38. description = S("Set area protection region position @1 to your"
  39. .." location or the one specified", "1"),
  40. privs = {},
  41. func = function(name, param)
  42. local pos
  43. local found, _, x, y, z = param:find(
  44. "^(-?%d+)[, ](-?%d+)[, ](-?%d+)$")
  45. if found then
  46. pos = {x=tonumber(x), y=tonumber(y), z=tonumber(z)}
  47. elseif param == "" then
  48. local player = minetest.get_player_by_name(name)
  49. if player then
  50. pos = player:get_pos()
  51. else
  52. return false, S("Unable to get position.")
  53. end
  54. else
  55. return false, S("Invalid usage, see /help @1.", "area_pos1")
  56. end
  57. pos = posLimit(vector.round(pos))
  58. areas:setPos1(name, pos)
  59. return true, S("Area position @1 set to @2", "1",
  60. minetest.pos_to_string(pos))
  61. end,
  62. })
  63. minetest.register_chatcommand("area_pos2", {
  64. params = "[X Y Z|X,Y,Z]",
  65. description = S("Set area protection region position @1 to your"
  66. .." location or the one specified", "2"),
  67. func = function(name, param)
  68. local pos
  69. local found, _, x, y, z = param:find(
  70. "^(-?%d+)[, ](-?%d+)[, ](-?%d+)$")
  71. if found then
  72. pos = {x=tonumber(x), y=tonumber(y), z=tonumber(z)}
  73. elseif param == "" then
  74. local player = minetest.get_player_by_name(name)
  75. if player then
  76. pos = player:get_pos()
  77. else
  78. return false, S("Unable to get position.")
  79. end
  80. else
  81. return false, S("Invalid usage, see /help @1.", "area_pos2")
  82. end
  83. pos = posLimit(vector.round(pos))
  84. areas:setPos2(name, pos)
  85. return true, S("Area position @1 set to @2", "2",
  86. minetest.pos_to_string(pos))
  87. end,
  88. })
  89. minetest.register_chatcommand("area_pos", {
  90. params = "set/set1/set2/get",
  91. description = S("Set area protection region, position 1, or position 2"
  92. .." by punching nodes, or display the region"),
  93. func = function(name, param)
  94. if param == "set" then -- Set both area positions
  95. areas.set_pos[name] = "pos1"
  96. return true, S("Select positions by punching two nodes.")
  97. elseif param == "set1" then -- Set area position 1
  98. areas.set_pos[name] = "pos1only"
  99. return true, S("Select position @1 by punching a node.", "1")
  100. elseif param == "set2" then -- Set area position 2
  101. areas.set_pos[name] = "pos2"
  102. return true, S("Select position @1 by punching a node.", "2")
  103. elseif param == "get" then -- Display current area positions
  104. local pos1str, pos2str = S("Position @1: ", "1"), S("Position @1: ", "2")
  105. if areas.pos1[name] then
  106. pos1str = pos1str..minetest.pos_to_string(areas.pos1[name])
  107. else
  108. pos1str = pos1str..S("<not set>")
  109. end
  110. if areas.pos2[name] then
  111. pos2str = pos2str..minetest.pos_to_string(areas.pos2[name])
  112. else
  113. pos2str = pos2str..S("<not set>")
  114. end
  115. return true, pos1str.."\n"..pos2str
  116. else
  117. return false, S("Unknown subcommand: @1", param)
  118. end
  119. end,
  120. })
  121. function areas:getPos(playerName)
  122. local pos1, pos2 = areas.pos1[playerName], areas.pos2[playerName]
  123. if not (pos1 and pos2) then
  124. return nil
  125. end
  126. -- Copy positions so that the area table doesn't contain multiple
  127. -- references to the same position.
  128. pos1, pos2 = vector.new(pos1), vector.new(pos2)
  129. return areas:sortPos(pos1, pos2)
  130. end
  131. function areas:setPos1(playerName, pos)
  132. areas.pos1[playerName] = posLimit(pos)
  133. areas.markPos1(playerName)
  134. end
  135. function areas:setPos2(playerName, pos)
  136. areas.pos2[playerName] = posLimit(pos)
  137. areas.markPos2(playerName)
  138. end
  139. minetest.register_on_punchnode(function(pos, node, puncher)
  140. local name = puncher:get_player_name()
  141. -- Currently setting position
  142. if name ~= "" and areas.set_pos[name] then
  143. if areas.set_pos[name] == "pos1" then
  144. areas.pos1[name] = pos
  145. areas.markPos1(name)
  146. areas.set_pos[name] = "pos2"
  147. minetest.chat_send_player(name,
  148. S("Position @1 set to @2", "1",
  149. minetest.pos_to_string(pos)))
  150. elseif areas.set_pos[name] == "pos1only" then
  151. areas.pos1[name] = pos
  152. areas.markPos1(name)
  153. areas.set_pos[name] = nil
  154. minetest.chat_send_player(name,
  155. S("Position @1 set to @2", "1",
  156. minetest.pos_to_string(pos)))
  157. elseif areas.set_pos[name] == "pos2" then
  158. areas.pos2[name] = pos
  159. areas.markPos2(name)
  160. areas.set_pos[name] = nil
  161. minetest.chat_send_player(name,
  162. S("Position @1 set to @2", "2",
  163. minetest.pos_to_string(pos)))
  164. end
  165. end
  166. end)
  167. -- Modifies positions `pos1` and `pos2` so that each component of `pos1`
  168. -- is less than or equal to its corresponding component of `pos2`,
  169. -- returning the two positions.
  170. function areas:sortPos(pos1, pos2)
  171. if pos1.x > pos2.x then
  172. pos2.x, pos1.x = pos1.x, pos2.x
  173. end
  174. if pos1.y > pos2.y then
  175. pos2.y, pos1.y = pos1.y, pos2.y
  176. end
  177. if pos1.z > pos2.z then
  178. pos2.z, pos1.z = pos1.z, pos2.z
  179. end
  180. return pos1, pos2
  181. end
  182. -- Marks area position 1
  183. areas.markPos1 = function(name)
  184. local pos = areas.pos1[name]
  185. if areas.marker1[name] ~= nil then -- Marker already exists
  186. areas.marker1[name]:remove() -- Remove marker
  187. areas.marker1[name] = nil
  188. end
  189. if pos ~= nil then -- Add marker
  190. areas.marker1[name] = minetest.add_entity(pos, "areas:pos1")
  191. areas.marker1[name]:get_luaentity().active = true
  192. end
  193. end
  194. -- Marks area position 2
  195. areas.markPos2 = function(name)
  196. local pos = areas.pos2[name]
  197. if areas.marker2[name] ~= nil then -- Marker already exists
  198. areas.marker2[name]:remove() -- Remove marker
  199. areas.marker2[name] = nil
  200. end
  201. if pos ~= nil then -- Add marker
  202. areas.marker2[name] = minetest.add_entity(pos, "areas:pos2")
  203. areas.marker2[name]:get_luaentity().active = true
  204. end
  205. end
  206. minetest.register_entity("areas:pos1", {
  207. initial_properties = {
  208. visual = "cube",
  209. visual_size = {x=1.1, y=1.1},
  210. textures = {"areas_pos1.png", "areas_pos1.png",
  211. "areas_pos1.png", "areas_pos1.png",
  212. "areas_pos1.png", "areas_pos1.png"},
  213. collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
  214. },
  215. on_step = function(self, dtime)
  216. if self.active == nil then
  217. self.object:remove()
  218. end
  219. end,
  220. on_punch = function(self, hitter)
  221. self.object:remove()
  222. local name = hitter:get_player_name()
  223. areas.marker1[name] = nil
  224. end,
  225. })
  226. minetest.register_entity("areas:pos2", {
  227. initial_properties = {
  228. visual = "cube",
  229. visual_size = {x=1.1, y=1.1},
  230. textures = {"areas_pos2.png", "areas_pos2.png",
  231. "areas_pos2.png", "areas_pos2.png",
  232. "areas_pos2.png", "areas_pos2.png"},
  233. collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
  234. },
  235. on_step = function(self, dtime)
  236. if self.active == nil then
  237. self.object:remove()
  238. end
  239. end,
  240. on_punch = function(self, hitter)
  241. self.object:remove()
  242. local name = hitter:get_player_name()
  243. areas.marker2[name] = nil
  244. end,
  245. })