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
This commit is contained in:
rubenwardy 2022-06-05 16:47:38 +01:00 committed by GitHub
parent 21323ef1ff
commit 03d86ea0b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 232 additions and 402 deletions

@ -67,6 +67,12 @@ appgurueu:
erlehmann, Warr1024, rollerozxa: erlehmann, Warr1024, rollerozxa:
textures/base/pack/no_screenshot.png 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 License of Minetest source code
------------------------------- -------------------------------

@ -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

@ -17,6 +17,7 @@
mt_color_grey = "#AAAAAA" mt_color_grey = "#AAAAAA"
mt_color_blue = "#6389FF" mt_color_blue = "#6389FF"
mt_color_lightblue = "#99CCFF"
mt_color_green = "#72FF63" mt_color_green = "#72FF63"
mt_color_dark_green = "#25C191" mt_color_dark_green = "#25C191"
mt_color_orange = "#FF8800" 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_create_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_content.lua") dofile(menupath .. DIR_DELIM .. "dlg_delete_content.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua") dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_register.lua")
dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua") dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
local tabs = {} local tabs = {}

@ -87,27 +87,34 @@ local function get_formspec(tabview, name, tabdata)
"field[4.25,0.5;1.25,0.75;te_port;;" .. "field[4.25,0.5;1.25,0.75;te_port;;" ..
core.formspec_escape(core.settings:get("remote_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 -- Description Background
"label[0.25,2.75;" .. fgettext("Server Description") .. "]" .. "label[0.25,1.6;" .. fgettext("Server Description") .. "]" ..
"box[0.25,3;5.25,2.75;#999999]".. "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 -- 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 tabdata.selected then
if gamedata.fav then if gamedata.fav then
retval = retval .. "button[0.25,6;2.5,0.75;btn_delete_favorite;" .. retval = retval .. "tooltip[btn_delete_favorite;" .. fgettext("Remove favorite") .. "]"
fgettext("Del. 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 end
if gamedata.serverdescription then 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) .. "]" core.formspec_escape(gamedata.serverdescription) .. "]"
end end
end end
@ -339,12 +346,15 @@ local function main_button_handler(tabview, fields, name, tabdata)
return true return true
end 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 and fields.te_address ~= "" and fields.te_port then
gamedata.playername = fields.te_name gamedata.playername = fields.te_name
gamedata.password = fields.te_pwd gamedata.password = fields.te_pwd
gamedata.address = fields.te_address gamedata.address = fields.te_address
gamedata.port = tonumber(fields.te_port) 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 gamedata.selected_world = 0
local idx = core.get_table_index("servers") local idx = core.get_table_index("servers")
@ -381,6 +391,25 @@ local function main_button_handler(tabview, fields, name, tabdata)
return true return true
end 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 return false
end end

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

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

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

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

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

@ -64,7 +64,7 @@ void set_default_settings()
settings->setDefault("enable_client_modding", "false"); settings->setDefault("enable_client_modding", "false");
settings->setDefault("max_out_chat_queue_size", "20"); settings->setDefault("max_out_chat_queue_size", "20");
settings->setDefault("pause_on_lost_focus", "false"); 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"); settings->setDefault("chat_weblink_color", "#8888FF");
// Keymap // Keymap

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

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

@ -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;
};

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

@ -101,11 +101,20 @@ void Client::handleCommand_Hello(NetworkPacket* pkt)
// Authenticate using that method, or abort if there wasn't any method found // 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_NONE) {
if (chosen_auth_mechanism == AUTH_MECHANISM_FIRST_SRP && bool is_register = chosen_auth_mechanism == AUTH_MECHANISM_FIRST_SRP;
!m_simple_singleplayer_mode && ELoginRegister mode = is_register ? ELoginRegister::Register : ELoginRegister::Login;
!getServerAddress().isLocalhost() && if (m_allow_login_or_register != ELoginRegister::Any &&
g_settings->getBool("enable_register_confirmation")) { m_allow_login_or_register != mode) {
promptConfirmRegistration(chosen_auth_mechanism); 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 { } else {
startAuth(chosen_auth_mechanism); startAuth(chosen_auth_mechanism);
} }

@ -139,6 +139,14 @@ int ModApiMainMenu::l_start(lua_State *L)
data->password = getTextData(L,"password"); data->password = getTextData(L,"password");
data->address = getTextData(L,"address"); data->address = getTextData(L,"address");
data->port = getTextData(L,"port"); 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->serverdescription = getTextData(L,"serverdescription");
data->servername = getTextData(L,"servername"); data->servername = getTextData(L,"servername");

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 B