diff --git a/doc/lua_api.md b/doc/lua_api.md index 5713e86966dc0..389ea73f272fa 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -7097,6 +7097,8 @@ Misc. * `minetest.is_player(obj)`: boolean, whether `obj` is a player * `minetest.player_exists(name)`: boolean, whether player exists (regardless of online status) +* `minetest.is_valid_player_name(name)`: boolean, whether the given name + could be used as a player name (regardless of whether said player exists). * `minetest.hud_replace_builtin(name, hud_definition)` * Replaces definition of a builtin hud element * `name`: `"breath"`, `"health"` or `"minimap"` @@ -7989,9 +7991,9 @@ child will follow movement and rotation of that bone. * `set_observers(observers)`: sets observers (players this object is sent to) * If `observers` is `nil`, the object's observers are "unmanaged": The object is sent to all players as governed by server settings. This is the default. - * `observers` is a "set" of player names: `{[player name] = true, [other player name] = true, ...}` - * A set is a table where the keys are the elements of the set (in this case, player names) - and the values are all `true`. + * `observers` is a "set" of player names: `{name1 = true, name2 = true, ...}` + * A set is a table where the keys are the elements of the set + (in this case, *valid* player names) and the values are all `true`. * Attachments: The *effective observers* of an object are made up of all players who can observe the object *and* are also effective observers of its parent object (if there is one). diff --git a/src/main.cpp b/src/main.cpp index 7474ae84c5ec0..9f358bb66c632 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1095,13 +1095,9 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings & if (cmd_args.exists("terminal")) { #if USE_CURSES - bool name_ok = true; std::string admin_nick = g_settings->get("name"); - name_ok = name_ok && !admin_nick.empty(); - name_ok = name_ok && string_allowed(admin_nick, PLAYERNAME_ALLOWED_CHARS); - - if (!name_ok) { + if (!is_valid_player_name(admin_nick)) { if (admin_nick.empty()) { errorstream << "No name given for admin. " << "Please check your minetest.conf that it " @@ -1110,7 +1106,8 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings & } else { errorstream << "Name for admin '" << admin_nick << "' is not valid. " - << "Please check that it only contains allowed characters. " + << "Please check that it only contains allowed characters " + << "and that it is at most 20 characters long. " << "Valid characters are: " << PLAYERNAME_ALLOWED_CHARS_USER_EXPL << std::endl; } diff --git a/src/player.cpp b/src/player.cpp index e55de5937ba40..fd902aa83eaf5 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -30,6 +30,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "porting.h" // strlcpy +bool is_valid_player_name(std::string_view name) { + return !name.empty() && name.size() <= PLAYERNAME_SIZE && string_allowed(name, PLAYERNAME_ALLOWED_CHARS); +} + Player::Player(const std::string &name, IItemDefManager *idef): inventory(idef) { diff --git a/src/player.h b/src/player.h index 9991dd774edae..dd2be4986ade8 100644 --- a/src/player.h +++ b/src/player.h @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "constants.h" #include "network/networkprotocol.h" #include "util/basic_macros.h" +#include "util/string.h" #include #include #include @@ -35,6 +36,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_" #define PLAYERNAME_ALLOWED_CHARS_USER_EXPL "'a' to 'z', 'A' to 'Z', '0' to '9', '-', '_'" +bool is_valid_player_name(std::string_view name); + struct PlayerFovSpec { f32 fov; diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 89974fb0e6134..00c825ddc0573 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -859,12 +859,8 @@ int ObjectRef::l_set_observers(lua_State *L) lua_pushnil(L); while (lua_next(L, 2) != 0) { std::string name = readParam(L, -2); - if (name.empty()) - throw LuaError("Observer name is empty"); - if (name.size() > PLAYERNAME_SIZE) - throw LuaError("Observer name is too long"); - if (!string_allowed(name, PLAYERNAME_ALLOWED_CHARS)) - throw LuaError("Observer name contains invalid characters"); + if (!is_valid_player_name(name)) + throw LuaError("Observer name is not a valid player name"); if (!lua_toboolean(L, -1)) // falsy value? throw LuaError("Values in the `observers` table need to be true"); observer_names.insert(std::move(name)); diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index 883b9480cf629..fac3e54d15ddd 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -44,6 +44,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/sha1.h" #include "my_sha256.h" #include "util/png.h" +#include "player.h" #include // only available in zstd 1.3.5+ @@ -674,6 +675,16 @@ int ModApiUtil::l_urlencode(lua_State *L) return 1; } +// is_valid_player_name(name) +int ModApiUtil::l_is_valid_player_name(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + auto s = readParam(L, 1); + lua_pushboolean(L, is_valid_player_name(s)); + return 1; +} + void ModApiUtil::Initialize(lua_State *L, int top) { API_FCT(log); @@ -722,6 +733,7 @@ void ModApiUtil::Initialize(lua_State *L, int top) API_FCT(set_last_run_mod); API_FCT(urlencode); + API_FCT(is_valid_player_name); LuaSettings::create(L, g_settings, g_settings_path); lua_setfield(L, top, "settings"); diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h index 056e09090a42b..e0daf3e79cf99 100644 --- a/src/script/lua_api/l_util.h +++ b/src/script/lua_api/l_util.h @@ -134,6 +134,9 @@ class ModApiUtil : public ModApiBase // urlencode(value) static int l_urlencode(lua_State *L); + // is_valid_player_name(name) + static int l_is_valid_player_name(lua_State *L); + public: static void Initialize(lua_State *L, int top); static void InitializeAsync(lua_State *L, int top);