pos.lua 7.4 KB

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