Browse Source

Add register dialog to separate login/register (#12185)

New users find Minetest's account system confusing.
This change moves username/password to a new dialog,
with login and register buttons added to the Join Game tab.

The old registration confirmation dialog is removed in
favour of the new dialog.

Fixes #8138
rubenwardy 1 year ago
parent
commit
03d86ea0b4

+ 6 - 0
LICENSE.txt

@@ -67,6 +67,12 @@ appgurueu:
 erlehmann, Warr1024, rollerozxa:
   textures/base/pack/no_screenshot.png
 
+kilbith:
+  textures/base/pack/server_favorite.png
+
+SmallJoker
+  textures/base/pack/server_favorite_delete.png (based on server_favorite.png)
+
 License of Minetest source code
 -------------------------------
 

+ 123 - 0
builtin/mainmenu/dlg_register.lua

@@ -0,0 +1,123 @@
+--Minetest
+--Copyright (C) 2022 rubenwardy
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+
+local function register_formspec(dialogdata)
+	local title = fgettext("Joining $1", dialogdata.server and dialogdata.server.name or dialogdata.address)
+	local buttons_y = 4 + 1.3
+	if dialogdata.error then
+		buttons_y = buttons_y + 0.8
+	end
+
+	local retval = {
+		"formspec_version[4]",
+		"size[8,", tostring(buttons_y + 1.175), "]",
+		"set_focus[", (dialogdata.name ~= "" and "password" or "name"), "]",
+		"label[0.375,0.8;", title, "]",
+		"field[0.375,1.575;7.25,0.8;name;", core.formspec_escape(fgettext("Name")), ";",
+				core.formspec_escape(dialogdata.name), "]",
+		"pwdfield[0.375,2.875;7.25,0.8;password;", core.formspec_escape(fgettext("Password")), "]",
+		"pwdfield[0.375,4.175;7.25,0.8;password_2;", core.formspec_escape(fgettext("Confirm Password")), "]"
+	}
+
+	if dialogdata.error then
+		table.insert_all(retval, {
+			"box[0.375,", tostring(buttons_y - 0.9), ";7.25,0.6;darkred]",
+			"label[0.625,", tostring(buttons_y - 0.6), ";", core.formspec_escape(dialogdata.error), "]",
+		})
+	end
+
+	table.insert_all(retval, {
+		"container[0.375,", tostring(buttons_y), "]",
+		"button[0,0;2.5,0.8;dlg_register_confirm;", fgettext("Register"), "]",
+		"button[4.75,0;2.5,0.8;dlg_register_cancel;", fgettext("Cancel"), "]",
+		"container_end[]",
+	})
+
+	return table.concat(retval, "")
+end
+
+--------------------------------------------------------------------------------
+local function register_buttonhandler(this, fields)
+	this.data.name = fields.name
+	this.data.error = nil
+
+	if fields.dlg_register_confirm or fields.key_enter then
+		if fields.name == "" then
+			this.data.error = fgettext("Missing name")
+			return true
+		end
+		if fields.password ~= fields.password_2 then
+			this.data.error = fgettext("Passwords do not match")
+			return true
+		end
+
+		gamedata.playername = fields.name
+		gamedata.password   = fields.password
+		gamedata.address    = this.data.address
+		gamedata.port       = this.data.port
+		gamedata.allow_login_or_register = "register"
+		gamedata.selected_world = 0
+
+		assert(gamedata.address and gamedata.port)
+
+		local server = this.data.server
+		if server then
+			serverlistmgr.add_favorite(server)
+			gamedata.servername        = server.name
+			gamedata.serverdescription = server.description
+		else
+			gamedata.servername        = ""
+			gamedata.serverdescription = ""
+
+			serverlistmgr.add_favorite({
+				address = gamedata.address,
+				port = gamedata.port,
+			})
+		end
+
+		core.settings:set("name", fields.name)
+		core.settings:set("address",     gamedata.address)
+		core.settings:set("remote_port", gamedata.port)
+
+		core.start()
+	end
+
+	if fields["dlg_register_cancel"] then
+		this:delete()
+		return true
+	end
+
+	return false
+end
+
+--------------------------------------------------------------------------------
+function create_register_dialog(address, port, server)
+	assert(address)
+	assert(type(port) == "number")
+
+	local retval = dialog_create("dlg_register",
+			register_formspec,
+			register_buttonhandler,
+			nil)
+	retval.data.address = address
+	retval.data.port = port
+	retval.data.server = server
+	retval.data.name = core.settings:get("name") or ""
+	return retval
+end

+ 2 - 0
builtin/mainmenu/init.lua

@@ -17,6 +17,7 @@
 
 mt_color_grey  = "#AAAAAA"
 mt_color_blue  = "#6389FF"
+mt_color_lightblue  = "#99CCFF"
 mt_color_green = "#72FF63"
 mt_color_dark_green = "#25C191"
 mt_color_orange  = "#FF8800"
@@ -43,6 +44,7 @@ dofile(menupath .. DIR_DELIM .. "dlg_contentstore.lua")
 dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua")
 dofile(menupath .. DIR_DELIM .. "dlg_delete_content.lua")
 dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua")
+dofile(menupath .. DIR_DELIM .. "dlg_register.lua")
 dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
 
 local tabs = {}

+ 43 - 14
builtin/mainmenu/tab_online.lua

@@ -87,27 +87,34 @@ local function get_formspec(tabview, name, tabdata)
 		"field[4.25,0.5;1.25,0.75;te_port;;" ..
 			core.formspec_escape(core.settings:get("remote_port")) .. "]" ..
 
-		-- Name / Password
-		"label[0.25,1.55;" .. fgettext("Name") .. "]" ..
-		"label[3,1.55;" .. fgettext("Password") .. "]" ..
-		"field[0.25,1.75;2.75,0.75;te_name;;" ..
-			core.formspec_escape(core.settings:get("name")) .. "]" ..
-		"pwdfield[3,1.75;2.5,0.75;te_pwd;]" ..
-
 		-- Description Background
-		"label[0.25,2.75;" .. fgettext("Server Description") .. "]" ..
-		"box[0.25,3;5.25,2.75;#999999]"..
+		"label[0.25,1.6;" .. fgettext("Server Description") .. "]" ..
+		"box[0.25,1.85;5.25,2.7;#999999]"..
+
+		-- Name / Password
+		"container[0,4.8]" ..
+		"label[0.25,0;" .. fgettext("Name") .. "]" ..
+		"label[3,0;" .. fgettext("Password") .. "]" ..
+		"field[0.25,0.2;2.625,0.75;te_name;;" .. core.formspec_escape(core.settings:get("name")) .. "]" ..
+		"pwdfield[2.875,0.2;2.625,0.75;te_pwd;]" ..
+		"container_end[]" ..
 
 		-- Connect
-		"button[3,6;2.5,0.75;btn_mp_connect;" .. fgettext("Connect") .. "]"
+		"button[3,6;2.5,0.75;btn_mp_login;" .. fgettext("Login") .. "]"
+
+	if core.settings:get_bool("enable_split_login_register") then
+		retval = retval .. "button[0.25,6;2.5,0.75;btn_mp_register;" .. fgettext("Register") .. "]"
+	end
 
 	if tabdata.selected then
 		if gamedata.fav then
-			retval = retval .. "button[0.25,6;2.5,0.75;btn_delete_favorite;" ..
-				fgettext("Del. Favorite") .. "]"
+			retval = retval .. "tooltip[btn_delete_favorite;" .. fgettext("Remove favorite") .. "]"
+			retval = retval .. "style[btn_delete_favorite;padding=6]"
+			retval = retval .. "image_button[5,1.3;0.5,0.5;" .. defaulttexturedir ..
+				"server_favorite_delete.png;btn_delete_favorite;]"
 		end
 		if gamedata.serverdescription then
-			retval = retval .. "textarea[0.25,3;5.25,2.75;;;" ..
+			retval = retval .. "textarea[0.25,1.85;5.2,2.75;;;" ..
 				core.formspec_escape(gamedata.serverdescription) .. "]"
 		end
 	end
@@ -339,12 +346,15 @@ local function main_button_handler(tabview, fields, name, tabdata)
 		return true
 	end
 
-	if (fields.btn_mp_connect or fields.key_enter)
+	if (fields.btn_mp_login or fields.key_enter)
 			and fields.te_address ~= "" and fields.te_port then
 		gamedata.playername = fields.te_name
 		gamedata.password   = fields.te_pwd
 		gamedata.address    = fields.te_address
 		gamedata.port       = tonumber(fields.te_port)
+
+		local enable_split_login_register = core.settings:get_bool("enable_split_login_register")
+		gamedata.allow_login_or_register = enable_split_login_register and "login" or "any"
 		gamedata.selected_world = 0
 
 		local idx = core.get_table_index("servers")
@@ -381,6 +391,25 @@ local function main_button_handler(tabview, fields, name, tabdata)
 		return true
 	end
 
+	if fields.btn_mp_register and fields.te_address ~= "" and fields.te_port then
+		local idx = core.get_table_index("servers")
+		local server = idx and tabdata.lookup[idx]
+		if server and (server.address ~= fields.te_address or server.port ~= tonumber(fields.te_port)) then
+			server = nil
+		end
+
+		if server and not is_server_protocol_compat_or_error(
+					server.proto_min, server.proto_max) then
+			return true
+		end
+
+		local dlg = create_register_dialog(fields.te_address, tonumber(fields.te_port), server)
+		dlg:set_parent(tabview)
+		tabview:hide()
+		dlg:show()
+		return true
+	end
+
 	return false
 end
 

+ 3 - 3
builtin/settingtypes.txt

@@ -1033,9 +1033,9 @@ serverlist_file (Serverlist file) string favoriteservers.json
 #    0 to disable queueing and -1 to make the queue size unlimited.
 max_out_chat_queue_size (Maximum size of the out chat queue) int 20
 
-#    Enable register confirmation when connecting to server.
-#    If disabled, new account will be registered automatically.
-enable_register_confirmation (Enable register confirmation) bool true
+#    If enabled, account registration is separate from login in the UI.
+#    If disabled, new accounts will be registered automatically when logging in.
+enable_split_login_register (Enable split login/register) bool true
 
 [*Advanced]
 

+ 4 - 18
src/client/client.cpp

@@ -100,7 +100,8 @@ Client::Client(
 		MtEventManager *event,
 		RenderingEngine *rendering_engine,
 		bool ipv6,
-		GameUI *game_ui
+		GameUI *game_ui,
+		ELoginRegister allow_login_or_register
 ):
 	m_tsrc(tsrc),
 	m_shsrc(shsrc),
@@ -124,7 +125,8 @@ Client::Client(
 	m_media_downloader(new ClientMediaDownloader()),
 	m_state(LC_Created),
 	m_game_ui(game_ui),
-	m_modchannel_mgr(new ModChannelMgr())
+	m_modchannel_mgr(new ModChannelMgr()),
+	m_allow_login_or_register(allow_login_or_register)
 {
 	// Add local player
 	m_env.setLocalPlayer(new LocalPlayer(this, playername));
@@ -396,10 +398,6 @@ void Client::step(float dtime)
 		initial_step = false;
 	}
 	else if(m_state == LC_Created) {
-		if (m_is_registration_confirmation_state) {
-			// Waiting confirmation
-			return;
-		}
 		float &counter = m_connection_reinit_timer;
 		counter -= dtime;
 		if(counter <= 0.0) {
@@ -1078,18 +1076,6 @@ void Client::sendInit(const std::string &playerName)
 	Send(&pkt);
 }
 
-void Client::promptConfirmRegistration(AuthMechanism chosen_auth_mechanism)
-{
-	m_chosen_auth_mech = chosen_auth_mechanism;
-	m_is_registration_confirmation_state = true;
-}
-
-void Client::confirmRegistration()
-{
-	m_is_registration_confirmation_state = false;
-	startAuth(m_chosen_auth_mech);
-}
-
 void Client::startAuth(AuthMechanism chosen_auth_mechanism)
 {
 	m_chosen_auth_mech = chosen_auth_mechanism;

+ 4 - 4
src/client/client.h

@@ -37,6 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mesh_generator_thread.h"
 #include "network/address.h"
 #include "network/peerhandler.h"
+#include "gameparams.h"
 #include <fstream>
 
 #define CLIENT_CHAT_MESSAGE_LIMIT_PER_10S 10.0f
@@ -127,7 +128,8 @@ public:
 			MtEventManager *event,
 			RenderingEngine *rendering_engine,
 			bool ipv6,
-			GameUI *game_ui
+			GameUI *game_ui,
+			ELoginRegister allow_login_or_register
 	);
 
 	~Client();
@@ -347,8 +349,7 @@ public:
 	u16 getProtoVersion()
 	{ return m_proto_ver; }
 
-	void confirmRegistration();
-	bool m_is_registration_confirmation_state = false;
+	ELoginRegister m_allow_login_or_register = ELoginRegister::Any;
 	bool m_simple_singleplayer_mode;
 
 	float mediaReceiveProgress();
@@ -460,7 +461,6 @@ private:
 	static AuthMechanism choseAuthMech(const u32 mechs);
 
 	void sendInit(const std::string &playerName);
-	void promptConfirmRegistration(AuthMechanism chosen_auth_mechanism);
 	void startAuth(AuthMechanism chosen_auth_mechanism);
 	void sendDeletedBlocks(std::vector<v3s16> &blocks);
 	void sendGotBlocks(const std::vector<v3s16> &blocks);

+ 1 - 0
src/client/clientlauncher.cpp

@@ -451,6 +451,7 @@ bool ClientLauncher::launch_game(std::string &error_message,
 		start_data.name = menudata.name;
 		start_data.password = menudata.password;
 		start_data.address = std::move(menudata.address);
+		start_data.allow_login_or_register = menudata.allow_login_or_register;
 		server_name = menudata.servername;
 		server_description = menudata.serverdescription;
 

+ 11 - 23
src/client/game.cpp

@@ -43,7 +43,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "gameparams.h"
 #include "gettext.h"
 #include "gui/guiChatConsole.h"
-#include "gui/guiConfirmRegistration.h"
 #include "gui/guiFormSpecMenu.h"
 #include "gui/guiKeyChangeMenu.h"
 #include "gui/guiPasswordChange.h"
@@ -1480,7 +1479,8 @@ bool Game::connectToServer(const GameStartData &start_data,
 				start_data.password, start_data.address,
 				*draw_control, texture_src, shader_src,
 				itemdef_manager, nodedef_manager, sound, eventmgr,
-				m_rendering_engine, connect_address.isIPv6(), m_game_ui.get());
+				m_rendering_engine, connect_address.isIPv6(), m_game_ui.get(),
+				start_data.allow_login_or_register);
 		client->migrateModStorage();
 	} catch (const BaseException &e) {
 		*error_message = fmtgettext("Error creating client: %s", e.what());
@@ -1543,28 +1543,16 @@ bool Game::connectToServer(const GameStartData &start_data,
 				break;
 			}
 
-			if (client->m_is_registration_confirmation_state) {
-				if (registration_confirmation_shown) {
-					// Keep drawing the GUI
-					m_rendering_engine->draw_menu_scene(guienv, dtime, true);
-				} else {
-					registration_confirmation_shown = true;
-					(new GUIConfirmRegistration(guienv, guienv->getRootGUIElement(), -1,
-						   &g_menumgr, client, start_data.name, start_data.password,
-						   connection_aborted, texture_src))->drop();
-				}
-			} else {
-				wait_time += dtime;
-				// Only time out if we aren't waiting for the server we started
-				if (!start_data.address.empty() && wait_time > 10) {
-					*error_message = gettext("Connection timed out.");
-					errorstream << *error_message << std::endl;
-					break;
-				}
-
-				// Update status
-				showOverlayMessage(N_("Connecting to server..."), dtime, 20);
+			wait_time += dtime;
+			// Only time out if we aren't waiting for the server we started
+			if (!start_data.address.empty() && wait_time > 10) {
+				*error_message = gettext("Connection timed out.");
+				errorstream << *error_message << std::endl;
+				break;
 			}
+
+			// Update status
+			showOverlayMessage(N_("Connecting to server..."), dtime, 20);
 		}
 	} catch (con::PeerNotFoundException &e) {
 		// TODO: Should something be done here? At least an info/error

+ 1 - 1
src/defaultsettings.cpp

@@ -64,7 +64,7 @@ void set_default_settings()
 	settings->setDefault("enable_client_modding", "false");
 	settings->setDefault("max_out_chat_queue_size", "20");
 	settings->setDefault("pause_on_lost_focus", "false");
-	settings->setDefault("enable_register_confirmation", "true");
+	settings->setDefault("enable_split_login_register", "true");
 	settings->setDefault("chat_weblink_color", "#8888FF");
 
 	// Keymap

+ 9 - 2
src/gameparams.h

@@ -20,8 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #pragma once
 
 #include "irrlichttypes.h"
-
-struct SubgameSpec;
+#include "content/subgames.h"
 
 // Information provided from "main"
 struct GameParams
@@ -34,6 +33,12 @@ struct GameParams
 	bool is_dedicated_server;
 };
 
+enum class ELoginRegister {
+	Any = 0,
+	Login,
+	Register
+};
+
 // Information processed by main menu
 struct GameStartData : GameParams
 {
@@ -46,6 +51,8 @@ struct GameStartData : GameParams
 	std::string address;
 	bool local_server;
 
+	ELoginRegister allow_login_or_register = ELoginRegister::Any;
+
 	// "world_path" must be kept in sync!
 	WorldSpec world_spec;
 };

+ 0 - 1
src/gui/CMakeLists.txt

@@ -11,7 +11,6 @@ set(gui_SRCS
 	${CMAKE_CURRENT_SOURCE_DIR}/guiButtonImage.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/guiButtonItemImage.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/guiChatConsole.cpp
-	${CMAKE_CURRENT_SOURCE_DIR}/guiConfirmRegistration.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/guiEditBox.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/guiEditBoxWithScrollbar.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/guiEngine.cpp

+ 0 - 266
src/gui/guiConfirmRegistration.cpp

@@ -1,266 +0,0 @@
-/*
-Minetest
-Copyright (C) 2018 srifqi, Muhammad Rifqi Priyo Susanto
-		<muhammadrifqipriyosusanto@gmail.com>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with this program; if not, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-
-#include "guiConfirmRegistration.h"
-#include "client/client.h"
-#include "guiButton.h"
-#include <IGUICheckBox.h>
-#include <IGUIButton.h>
-#include <IGUIStaticText.h>
-#include <IGUIFont.h>
-#include "guiEditBoxWithScrollbar.h"
-#include "porting.h"
-
-#ifdef HAVE_TOUCHSCREENGUI
-	#include "client/renderingengine.h"
-#endif
-
-#include "gettext.h"
-
-// Continuing from guiPasswordChange.cpp
-const int ID_confirmPassword = 262;
-const int ID_confirm = 263;
-const int ID_intotext = 264;
-const int ID_cancel = 265;
-const int ID_message = 266;
-
-GUIConfirmRegistration::GUIConfirmRegistration(gui::IGUIEnvironment *env,
-		gui::IGUIElement *parent, s32 id, IMenuManager *menumgr, Client *client,
-		const std::string &playername, const std::string &password,
-		bool *aborted, ISimpleTextureSource *tsrc) :
-		GUIModalMenu(env, parent, id, menumgr),
-		m_client(client), m_playername(playername), m_password(password),
-		m_aborted(aborted), m_tsrc(tsrc)
-{
-#ifdef HAVE_TOUCHSCREENGUI
-	m_touchscreen_visible = false;
-#endif
-}
-
-void GUIConfirmRegistration::regenerateGui(v2u32 screensize)
-{
-	acceptInput();
-	removeAllChildren();
-
-	/*
-		Calculate new sizes and positions
-	*/
-#ifdef HAVE_TOUCHSCREENGUI
-	const float s = m_gui_scale * RenderingEngine::getDisplayDensity() / 2;
-#else
-	const float s = m_gui_scale;
-#endif
-	DesiredRect = core::rect<s32>(
-		screensize.X / 2 - 600 * s / 2,
-		screensize.Y / 2 - 360 * s / 2,
-		screensize.X / 2 + 600 * s / 2,
-		screensize.Y / 2 + 360 * s / 2
-	);
-	recalculateAbsolutePosition(false);
-
-	v2s32 size = DesiredRect.getSize();
-	v2s32 topleft_client(0, 0);
-
-	const wchar_t *text;
-
-	/*
-		Add stuff
-	*/
-	s32 ypos = 30 * s;
-	{
-		core::rect<s32> rect2(0, 0, 540 * s, 180 * s);
-		rect2 += topleft_client + v2s32(30 * s, ypos);
-		static const std::string info_text_template = strgettext(
-				"You are about to join this server with the name \"%s\" for the "
-				"first time.\n"
-				"If you proceed, a new account using your credentials will be "
-				"created on this server.\n"
-				"Please retype your password and click 'Register and Join' to "
-				"confirm account creation, or click 'Cancel' to abort.");
-		char info_text_buf[1024];
-		porting::mt_snprintf(info_text_buf, sizeof(info_text_buf),
-				info_text_template.c_str(), m_playername.c_str());
-
-		std::wstring info_text_w = utf8_to_wide(info_text_buf);
-		gui::IGUIEditBox *e = new GUIEditBoxWithScrollBar(info_text_w.c_str(),
-				true, Environment, this, ID_intotext, rect2, false, true);
-		e->drop();
-		e->setMultiLine(true);
-		e->setWordWrap(true);
-		e->setTextAlignment(gui::EGUIA_UPPERLEFT, gui::EGUIA_CENTER);
-	}
-
-	ypos += 200 * s;
-	{
-		core::rect<s32> rect2(0, 0, 540 * s, 30 * s);
-		rect2 += topleft_client + v2s32(30 * s, ypos);
-		gui::IGUIEditBox *e = Environment->addEditBox(m_pass_confirm.c_str(),
-				rect2, true, this, ID_confirmPassword);
-		e->setPasswordBox(true);
-		Environment->setFocus(e);
-	}
-
-	ypos += 50 * s;
-	{
-		core::rect<s32> rect2(0, 0, 230 * s, 35 * s);
-		rect2 = rect2 + v2s32(size.X / 2 - 220 * s, ypos);
-		text = wgettext("Register and Join");
-		GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_confirm, text);
-		delete[] text;
-	}
-	{
-		core::rect<s32> rect2(0, 0, 120 * s, 35 * s);
-		rect2 = rect2 + v2s32(size.X / 2 + 70 * s, ypos);
-		text = wgettext("Cancel");
-		GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_cancel, text);
-		delete[] text;
-	}
-	{
-		core::rect<s32> rect2(0, 0, 500 * s, 40 * s);
-		rect2 += topleft_client + v2s32(30 * s, ypos + 40 * s);
-		text = wgettext("Passwords do not match!");
-		IGUIElement *e = Environment->addStaticText(
-				text, rect2, false, true, this, ID_message);
-		e->setVisible(false);
-		delete[] text;
-	}
-}
-
-void GUIConfirmRegistration::drawMenu()
-{
-	gui::IGUISkin *skin = Environment->getSkin();
-	if (!skin)
-		return;
-	video::IVideoDriver *driver = Environment->getVideoDriver();
-
-	video::SColor bgcolor(140, 0, 0, 0);
-	driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
-
-	gui::IGUIElement::draw();
-#ifdef __ANDROID__
-	getAndroidUIInput();
-#endif
-}
-
-void GUIConfirmRegistration::closeMenu(bool goNext)
-{
-	if (goNext) {
-		m_client->confirmRegistration();
-	} else {
-		*m_aborted = true;
-		infostream << "Connect aborted [Escape]" << std::endl;
-	}
-	quitMenu();
-}
-
-void GUIConfirmRegistration::acceptInput()
-{
-	gui::IGUIElement *e;
-	e = getElementFromId(ID_confirmPassword);
-	if (e)
-		m_pass_confirm = e->getText();
-}
-
-bool GUIConfirmRegistration::processInput()
-{
-	if (utf8_to_wide(m_password) != m_pass_confirm) {
-		gui::IGUIElement *e = getElementFromId(ID_message);
-		if (e)
-			e->setVisible(true);
-		return false;
-	}
-	return true;
-}
-
-bool GUIConfirmRegistration::OnEvent(const SEvent &event)
-{
-	if (event.EventType == EET_KEY_INPUT_EVENT) {
-		// clang-format off
-		if ((event.KeyInput.Key == KEY_ESCAPE ||
-				event.KeyInput.Key == KEY_CANCEL) &&
-				event.KeyInput.PressedDown) {
-			closeMenu(false);
-			return true;
-		}
-		// clang-format on
-		if (event.KeyInput.Key == KEY_RETURN && event.KeyInput.PressedDown) {
-			acceptInput();
-			if (processInput())
-				closeMenu(true);
-			return true;
-		}
-	}
-
-	if (event.EventType != EET_GUI_EVENT)
-		return Parent ? Parent->OnEvent(event) : false;
-
-	if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST && isVisible()) {
-		if (!canTakeFocus(event.GUIEvent.Element)) {
-			infostream << "GUIConfirmRegistration: Not allowing focus change."
-				<< std::endl;
-			// Returning true disables focus change
-			return true;
-		}
-	} else if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED) {
-		switch (event.GUIEvent.Caller->getID()) {
-		case ID_confirm:
-			acceptInput();
-			if (processInput())
-				closeMenu(true);
-			return true;
-		case ID_cancel:
-			closeMenu(false);
-			return true;
-		}
-	} else if (event.GUIEvent.EventType == gui::EGET_EDITBOX_ENTER) {
-		switch (event.GUIEvent.Caller->getID()) {
-		case ID_confirmPassword:
-			acceptInput();
-			if (processInput())
-				closeMenu(true);
-			return true;
-		}
-	}
-
-	return false;
-}
-
-#ifdef __ANDROID__
-bool GUIConfirmRegistration::getAndroidUIInput()
-{
-	if (!hasAndroidUIInput() || m_jni_field_name != "password")
-		return false;
-
-	// still waiting
-	if (porting::getInputDialogState() == -1)
-		return true;
-
-	m_jni_field_name.clear();
-
-	gui::IGUIElement *e = getElementFromId(ID_confirmPassword);
-
-	if (!e || e->getType() != irr::gui::EGUIET_EDIT_BOX)
-		return false;
-
-	std::string text = porting::getInputDialogValue();
-	e->setText(utf8_to_wide(text).c_str());
-	return false;
-}
-#endif

