An advanced-ish waypoints mod for Minetest.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. --
  2. -- Minetest advmarkers SSCSM
  3. --
  4. advmarkers = {}
  5. local data = {}
  6. -- Convert positions to/from strings
  7. local function pos_to_string(pos)
  8. if type(pos) == 'table' then
  9. pos = minetest.pos_to_string(vector.round(pos))
  10. end
  11. if type(pos) == 'string' then
  12. return pos
  13. end
  14. end
  15. local function string_to_pos(pos)
  16. if type(pos) == 'string' then
  17. pos = minetest.string_to_pos(pos)
  18. end
  19. if type(pos) == 'table' then
  20. return vector.round(pos)
  21. end
  22. end
  23. -- Run remote command
  24. -- This is easier to do with chatcommands because servers cannot send mod
  25. -- channel messages to specific clients.
  26. local csm_key = string.char(1) .. 'ADVMARKERS_SSCSM' .. string.char(1)
  27. local function run_remote_command(cmd, param)
  28. local msg = csm_key
  29. if cmd then
  30. msg = msg .. cmd
  31. if param then msg = msg .. param end
  32. end
  33. minetest.run_server_chatcommand('wp', msg)
  34. end
  35. -- Display a waypoint
  36. function advmarkers.display_waypoint(name)
  37. name = tostring(name)
  38. if data['marker-' .. name] then
  39. run_remote_command('0', tostring(name))
  40. return true
  41. else
  42. return false
  43. end
  44. end
  45. -- Get a waypoint
  46. function advmarkers.get_waypoint(name)
  47. return string_to_pos(data['marker-' .. tostring(name)])
  48. end
  49. advmarkers.get_marker = advmarkers.get_waypoint
  50. -- Delete a waypoint
  51. function advmarkers.delete_waypoint(name)
  52. name = tostring(name)
  53. if data['marker-' .. name] ~= nil then
  54. data['marker-' .. name] = nil
  55. run_remote_command('D', name)
  56. end
  57. end
  58. advmarkers.delete_marker = advmarkers.delete_waypoint
  59. -- Set a waypoint
  60. function advmarkers.set_waypoint(pos, name)
  61. pos = pos_to_string(pos)
  62. if not pos then return end
  63. name = tostring(name)
  64. data['marker-' .. name] = pos
  65. run_remote_command('S', pos:gsub(' ', '') .. ' ' .. name)
  66. return true
  67. end
  68. advmarkers.set_marker = advmarkers.set_waypoint
  69. -- Rename a waypoint and re-interpret the position.
  70. function advmarkers.rename_waypoint(oldname, newname)
  71. oldname, newname = tostring(oldname), tostring(newname)
  72. local pos = advmarkers.get_waypoint(oldname)
  73. if not pos or not advmarkers.set_waypoint(pos, newname) then return end
  74. if oldname ~= newname then
  75. advmarkers.delete_waypoint(oldname)
  76. end
  77. return true
  78. end
  79. advmarkers.rename_marker = advmarkers.rename_waypoint
  80. -- Import waypoints - Note that this won't import strings made by older
  81. -- versions of the CSM.
  82. function advmarkers.import(s, clear)
  83. if type(s) ~= 'table' then
  84. if s:sub(1, 1) ~= 'J' then return end
  85. s = minetest.decode_base64(s:sub(2))
  86. local success, msg = pcall(minetest.decompress, s)
  87. if not success then return end
  88. s = minetest.parse_json(msg)
  89. end
  90. -- Iterate over waypoints to preserve existing ones and check for errors.
  91. if type(s) ~= 'table' then return end
  92. if clear then data = {} end
  93. for name, pos in pairs(s) do
  94. if type(name) == 'string' and type(pos) == 'string' and
  95. name:sub(1, 7) == 'marker-' and minetest.string_to_pos(pos) and
  96. data[name] ~= pos then
  97. -- Prevent collisions
  98. local c = 0
  99. while data[name] and c < 50 do
  100. name = name .. '_'
  101. c = c + 1
  102. end
  103. -- Sanity check
  104. if c < 50 then
  105. data[name] = pos
  106. end
  107. end
  108. end
  109. end
  110. -- Get waypoint names
  111. function advmarkers.get_waypoint_names(sorted)
  112. local res = {}
  113. for name, pos in pairs(data) do
  114. if name:sub(1, 7) == 'marker-' then
  115. table.insert(res, name:sub(8))
  116. end
  117. end
  118. if sorted or sorted == nil then table.sort(res) end
  119. return res
  120. end
  121. -- Display the formspec
  122. local formspec_list = {}
  123. local selected_name = false
  124. function advmarkers.display_formspec()
  125. local formspec = 'size[5.25,8]' ..
  126. 'label[0,0;Waypoint list ' ..
  127. minetest.colorize('#888888', '(SSCSM)') .. ']' ..
  128. 'button_exit[0,7.5;1.3125,0.5;display;Display]' ..
  129. 'button[1.3125,7.5;1.3125,0.5;teleport;Teleport]' ..
  130. 'button[2.625,7.5;1.3125,0.5;rename;Rename]' ..
  131. 'button[3.9375,7.5;1.3125,0.5;delete;Delete]' ..
  132. 'textlist[0,0.75;5,6;marker;'
  133. -- Iterate over all the markers
  134. local id = 0
  135. local selected = 1
  136. formspec_list = advmarkers.get_waypoint_names()
  137. for id, name in ipairs(formspec_list) do
  138. if id > 1 then formspec = formspec .. ',' end
  139. if not selected_name then selected_name = name end
  140. if name == selected_name then selected = id end
  141. formspec = formspec .. '##' .. minetest.formspec_escape(name)
  142. end
  143. -- Close the text list and display the selected marker position
  144. formspec = formspec .. ';' .. tostring(selected) .. ']'
  145. if selected_name then
  146. local pos = advmarkers.get_marker(selected_name)
  147. if pos then
  148. pos = minetest.formspec_escape(tostring(pos.x) .. ', ' ..
  149. tostring(pos.y) .. ', ' .. tostring(pos.z))
  150. pos = 'Waypoint position: ' .. pos
  151. formspec = formspec .. 'label[0,6.75;' .. pos .. ']'
  152. end
  153. else
  154. -- Draw over the buttons
  155. formspec = formspec .. 'button_exit[0,7.5;5.25,0.5;quit;Close dialog]' ..
  156. 'label[0,6.75;No waypoints. Add one with "/add_wp".]'
  157. end
  158. -- Display the formspec
  159. return minetest.show_formspec('advmarkers-sscsm', formspec)
  160. end
  161. -- Register chatcommands
  162. local mrkr_cmd
  163. function mrkr_cmd(param)
  164. if param == '' then return advmarkers.display_formspec() end
  165. if param == '--ssm' then param = '' end
  166. minetest.run_server_chatcommand('wp', param)
  167. end
  168. sscsm.register_chatcommand('mrkr', mrkr_cmd)
  169. sscsm.register_chatcommand('wp', mrkr_cmd)
  170. sscsm.register_chatcommand('wps', mrkr_cmd)
  171. sscsm.register_chatcommand('waypoint', mrkr_cmd)
  172. sscsm.register_chatcommand('waypoints', mrkr_cmd)
  173. function mrkr_cmd(param)
  174. minetest.run_server_chatcommand('add_wp', param)
  175. run_remote_command()
  176. end
  177. sscsm.register_chatcommand('add_wp', mrkr_cmd)
  178. sscsm.register_chatcommand('add_waypoint', mrkr_cmd)
  179. sscsm.register_chatcommand('add_mrkr', mrkr_cmd)
  180. mrkr_cmd = nil
  181. -- Set the HUD
  182. minetest.register_on_formspec_input(function(formname, fields)
  183. if formname == 'advmarkers-ignore' then
  184. return true
  185. elseif formname ~= 'advmarkers-sscsm' then
  186. return
  187. end
  188. local name = false
  189. if fields.marker then
  190. local event = minetest.explode_textlist_event(fields.marker)
  191. if event.index then
  192. name = formspec_list[event.index]
  193. end
  194. else
  195. name = selected_name
  196. end
  197. if name then
  198. if fields.display then
  199. if not advmarkers.display_waypoint(name) then
  200. minetest.display_chat_message('Error displaying waypoint!')
  201. end
  202. elseif fields.rename then
  203. minetest.show_formspec('advmarkers-sscsm', 'size[6,3]' ..
  204. 'label[0.35,0.2;Rename waypoint]' ..
  205. 'field[0.3,1.3;6,1;new_name;New name;' ..
  206. minetest.formspec_escape(name) .. ']' ..
  207. 'button[0,2;3,1;cancel;Cancel]' ..
  208. 'button[3,2;3,1;rename_confirm;Rename]')
  209. elseif fields.rename_confirm then
  210. if fields.new_name and #fields.new_name > 0 then
  211. if advmarkers.rename_waypoint(name, fields.new_name) then
  212. selected_name = fields.new_name
  213. else
  214. minetest.display_chat_message('Error renaming waypoint!')
  215. end
  216. advmarkers.display_formspec()
  217. else
  218. minetest.display_chat_message(
  219. 'Please enter a new name for the waypoint.'
  220. )
  221. end
  222. elseif fields.teleport then
  223. minetest.show_formspec('advmarkers-sscsm', 'size[6,2.2]' ..
  224. 'label[0.35,0.25;' .. minetest.formspec_escape(
  225. 'Teleport to a waypoint\n - ' .. name
  226. ) .. ']' ..
  227. 'button[0,1.25;3,1;cancel;Cancel]' ..
  228. 'button_exit[3,1.25;3,1;teleport_confirm;Teleport]')
  229. elseif fields.teleport_confirm then
  230. -- Teleport with /teleport
  231. local pos = advmarkers.get_waypoint(name)
  232. if pos then
  233. minetest.run_server_chatcommand('teleport',
  234. pos.x .. ', ' .. pos.y .. ', ' .. pos.z)
  235. else
  236. minetest.display_chat_message('Error teleporting to waypoint!')
  237. end
  238. elseif fields.delete then
  239. minetest.show_formspec('advmarkers-sscsm', 'size[6,2]' ..
  240. 'label[0.35,0.25;Are you sure you want to delete this marker?]' ..
  241. 'button[0,1;3,1;cancel;Cancel]' ..
  242. 'button[3,1;3,1;delete_confirm;Delete]')
  243. elseif fields.delete_confirm then
  244. advmarkers.delete_waypoint(name)
  245. selected_name = false
  246. advmarkers.display_formspec()
  247. elseif fields.cancel then
  248. advmarkers.display_formspec()
  249. elseif name ~= selected_name then
  250. selected_name = name
  251. advmarkers.display_formspec()
  252. end
  253. elseif fields.display or fields.delete then
  254. minetest.display_chat_message('Please select a marker.')
  255. end
  256. return true
  257. end)
  258. -- Update the waypoint list
  259. minetest.register_on_receiving_chat_message(function(message)
  260. if message:sub(1, #csm_key) == csm_key then
  261. advmarkers.import(message:sub(#csm_key + 1), true)
  262. return true
  263. end
  264. end)
  265. run_remote_command()