The CSM version of advmarkers.
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.

406 lignes
13KB

  1. --
  2. -- Minetest advmarkers CSM
  3. --
  4. -- Needs the https://github.com/Billy-S/kingdoms_game/tree/master/mods/marker
  5. -- mod to be able to display HUD elements
  6. --
  7. advmarkers = {}
  8. -- Get the mod storage
  9. local storage = minetest.get_mod_storage()
  10. -- Convert positions to/from strings
  11. local function pos_to_string(pos)
  12. if type(pos) == 'table' then
  13. pos = minetest.pos_to_string(vector.round(pos))
  14. end
  15. if type(pos) == 'string' then
  16. return pos
  17. end
  18. end
  19. local function string_to_pos(pos)
  20. if type(pos) == 'string' then
  21. pos = minetest.string_to_pos(pos)
  22. end
  23. if type(pos) == 'table' then
  24. return vector.round(pos)
  25. end
  26. end
  27. -- Set the HUD position
  28. -- TODO: Make this entirely client-side or allow the command to be changed.
  29. function advmarkers.set_hud_pos(pos)
  30. pos = string_to_pos(pos)
  31. if not pos then return end
  32. minetest.run_server_chatcommand('mrkr', tostring(pos.x) .. ' ' ..
  33. tostring(pos.y) .. ' ' .. tostring(pos.z))
  34. return true
  35. end
  36. -- Add a marker
  37. function advmarkers.set_marker(pos, name)
  38. pos = pos_to_string(pos)
  39. if not pos then return end
  40. storage:set_string('marker-' .. tostring(name), pos)
  41. return true
  42. end
  43. -- Delete a marker
  44. function advmarkers.delete_marker(name)
  45. storage:set_string('marker-' .. tostring(name), '')
  46. end
  47. -- Get a marker
  48. function advmarkers.get_marker(name)
  49. return string_to_pos(storage:get_string('marker-' .. tostring(name)))
  50. end
  51. -- Rename a marker and re-interpret the position.
  52. function advmarkers.rename_marker(oldname, newname)
  53. oldname, newname = tostring(oldname), tostring(newname)
  54. local pos = advmarkers.get_marker(oldname)
  55. if not pos or not advmarkers.set_marker(pos, newname) then return end
  56. if oldname ~= newname then
  57. advmarkers.delete_marker(oldname)
  58. end
  59. return true
  60. end
  61. -- Display a marker
  62. function advmarkers.display_marker(name)
  63. return advmarkers.set_hud_pos(advmarkers.get_marker(name))
  64. end
  65. -- Export markers
  66. function advmarkers.export(raw)
  67. local s = storage:to_table().fields
  68. if raw == 'M' then
  69. s = minetest.compress(minetest.serialize(s))
  70. s = 'M' .. minetest.encode_base64(s)
  71. elseif not raw then
  72. s = minetest.compress(minetest.write_json(s))
  73. s = 'J' .. minetest.encode_base64(s)
  74. end
  75. return s
  76. end
  77. -- Import markers
  78. function advmarkers.import(s)
  79. if type(s) ~= 'table' then
  80. local ver = s:sub(1, 1)
  81. if ver ~= 'M' and ver ~= 'J' then return end
  82. s = minetest.decode_base64(s:sub(2))
  83. local success, msg = pcall(minetest.decompress, s)
  84. if not success then return end
  85. if ver == 'M' then
  86. s = minetest.deserialize(msg)
  87. else
  88. s = minetest.parse_json(msg)
  89. end
  90. end
  91. -- Iterate over markers to preserve existing ones and check for errors.
  92. if type(s) == 'table' then
  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. storage:get_string(name) ~= pos then
  97. -- Prevent collisions
  98. local c = 0
  99. while #storage:get_string(name) > 0 and c < 50 do
  100. name = name .. '_'
  101. c = c + 1
  102. end
  103. -- Sanity check
  104. if c < 50 then
  105. storage:set_string(name, pos)
  106. end
  107. end
  108. end
  109. return true
  110. end
  111. end
  112. -- Get the markers formspec
  113. local formspec_list = {}
  114. local selected_name = false
  115. function advmarkers.display_formspec()
  116. local formspec = 'size[5.25,8]' ..
  117. 'label[0,0;Marker list]' ..
  118. 'button_exit[0,7.5;1.3125,0.5;display;Display]' ..
  119. 'button[1.3125,7.5;1.3125,0.5;teleport;Teleport]' ..
  120. 'button[2.625,7.5;1.3125,0.5;rename;Rename]' ..
  121. 'button[3.9375,7.5;1.3125,0.5;delete;Delete]' ..
  122. 'textlist[0,0.75;5,6;marker;'
  123. -- Iterate over all the markers
  124. local id = 0
  125. local selected = 1
  126. formspec_list = {}
  127. for name, pos in pairs(storage:to_table().fields) do
  128. if name:sub(1, 7) == 'marker-' then
  129. id = id + 1
  130. if id > 1 then
  131. formspec = formspec .. ','
  132. end
  133. name = name:sub(8)
  134. if not selected_name then
  135. selected_name = name
  136. end
  137. if name == selected_name then
  138. selected = id
  139. end
  140. formspec_list[#formspec_list + 1] = name
  141. formspec = formspec .. '##' .. minetest.formspec_escape(name)
  142. end
  143. end
  144. -- Close the text list and display the selected marker position
  145. formspec = formspec .. ';' .. tostring(selected) .. ']'
  146. if selected_name then
  147. local pos = advmarkers.get_marker(selected_name)
  148. if pos then
  149. pos = minetest.formspec_escape(tostring(pos.x) .. ', ' ..
  150. tostring(pos.y) .. ', ' .. tostring(pos.z))
  151. pos = 'Marker position: ' .. pos
  152. formspec = formspec .. 'label[0,6.75;' .. pos .. ']'
  153. end
  154. else
  155. -- Draw over the buttons
  156. formspec = formspec .. 'button_exit[0,7.5;5.25,0.5;quit;Close dialog]' ..
  157. 'label[0,6.75;No markers. Add one with ".add_mrkr".]'
  158. end
  159. -- Display the formspec
  160. return minetest.show_formspec('advmarkers-csm', formspec)
  161. end
  162. -- Open the markers GUI
  163. minetest.register_chatcommand('mrkr', {
  164. params = '',
  165. description = 'Open the advmarkers GUI',
  166. func = advmarkers.display_formspec
  167. })
  168. -- Add a marker
  169. minetest.register_chatcommand('add_mrkr', {
  170. params = '<pos / "here" / "there"> <name>',
  171. description = 'Adds a marker.',
  172. func = function(param)
  173. local s, e = param:find(' ')
  174. if not s or not e then
  175. return false, 'Invalid syntax! See .help add_mrkr for more info.'
  176. end
  177. local pos = param:sub(1, s - 1)
  178. local name = param:sub(e + 1)
  179. -- Validate the position
  180. if pos == 'here' then
  181. pos = minetest.localplayer:get_pos()
  182. elseif pos == 'there' then
  183. if not advmarkers.last_coords then
  184. return false, 'No-one has used ".coords" and you have not died!'
  185. end
  186. pos = advmarkers.last_coords
  187. else
  188. pos = string_to_pos(pos)
  189. if not pos then
  190. return false, 'Invalid position!'
  191. end
  192. end
  193. -- Validate the name
  194. if not name or #name < 1 then
  195. return false, 'Invalid name!'
  196. end
  197. -- Set the marker
  198. return advmarkers.set_marker(pos, name), 'Done!'
  199. end
  200. })
  201. -- Set the HUD
  202. minetest.register_on_formspec_input(function(formname, fields)
  203. if formname == 'advmarkers-ignore' then
  204. return true
  205. elseif formname ~= 'advmarkers-csm' then
  206. return
  207. end
  208. local name = false
  209. if fields.marker then
  210. local event = minetest.explode_textlist_event(fields.marker)
  211. if event.index then
  212. name = formspec_list[event.index]
  213. end
  214. else
  215. name = selected_name
  216. end
  217. if name then
  218. if fields.display then
  219. if not advmarkers.display_marker(name) then
  220. minetest.display_chat_message('Error displaying marker!')
  221. end
  222. elseif fields.rename then
  223. minetest.show_formspec('advmarkers-csm', 'size[6,3]' ..
  224. 'label[0.35,0.2;Rename marker]' ..
  225. 'field[0.3,1.3;6,1;new_name;New name;' ..
  226. minetest.formspec_escape(name) .. ']' ..
  227. 'button[0,2;3,1;cancel;Cancel]' ..
  228. 'button[3,2;3,1;rename_confirm;Rename]')
  229. elseif fields.rename_confirm then
  230. if fields.new_name and #fields.new_name > 0 then
  231. if advmarkers.rename_marker(name, fields.new_name) then
  232. selected_name = fields.new_name
  233. else
  234. minetest.display_chat_message('Error renaming marker!')
  235. end
  236. advmarkers.display_formspec()
  237. else
  238. minetest.display_chat_message(
  239. 'Please enter a new name for the marker.'
  240. )
  241. end
  242. elseif fields.teleport then
  243. minetest.show_formspec('advmarkers-csm', 'size[6,2.2]' ..
  244. 'label[0.35,0.25;' .. minetest.formspec_escape(
  245. 'Teleport to a marker\n - ' .. name
  246. ) .. ']' ..
  247. 'button[0,1.25;2,1;cancel;Cancel]' ..
  248. 'button_exit[2,1.25;1,1;teleport_tpj;/tpj]' ..
  249. 'button_exit[3,1.25;1,1;teleport_tpc;/tpc]' ..
  250. 'button_exit[4,1.25;2,1;teleport_confirm;/teleport]')
  251. elseif fields.teleport_tpj then
  252. -- Teleport with /tpj
  253. local pos = advmarkers.get_marker(name)
  254. if pos and minetest.localplayer then
  255. local cpos = minetest.localplayer:get_pos()
  256. for _, dir in ipairs({'x', 'y', 'z'}) do
  257. local distance = pos[dir] - cpos[dir]
  258. minetest.run_server_chatcommand('tpj', dir .. ' ' ..
  259. tostring(distance))
  260. end
  261. else
  262. minetest.display_chat_message('Error teleporting to marker!')
  263. end
  264. elseif fields.teleport_confirm or fields.teleport_tpc then
  265. -- Teleport with /teleport
  266. local pos = advmarkers.get_marker(name)
  267. local cmd
  268. if fields.teleport_confirm then
  269. cmd = 'teleport'
  270. else
  271. cmd = 'tpc'
  272. end
  273. if pos and minetest.localplayer then
  274. minetest.run_server_chatcommand(cmd,
  275. pos.x .. ',' .. pos.y .. ',' .. pos.z)
  276. else
  277. minetest.display_chat_message('Error teleporting to marker!')
  278. end
  279. elseif fields.delete then
  280. minetest.show_formspec('advmarkers-csm', 'size[6,2]' ..
  281. 'label[0.35,0.25;Are you sure you want to delete this marker?]' ..
  282. 'button[0,1;3,1;cancel;Cancel]' ..
  283. 'button[3,1;3,1;delete_confirm;Delete]')
  284. elseif fields.delete_confirm then
  285. advmarkers.delete_marker(name)
  286. selected_name = false
  287. advmarkers.display_formspec()
  288. elseif fields.cancel then
  289. advmarkers.display_formspec()
  290. elseif name ~= selected_name then
  291. selected_name = name
  292. advmarkers.display_formspec()
  293. end
  294. elseif fields.display or fields.delete then
  295. minetest.display_chat_message('Please select a marker.')
  296. end
  297. return true
  298. end)
  299. -- Auto-add markers on death.
  300. minetest.register_on_death(function()
  301. if minetest.localplayer then
  302. local name = os.date('Death on %Y-%m-%d %H:%M:%S')
  303. local pos = minetest.localplayer:get_pos()
  304. advmarkers.last_coords = pos
  305. advmarkers.set_marker(pos, name)
  306. minetest.display_chat_message('Added marker "' .. name .. '".')
  307. end
  308. end)
  309. -- Allow string exporting
  310. minetest.register_chatcommand('mrkr_export', {
  311. params = '[old]',
  312. description = 'Exports an advmarkers string containing all your markers.',
  313. func = function(param)
  314. local export
  315. if param == 'old' then
  316. export = advmarkers.export('M')
  317. else
  318. export = advmarkers.export()
  319. end
  320. minetest.show_formspec('advmarkers-ignore',
  321. 'field[_;Your marker export string;' ..
  322. minetest.formspec_escape(export) .. ']')
  323. end
  324. })
  325. -- String importing
  326. minetest.register_chatcommand('mrkr_import', {
  327. params = '<advmarkers string>',
  328. description = 'Imports an advmarkers string. This will not overwrite ' ..
  329. 'existing markers that have the same name.',
  330. func = function(param)
  331. if advmarkers.import(param) then
  332. return true, 'Markers imported!'
  333. else
  334. return false, 'Invalid advmarkers string!'
  335. end
  336. end
  337. })
  338. -- Upload markers to the advmarkers server-side mod.
  339. minetest.register_chatcommand('mrkr_upload', {
  340. params = '',
  341. description = 'Uploads all markers to this server\'s advmarkers storage.',
  342. func = function(param)
  343. local data = advmarkers.export()
  344. minetest.run_server_chatcommand('mrkr_import', data)
  345. end
  346. })
  347. -- Chat channels .coords integration.
  348. -- You do not need to have chat channels installed for this to work.
  349. if not minetest.registered_on_receiving_chat_message then
  350. minetest.registered_on_receiving_chat_message =
  351. minetest.registered_on_receiving_chat_messages
  352. end
  353. table.insert(minetest.registered_on_receiving_chat_message, 1, function(msg)
  354. local s, e = msg:find('Current Position: %-?[0-9]+, %-?[0-9]+, %-?[0-9]+%.')
  355. if s and e then
  356. local pos = string_to_pos(msg:sub(s + 18, e - 1))
  357. if pos then
  358. advmarkers.last_coords = pos
  359. end
  360. end
  361. end)
  362. -- Add '.mrkrthere'
  363. minetest.register_chatcommand('mrkrthere', {
  364. params = '',
  365. description = 'Adds a (temporary) marker at the last ".coords" position.',
  366. func = function(param)
  367. if not advmarkers.last_coords then
  368. return false, 'No-one has used ".coords" and you have not died!'
  369. elseif not advmarkers.set_hud_pos(advmarkers.last_coords) then
  370. return false, 'Error setting the marker!'
  371. end
  372. end
  373. })