+ 0 - 65
src/gui/guiConfirmRegistration.h

@@ -1,65 +0,0 @@
-/*
-Minetest
-Copyright (C) 2018 srifqi, Muhammad Rifqi Priyo Susanto
-		<muhammadrifqipriyosusanto@gmail.com>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with this program; if not, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-
-#pragma once
-
-#include "irrlichttypes_extrabloated.h"
-#include "modalMenu.h"
-#include <string>
-
-class Client;
-class ISimpleTextureSource;
-
-class GUIConfirmRegistration : public GUIModalMenu
-{
-public:
-	GUIConfirmRegistration(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
-			s32 id, IMenuManager *menumgr, Client *client,
-			const std::string &playername, const std::string &password,
-			bool *aborted, ISimpleTextureSource *tsrc);
-	/*
-		Remove and re-add (or reposition) stuff
-	*/
-	void regenerateGui(v2u32 screensize);
-
-	void drawMenu();
-
-	void closeMenu(bool goNext);
-
-	void acceptInput();
-
-	bool processInput();
-
-	bool OnEvent(const SEvent &event);
-#ifdef __ANDROID__
-	bool getAndroidUIInput();
-#endif
-
-private:
-	std::wstring getLabelByID(s32 id) { return L""; }
-	std::string getNameByID(s32 id) { return "password"; }
-
-	Client *m_client = nullptr;
-	const std::string &m_playername;
-	const std::string &m_password;
-	bool *m_aborted = nullptr;
-	std::wstring m_pass_confirm = L"";
-	ISimpleTextureSource *m_tsrc;
-};

