init.lua 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. rename = rename or {}
  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. player:set_properties({
  134. infotext = rename.gpn(pname),
  135. })
  136. end
  137. return true
  138. end
  139. -- Get a player's display-name.
  140. -- Just returns their original name if no alias has been stored.
  141. -- This function has a shortname for ease of use.
  142. -- Note: this function may be called in contexts where the player is not online.
  143. function rename.get_player_name(pname)
  144. -- nil check.
  145. if not pname or pname == "" then
  146. return ""
  147. end
  148. local dname = rename.modstorage:get_string(pname .. ":org")
  149. if not dname or dname == "" then
  150. return pname
  151. end
  152. return dname
  153. end
  154. rename.gpn = rename.get_player_name
  155. -- Obtain a player's real name, if passed an alias name.
  156. -- If passed a player's real name, it is simply returned.
  157. -- This is the opposite of the previous function.
  158. function rename.get_real_name(name)
  159. local pname = rename.modstorage:get_string(name .. ":alt")
  160. if pname and pname ~= "" then
  161. -- The alias is registered, so return the real name it links to.
  162. return pname
  163. end
  164. -- No alias? Then return our argument as the real name.
  165. return name
  166. end
  167. rename.grn = rename.get_real_name
  168. -- Called from on_prejoinplayer (from the AC mod).
  169. -- This prevents players from joining with already-allocated names.
  170. -- This function assumes the given name is an alt to check for.
  171. function rename.name_currently_allocated(dname)
  172. local pname = rename.modstorage:get_string(dname .. ":alt")
  173. if pname and pname ~= "" then
  174. -- A real name is associated with this alt, which means this
  175. -- alt name must be considered allocated, too.
  176. return true
  177. end
  178. local lname = string.lower(dname)
  179. pname = rename.modstorage:get_string(lname .. ":low")
  180. if pname and pname ~= "" then
  181. -- A capitialized form of this name exists, so this name too
  182. -- must be considered allocated. The only difference is case.
  183. return true
  184. end
  185. end
  186. -- This is the function players should have access to.
  187. -- It performs cost validation.
  188. function rename.purchase_rename(pname, dname)
  189. -- Get player.
  190. local player = minetest.get_player_by_name(pname)
  191. if not player then
  192. return
  193. end
  194. dname = string.trim(dname)
  195. if #dname < 1 then
  196. minetest.chat_send_player(pname, "# Server: No nickname specified.")
  197. easyvend.sound_error(pname)
  198. return
  199. end
  200. -- The cost is ...
  201. local cost = "survivalist:copper_skill_token"
  202. -- Check if player can pay.
  203. local inv = player:get_inventory()
  204. if not inv:contains_item("main", cost) then
  205. minetest.chat_send_player(pname, "# Server: Changing your nickname costs 1 Copper Skill Mark (earned by completing an Iceworld Challenge).")
  206. minetest.chat_send_player(pname, "# Server: Have a Copper Skill Mark in your main inventory before running this command.")
  207. easyvend.sound_error(pname)
  208. return
  209. end
  210. if rename.rename_player(pname, dname) then
  211. -- Take cost, rename was successful.
  212. inv:remove_item("main", cost)
  213. minetest.chat_send_player(pname, "# Server: 1 Copper Skill Mark taken!")
  214. return
  215. end
  216. -- Something went wrong.
  217. minetest.chat_send_player(pname, "# Server: Name not changed, you are still called <" .. rename.gpn(pname) .. ">! No cost taken.")
  218. easyvend.sound_error(pname)
  219. end
  220. function rename.execute_whoami(pname)
  221. minetest.chat_send_player(pname, "# Server: You are recognized as <" .. rename.grn(pname) .. ">.")
  222. end
  223. help_info =
  224. "===| Charter Regulations For Aliases |===\n\n" ..
  225. "All people registered as Citizens of the Colony have the lawful opportunity " ..
  226. "(with conditions) to change the name that is shown to other Citizens, be it " ..
  227. "shown through communication channels and in avatar-to-avatar meetings. If you " ..
  228. "wish to change your name (which is here, and in other places, refered to as " ..
  229. "your Alias) then do read the following carefully. You will need to scroll the " ..
  230. "text.\n\n" ..
  231. "To discourage missuse of this capability, the Colony Controler requires a " ..
  232. "payment of 1 Copper Skill Token before Citizens are allowed to change their " ..
  233. "official alias. A Citizen earns these tokens by proving their determination " ..
  234. "and skill by successfully completing the Iceworld Challenge. A Citizen may " ..
  235. "change their Alias as many times as they can afford to do so; however be " ..
  236. "warned that this can confuse others.\n\n" ..
  237. "When you change your Alias, it will be used in all your communication as seen " ..
  238. "by other Citizens and non-citizens, including the main chat. You may or may " ..
  239. "not be able to observe this change yourself, depending on the date of your " ..
  240. "client's software.\n\n" ..
  241. "When you choose an Alias, the Alias which you choose becomes a second name, " ..
  242. "with as much lawful authority as the first. You will continue to have access " ..
  243. "to all your protected land, and to any shared locations which other Citizens " ..
  244. "may have shared with you. You will continue to own this second name (along " ..
  245. "with your first) until you release it by choosing another. While you own your " ..
  246. "Alias, no one else may claim that Alias, or any similar to it in terms of " ..
  247. "capitalization. Also, no one may enter the Colony with that name or any name " ..
  248. "similar to it (again, in terms of capitalization). Other Citizens may send you " ..
  249. "Key-Mail using your Alias, and use bounty marks or gag orders or jailers on you, " ..
  250. "also using your Alias. Other Citizens may send you PMs using your Alias. Any new land you " ..
  251. "protect and items you own will continue to be protected under your original " ..
  252. "identification, which cannot be changed.\n\n" ..
  253. "No Alias can be the same as another player's identification or other Alias. No " ..
  254. "two players may have the same Alias at once. A Citizen can have only one Alias " ..
  255. "at a time, making a max total of two names per Citizen. When a Citizen chooses " ..
  256. "an Alias, any previous Alias they may have owned becomes free for another " ..
  257. "Citizen to claim. Using an Alias does not override the original name, and a " ..
  258. "Citizen's original name may still be used in communication by other players " ..
  259. "and in shares and in commands.\n\n" ..
  260. "If you change your Alias, you must do so with the understanding that this does " ..
  261. "NOT change your login credentials. You must still login to the server using " ..
  262. "your ORIGINAL player name!\n\n" ..
  263. "===| End Charter Alias Regulations |==="
  264. -- Compost the GUI formspec.
  265. function rename.compose_formspec(pname)
  266. local formspec = ""
  267. formspec = formspec .. "size[8,7]" ..
  268. default.gui_bg ..
  269. default.gui_bg_img ..
  270. default.gui_slots ..
  271. "label[0,0;Alias Registration]" ..
  272. "textarea[0.3,0.5;8,3;info;;" .. minetest.formspec_escape(help_info) .. "]" ..
  273. "field[0.3,4;4,1;alias;Write New Legal Alias;]" ..
  274. "button[0,6.2;3,1;choose;Recognize Alias]" ..
  275. "label[0,5.2;Your registered alias is <" .. rename.gpn(pname) .. ">.]" ..
  276. "label[0,5.6;Your legal identification is <" .. pname .. ">.]" ..
  277. "button[6,6.2;2,1;close;Close]"
  278. return formspec
  279. end
  280. -- API function (called from passport mod, for instance).
  281. function rename.show_formspec(pname)
  282. local formspec = rename.compose_formspec(pname)
  283. minetest.show_formspec(pname, "rename:rename", formspec)
  284. end
  285. -- GUI form input handler.
  286. function rename.on_receive_fields(player, formname, fields)
  287. local pname = player:get_player_name()
  288. if formname ~= "rename:rename" then
  289. return
  290. end
  291. if fields.quit then
  292. return true
  293. end
  294. if fields.choose then
  295. rename.purchase_rename(pname, fields.alias)
  296. minetest.close_formspec(pname, "rename:rename")
  297. return true
  298. end
  299. if fields.close then
  300. -- Go back to the KoC control panel.
  301. passport.show_formspec(pname)
  302. return true
  303. end
  304. return true
  305. end
  306. if not rename.run_once then
  307. rename.modstorage = minetest.get_mod_storage()
  308. -- Override engine functions.
  309. dofile(rename.modpath .. "/overrides.lua")
  310. minetest.register_chatcommand("whoami", {
  311. params = "",
  312. description = "Get your original login-name.",
  313. privs = {interact=true},
  314. func = function(pname, param)
  315. rename.execute_whoami(pname)
  316. return true
  317. end,
  318. })
  319. -- GUI input handler.
  320. minetest.register_on_player_receive_fields(function(...)
  321. return rename.on_receive_fields(...)
  322. end)
  323. local c = "rename:core"
  324. local f = rename.modpath .. "/init.lua"
  325. reload.register_file(c, f, false)
  326. rename.run_once = true
  327. end