init.lua 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. if not minetest.global_exists("rename") then rename = {} end
  2. rename.modpath = minetest.get_modpath("rename")
  3. -- Localize for performance.
  4. local math_random = math.random
  5. -- Make sure a chosen name is valid.
  6. -- We don't want players picking names that are impossible.
  7. function rename.validate_name(dname)
  8. if string.len(dname) > 20 then
  9. return false
  10. end
  11. if string.find(dname, "^[%w_]+$") then
  12. return true
  13. end
  14. end
  15. -- API function. Renames a player (validates, but costs nothing).
  16. -- Returns success if the rename is valid.
  17. -- First argument must be the player's real name.
  18. -- Second argument must be the chosen alt.
  19. function rename.rename_player(pname, dname, tell)
  20. -- Rout chat messages to 'tell'.
  21. -- If undefined then route chat messages to 'pname'.
  22. if not tell then
  23. tell = pname
  24. end
  25. -- Don't rename non-existent players.
  26. -- This avoids creating alias for players that don't yet exist.
  27. -- Doing so prevents real players from logging in with that name.
  28. if not minetest.player_exists(pname) then
  29. minetest.chat_send_player(tell, "# Server: Player <" .. pname .. "> does not exist.")
  30. return
  31. end
  32. -- If the new alias is the same as the old alias, do nothing.
  33. if dname == rename.gpn(pname) then
  34. minetest.chat_send_player(tell, "# Server: You are already called <" .. dname .. ">!")
  35. easyvend.sound_error(tell)
  36. return
  37. end
  38. -- Remove name from storage if it's the same as the original, internal name.
  39. -- This has to come before the impersonation checks, otherwise
  40. -- players would never be able to change their names back to the original.
  41. if dname == pname then
  42. local oname = rename.gpn(pname)
  43. local lname = string.lower(oname)
  44. -- Clear both keys: realname --> nick, and nick --> realname.
  45. rename.modstorage:set_string(pname .. ":org", nil)
  46. rename.modstorage:set_string(oname .. ":alt", nil)
  47. rename.modstorage:set_string(lname .. ":low", nil)
  48. -- Only send a chat message about it if the new alias
  49. -- is different from the old alias.
  50. if oname ~= dname then
  51. minetest.chat_send_all("# Server: Player <" .. oname .. "> renamed to <" .. pname .. ">!")
  52. end
  53. -- Update player's nametag if needed.
  54. player_labels.update_nametag_text(pname)
  55. return true
  56. end
  57. -- The new alias is *not* the same as the player's original name.
  58. -- This means we need to record the change (after a few more checks).
  59. -- Use the anticurse name-checker.
  60. -- This returns a string if the name would be rejected.
  61. local check = anticurse.on_prejoinplayer(dname)
  62. if type(check) == "string" then
  63. minetest.chat_send_player(tell, "# Server: " .. check)
  64. easyvend.sound_error(tell)
  65. return
  66. end
  67. -- Check if a name similar to this exists.
  68. local lname = string.lower(dname)
  69. local uname = rename.modstorage:get_string(lname .. ":low")
  70. if uname and uname ~= "" then
  71. -- Players are allowed to change the capitalization of their own alt name.
  72. if uname ~= pname then
  73. minetest.chat_send_player(tell, "# Server: Another name differing only in letter-case is already allocated by someone else.")
  74. easyvend.sound_error(tell)
  75. return
  76. end
  77. end
  78. -- Check the auth database to ensure players cannot choose names that are already allocated.
  79. do
  80. local get_auth = minetest.get_auth_handler().get_auth
  81. assert(type(get_auth) == "function")
  82. local check_name = minetest.get_auth_handler().check_similar_name
  83. assert(type(check_name) == "function")
  84. -- Check auth table to see if an entry with this exact name already exists.
  85. if get_auth(dname) ~= nil then
  86. minetest.chat_send_player(tell, "# Server: That name is currently allocated by someone else.")
  87. easyvend.sound_error(tell)
  88. return
  89. end
  90. -- Search the auth table to see if there is already a similar name.
  91. local names = check_name(dname)
  92. for k, v in pairs(names) do
  93. if v:lower() == lname then
  94. -- Players are allowed to chose names that differ in case from their original.
  95. if v:lower() ~= pname then
  96. minetest.chat_send_player(tell, "# Server: That name or a similar one is already allocated!")
  97. easyvend.sound_error(tell)
  98. return
  99. end
  100. end
  101. end
  102. end
  103. -- Don't allow impersonation.
  104. if minetest.player_exists(dname) or minetest.get_player_by_name(dname) then
  105. minetest.chat_send_player(tell, "# Server: That name is currently allocated by someone else.")
  106. easyvend.sound_error(tell)
  107. return
  108. end
  109. -- Check if name is valid.
  110. if not rename.validate_name(dname) then
  111. minetest.chat_send_player(tell, "# Server: Chosen name is invalid for use as a nick!")
  112. easyvend.sound_error(tell)
  113. return
  114. end
  115. -- Get player's old alt-name, if they had one.
  116. local cname = rename.gpn(pname)
  117. -- Add name to storage.
  118. -- There are two keys, realname --> nick, and nick --> realname.
  119. -- This allows us to obtain either name.
  120. -- We make a distinction between original names and alts with a postfix.
  121. -- This is necessary to prevent getting them confused.
  122. rename.modstorage:set_string(pname .. ":org", dname)
  123. rename.modstorage:set_string(dname .. ":alt", pname)
  124. rename.modstorage:set_string(string.lower(dname) .. ":low", pname)
  125. -- The old alt must be removed. This prevents corruption.
  126. rename.modstorage:set_string(cname .. ":alt", nil)
  127. rename.modstorage:set_string(string.lower(cname) .. ":low", nil)
  128. minetest.chat_send_all("# Server: Player <" .. cname .. "> is reidentified as <" .. dname .. ">!")
  129. -- Update player's nametag if needed.
  130. player_labels.update_nametag_text(pname)
  131. local player = minetest.get_player_by_name(pname)
  132. if player then
  133. pova.set_override(player, "properties", {infotext = rename.gpn(pname)})
  134. pova.set_override(player, "nametag", {text=rename.gpn(pname)})
  135. end
  136. return true
  137. end
  138. -- Get a player's display-name.
  139. -- Just returns their original name if no alias has been stored.
  140. -- This function has a shortname for ease of use.
  141. -- Note: this function may be called in contexts where the player is not online.
  142. function rename.get_player_name(pname)
  143. -- nil check.
  144. if not pname or pname == "" then
  145. return ""
  146. end
  147. local dname = rename.modstorage:get_string(pname .. ":org")
  148. if not dname or dname == "" then
  149. return pname
  150. end
  151. return dname
  152. end
  153. rename.gpn = rename.get_player_name
  154. -- Obtain a player's real name, if passed an alias name.
  155. -- If passed a player's real name, it is simply returned.
  156. -- This is the opposite of the previous function.
  157. function rename.get_real_name(name)
  158. local pname = rename.modstorage:get_string(name .. ":alt")
  159. if pname and pname ~= "" then
  160. -- The alias is registered, so return the real name it links to.
  161. return pname
  162. end
  163. -- No alias? Then return our argument as the real name.
  164. return name
  165. end
  166. rename.grn = rename.get_real_name
  167. -- Called from on_prejoinplayer (from the AC mod).
  168. -- This prevents players from joining with already-allocated names.
  169. -- This function assumes the given name is an alt to check for.
  170. function rename.name_currently_allocated(dname)
  171. local pname = rename.modstorage:get_string(dname .. ":alt")
  172. if pname and pname ~= "" then
  173. -- A real name is associated with this alt, which means this
  174. -- alt name must be considered allocated, too.
  175. return true
  176. end
  177. local lname = string.lower(dname)
  178. pname = rename.modstorage:get_string(lname .. ":low")
  179. if pname and pname ~= "" then
  180. -- A capitialized form of this name exists, so this name too
  181. -- must be considered allocated. The only difference is case.
  182. return true
  183. end
  184. end
  185. -- This is the function players should have access to.
  186. -- It performs cost validation.
  187. function rename.purchase_rename(pname, dname)
  188. -- Get player.
  189. local player = minetest.get_player_by_name(pname)
  190. if not player then
  191. return
  192. end
  193. dname = string.trim(dname)
  194. if #dname < 1 then
  195. minetest.chat_send_player(pname, "# Server: No nickname specified.")
  196. easyvend.sound_error(pname)
  197. return
  198. end
  199. -- The cost is ...
  200. local cost = "survivalist:copper_skill_token"
  201. -- Check if player can pay.
  202. local inv = player:get_inventory()
  203. if not inv:contains_item("main", cost) then
  204. minetest.chat_send_player(pname, "# Server: Changing your nickname costs 1 Copper Skill Mark (earned by completing an Iceworld Challenge).")
  205. minetest.chat_send_player(pname, "# Server: Have a Copper Skill Mark in your main inventory before running this command.")
  206. easyvend.sound_error(pname)
  207. return
  208. end
  209. if rename.rename_player(pname, dname) then
  210. -- Take cost, rename was successful.
  211. inv:remove_item("main", cost)
  212. minetest.chat_send_player(pname, "# Server: 1 Copper Skill Mark taken!")
  213. return
  214. end
  215. -- Something went wrong.
  216. minetest.chat_send_player(pname, "# Server: Name not changed, you are still called <" .. rename.gpn(pname) .. ">! No cost taken.")
  217. easyvend.sound_error(pname)
  218. end
  219. function rename.execute_whoami(pname)
  220. minetest.chat_send_player(pname, "# Server: You are recognized as <" .. rename.grn(pname) .. ">.")
  221. end
  222. help_info =
  223. "===| Charter Regulations For Aliases |===\n\n" ..
  224. "All people registered as Citizens of the Colony have the lawful opportunity " ..
  225. "(with conditions) to change the name that is shown to other Citizens, be it " ..
  226. "shown through communication channels and in avatar-to-avatar meetings. If you " ..
  227. "wish to change your name (which is here, and in other places, refered to as " ..
  228. "your Alias) then do read the following carefully. You will need to scroll the " ..
  229. "text.\n\n" ..
  230. "To discourage missuse of this capability, the Colony Controler requires a " ..
  231. "payment of 1 Copper Skill Token before Citizens are allowed to change their " ..
  232. "official alias. A Citizen earns these tokens by proving their determination " ..
  233. "and skill by successfully completing the Iceworld Challenge. A Citizen may " ..
  234. "change their Alias as many times as they can afford to do so; however be " ..
  235. "warned that this can confuse others.\n\n" ..
  236. "When you change your Alias, it will be used in all your communication as seen " ..
  237. "by other Citizens and non-citizens, including the main chat. You may or may " ..
  238. "not be able to observe this change yourself, depending on the date of your " ..
  239. "client's software.\n\n" ..
  240. "When you choose an Alias, the Alias which you choose becomes a second name, " ..
  241. "with as much lawful authority as the first. You will continue to have access " ..
  242. "to all your protected land, and to any shared locations which other Citizens " ..
  243. "may have shared with you. You will continue to own this second name (along " ..
  244. "with your first) until you release it by choosing another. While you own your " ..
  245. "Alias, no one else may claim that Alias, or any similar to it in terms of " ..
  246. "capitalization. Also, no one may enter the Colony with that name or any name " ..
  247. "similar to it (again, in terms of capitalization). Other Citizens may send you " ..
  248. "Key-Mail using your Alias, and use bounty marks or gag orders or jailers on you, " ..
  249. "also using your Alias. Other Citizens may send you PMs using your Alias. Any new land you " ..
  250. "protect and items you own will continue to be protected under your original " ..
  251. "identification, which cannot be changed.\n\n" ..
  252. "No Alias can be the same as another player's identification or other Alias. No " ..
  253. "two players may have the same Alias at once. A Citizen can have only one Alias " ..
  254. "at a time, making a max total of two names per Citizen. When a Citizen chooses " ..
  255. "an Alias, any previous Alias they may have owned becomes free for another " ..
  256. "Citizen to claim. Using an Alias does not override the original name, and a " ..
  257. "Citizen's original name may still be used in communication by other players " ..
  258. "and in shares and in commands.\n\n" ..
  259. "If you change your Alias, you must do so with the understanding that this does " ..
  260. "NOT change your login credentials. You must still login to the server using " ..
  261. "your ORIGINAL player name!\n\n" ..
  262. "===| End Charter Alias Regulations |==="
  263. -- Compost the GUI formspec.
  264. function rename.compose_formspec(pname)
  265. local formspec = ""
  266. formspec = formspec .. "size[8,7]" ..
  267. default.gui_bg ..
  268. default.gui_bg_img ..
  269. default.gui_slots ..
  270. "label[0,0;Alias Registration]" ..
  271. "textarea[0.3,0.5;8,3;info;;" .. minetest.formspec_escape(help_info) .. "]" ..
  272. "field[0.3,4;4,1;alias;Write New Legal Alias;]" ..
  273. "button[0,6.2;3,1;choose;Recognize Alias]" ..
  274. "label[0,5.2;Your registered alias is <" .. rename.gpn(pname) .. ">.]" ..
  275. "label[0,5.6;Your legal identification is <" .. pname .. ">.]" ..
  276. "button[6,6.2;2,1;close;Close]"
  277. return formspec
  278. end
  279. -- API function (called from passport mod, for instance).
  280. function rename.show_formspec(pname)
  281. local formspec = rename.compose_formspec(pname)
  282. minetest.show_formspec(pname, "rename:rename", formspec)
  283. end
  284. -- GUI form input handler.
  285. function rename.on_receive_fields(player, formname, fields)
  286. local pname = player:get_player_name()
  287. if formname ~= "rename:rename" then
  288. return
  289. end
  290. if fields.quit then
  291. return true
  292. end
  293. if fields.choose then
  294. rename.purchase_rename(pname, fields.alias)
  295. minetest.close_formspec(pname, "rename:rename")
  296. return true
  297. end
  298. if fields.close then
  299. -- Go back to the KoC control panel.
  300. passport.show_formspec(pname)
  301. return true
  302. end
  303. return true
  304. end
  305. if not rename.run_once then
  306. rename.modstorage = minetest.get_mod_storage()
  307. -- Override engine functions.
  308. dofile(rename.modpath .. "/overrides.lua")
  309. minetest.register_chatcommand("whoami", {
  310. params = "",
  311. description = "Get your original login-name.",
  312. privs = {interact=true},
  313. func = function(pname, param)
  314. rename.execute_whoami(pname)
  315. return true
  316. end,
  317. })
  318. -- GUI input handler.
  319. minetest.register_on_player_receive_fields(function(...)
  320. return rename.on_receive_fields(...)
  321. end)
  322. local c = "rename:core"
  323. local f = rename.modpath .. "/init.lua"
  324. reload.register_file(c, f, false)
  325. rename.run_once = true
  326. end