+ 3 - 0
src/gui/guiMainMenu.h

@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #pragma once
 
 #include "irrlichttypes_extrabloated.h"
+#include "gameparams.h"
 #include <string>
 #include <list>
 
@@ -50,5 +51,7 @@ struct MainMenuData {
 	// Data to be passed to the script
 	MainMenuDataForScript script_data;
 
+	ELoginRegister allow_login_or_register = ELoginRegister::Any;
+
 	MainMenuData() = default;
 };

+ 14 - 5
src/network/clientpackethandler.cpp

@@ -101,11 +101,20 @@ void Client::handleCommand_Hello(NetworkPacket* pkt)
 
 	// Authenticate using that method, or abort if there wasn't any method found
 	if (chosen_auth_mechanism != AUTH_MECHANISM_NONE) {
-		if (chosen_auth_mechanism == AUTH_MECHANISM_FIRST_SRP &&
-				!m_simple_singleplayer_mode &&
-				!getServerAddress().isLocalhost() &&
-				g_settings->getBool("enable_register_confirmation")) {
-			promptConfirmRegistration(chosen_auth_mechanism);
+		bool is_register = chosen_auth_mechanism == AUTH_MECHANISM_FIRST_SRP;
+		ELoginRegister mode = is_register ? ELoginRegister::Register : ELoginRegister::Login;
+		if (m_allow_login_or_register != ELoginRegister::Any &&
+				m_allow_login_or_register != mode) {
+			m_chosen_auth_mech = AUTH_MECHANISM_NONE;
+			m_access_denied = true;
+			if (m_allow_login_or_register == ELoginRegister::Login) {
+				m_access_denied_reason =
+						gettext("Name is not registered. To create an account on this server, click 'Register'");
+			} else {
+				m_access_denied_reason =
+						gettext("Name is taken. Please choose another name");
+			}
+			m_con->Disconnect();
 		} else {
 			startAuth(chosen_auth_mechanism);
 		}

+ 8 - 0
src/script/lua_api/l_mainmenu.cpp

@@ -139,6 +139,14 @@ int ModApiMainMenu::l_start(lua_State *L)
 		data->password = getTextData(L,"password");
 		data->address  = getTextData(L,"address");
 		data->port     = getTextData(L,"port");
+
+		const auto val = getTextData(L, "allow_login_or_register");
+		if (val == "login")
+			data->allow_login_or_register = ELoginRegister::Login;
+		else if (val == "register")
+			data->allow_login_or_register = ELoginRegister::Register;
+		else
+			data->allow_login_or_register = ELoginRegister::Any;
 	}
 	data->serverdescription = getTextData(L,"serverdescription");
 	data->servername        = getTextData(L,"servername");

BIN
textures/base/pack/server_favorite_delete.png