Skip to content

Commit 3b50b27

Browse files
committedJul 23, 2015
Optional reconnect functionality
Enable the server to request the client to reconnect. This can be done with the now extended minetest.request_shutdown([reason], [reconnect]) setting.
1 parent 1e0e85f commit 3b50b27

25 files changed

+233
-110
lines changed
 

Diff for: ‎builtin/fstk/ui.lua

+39-26
Original file line numberDiff line numberDiff line change
@@ -54,29 +54,42 @@ end
5454
--------------------------------------------------------------------------------
5555
--------------------------------------------------------------------------------
5656

57+
local function wordwrap_quickhack(str)
58+
local res = ""
59+
local ar = str:split("\n")
60+
for i = 1, #ar do
61+
local text = ar[i]
62+
-- Hack to add word wrapping.
63+
-- TODO: Add engine support for wrapping in formspecs
64+
while #text > 80 do
65+
if res ~= "" then
66+
res = res .. ","
67+
end
68+
res = res .. core.formspec_escape(string.sub(text, 1, 79))
69+
text = string.sub(text, 80, #text)
70+
end
71+
if res ~= "" then
72+
res = res .. ","
73+
end
74+
res = res .. core.formspec_escape(text)
75+
end
76+
return res
77+
end
78+
5779
--------------------------------------------------------------------------------
5880
function ui.update()
5981
local formspec = ""
6082

6183
-- handle errors
62-
if gamedata ~= nil and gamedata.errormessage ~= nil then
63-
local ar = gamedata.errormessage:split("\n")
64-
for i = 1, #ar do
65-
local text = ar[i]
66-
-- Hack to add word wrapping.
67-
-- TODO: Add engine support for wrapping in formspecs
68-
while #text > 80 do
69-
if formspec ~= "" then
70-
formspec = formspec .. ","
71-
end
72-
formspec = formspec .. core.formspec_escape(string.sub(text, 1, 79))
73-
text = string.sub(text, 80, #text)
74-
end
75-
if formspec ~= "" then
76-
formspec = formspec .. ","
77-
end
78-
formspec = formspec .. core.formspec_escape(text)
79-
end
84+
if gamedata ~= nil and gamedata.reconnect_requested then
85+
formspec = wordwrap_quickhack(gamedata.errormessage or "")
86+
formspec = "size[12,5]" ..
87+
"label[0.5,0;" .. fgettext("The server has requested a reconnect:") ..
88+
"]textlist[0.2,0.8;11.5,3.5;;" .. formspec ..
89+
"]button[6,4.6;3,0.5;btn_reconnect_no;" .. fgettext("Main menu") .. "]" ..
90+
"button[3,4.6;3,0.5;btn_reconnect_yes;" .. fgettext("Reconnect") .. "]"
91+
elseif gamedata ~= nil and gamedata.errormessage ~= nil then
92+
formspec = wordwrap_quickhack(gamedata.errormessage)
8093
local error_title
8194
if string.find(gamedata.errormessage, "ModError") then
8295
error_title = fgettext("An error occured in a Lua script, such as a mod:")
@@ -128,13 +141,6 @@ end
128141

129142
--------------------------------------------------------------------------------
130143
function ui.handle_buttons(fields)
131-
132-
if fields["btn_error_confirm"] then
133-
gamedata.errormessage = nil
134-
update_menu()
135-
return
136-
end
137-
138144
for key,value in pairs(ui.childlist) do
139145

140146
local retval = value:handle_buttons(fields)
@@ -168,8 +174,15 @@ end
168174
--------------------------------------------------------------------------------
169175
--------------------------------------------------------------------------------
170176
core.button_handler = function(fields)
171-
if fields["btn_error_confirm"] then
177+
if fields["btn_reconnect_yes"] then
178+
gamedata.reconnect_requested = false
179+
gamedata.errormessage = nil
180+
gamedata.do_reconnect = true
181+
core.start()
182+
return
183+
elseif fields["btn_reconnect_no"] or fields["btn_error_confirm"] then
172184
gamedata.errormessage = nil
185+
gamedata.reconnect_requested = false
173186
ui.update()
174187
return
175188
end

Diff for: ‎doc/lua_api.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -2174,7 +2174,8 @@ These functions return the leftover itemstack.
21742174
* Optional: Variable number of arguments that are passed to `func`
21752175

21762176
### Server
2177-
* `minetest.request_shutdown()`: request for server shutdown
2177+
* `minetest.request_shutdown([message],[reconnect])`: request for server shutdown. Will display `message` to clients,
2178+
and `reconnect` == true displays a reconnect button.
21782179
* `minetest.get_server_status()`: returns server status string
21792180

21802181
### Bans

Diff for: ‎minetest.conf.example

+3
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,9 @@
393393
# A message to be displayed to all clients when the server shuts down
394394
#kick_msg_crash = This server has experienced an internal error. You will now be disconnected.
395395
# A message to be displayed to all clients when the server crashes
396+
#ask_reconnect_on_crash = false
397+
# Whether to ask clients to reconnect after a (lua) crash.
398+
# Set this to true if your server is set up to restart automatically.
396399

397400
# Mod profiler
398401
#mod_profiling = false

Diff for: ‎src/client.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ Client::Client(
244244
m_chosen_auth_mech(AUTH_MECHANISM_NONE),
245245
m_auth_data(NULL),
246246
m_access_denied(false),
247+
m_access_denied_reconnect(false),
247248
m_itemdef_received(false),
248249
m_nodedef_received(false),
249250
m_media_downloader(new ClientMediaDownloader()),

Diff for: ‎src/client.h

+3
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,8 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
489489
bool accessDenied()
490490
{ return m_access_denied; }
491491

492+
bool reconnectRequested() { return m_access_denied_reconnect; }
493+
492494
std::string accessDeniedReason()
493495
{ return m_access_denied_reason; }
494496

@@ -636,6 +638,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
636638

637639

638640
bool m_access_denied;
641+
bool m_access_denied_reconnect;
639642
std::string m_access_denied_reason;
640643
std::queue<ClientEvent> m_client_event_queue;
641644
bool m_itemdef_received;

Diff for: ‎src/client/clientlauncher.cpp

+15-9
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,9 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
168168
ChatBackend chat_backend;
169169

170170
// If an error occurs, this is set to something by menu().
171-
// It is then displayed before the menu shows on the next call to menu()
171+
// It is then displayed before the menu shows on the next call to menu()
172172
std::string error_message;
173+
bool reconnect_requested = false;
173174

174175
bool first_loop = true;
175176

@@ -197,7 +198,8 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
197198
*/
198199
guiroot = guienv->addStaticText(L"", core::rect<s32>(0, 0, 10000, 10000));
199200

200-
bool game_has_run = launch_game(error_message, game_params, cmd_args);
201+
bool game_has_run = launch_game(error_message, reconnect_requested,
202+
game_params, cmd_args);
201203

202204
// If skip_main_menu, we only want to startup once
203205
if (skip_main_menu && !first_loop)
@@ -233,6 +235,7 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
233235
receiver->m_touchscreengui = new TouchScreenGUI(device, receiver);
234236
g_touchscreengui = receiver->m_touchscreengui;
235237
#endif
238+
236239
the_game(
237240
kill,
238241
random_input,
@@ -245,6 +248,7 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
245248
current_port,
246249
error_message,
247250
chat_backend,
251+
&reconnect_requested,
248252
gamespec,
249253
simple_singleplayer_mode
250254
);
@@ -325,14 +329,16 @@ bool ClientLauncher::init_engine(int log_level)
325329
}
326330

327331
bool ClientLauncher::launch_game(std::string &error_message,
328-
GameParams &game_params, const Settings &cmd_args)
332+
bool reconnect_requested, GameParams &game_params,
333+
const Settings &cmd_args)
329334
{
330335
// Initialize menu data
331336
MainMenuData menudata;
332-
menudata.address = address;
333-
menudata.name = playername;
334-
menudata.port = itos(game_params.socket_port);
335-
menudata.errormessage = error_message;
337+
menudata.address = address;
338+
menudata.name = playername;
339+
menudata.port = itos(game_params.socket_port);
340+
menudata.script_data.errormessage = error_message;
341+
menudata.script_data.reconnect_requested = reconnect_requested;
336342

337343
error_message.clear();
338344

@@ -379,11 +385,11 @@ bool ClientLauncher::launch_game(std::string &error_message,
379385
}
380386
}
381387

382-
if (!menudata.errormessage.empty()) {
388+
if (!menudata.script_data.errormessage.empty()) {
383389
/* The calling function will pass this back into this function upon the
384390
* next iteration (if any) causing it to be displayed by the GUI
385391
*/
386-
error_message = menudata.errormessage;
392+
error_message = menudata.script_data.errormessage;
387393
return false;
388394
}
389395

Diff for: ‎src/client/clientlauncher.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ class ClientLauncher
9292
void init_args(GameParams &game_params, const Settings &cmd_args);
9393
bool init_engine(int log_level);
9494

95-
bool launch_game(std::string &error_message, GameParams &game_params,
96-
const Settings &cmd_args);
95+
bool launch_game(std::string &error_message, bool reconnect_requested,
96+
GameParams &game_params, const Settings &cmd_args);
9797

9898
void main_menu(MainMenuData *menudata);
9999
bool create_engine_device(int log_level);

Diff for: ‎src/defaultsettings.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ void set_default_settings(Settings *settings)
254254

255255
settings->setDefault("kick_msg_shutdown", "Server shutting down.");
256256
settings->setDefault("kick_msg_crash", "This server has experienced an internal error. You will now be disconnected.");
257+
settings->setDefault("ask_reconnect_on_crash", "false");
257258

258259
settings->setDefault("profiler_print_interval", "0");
259260
settings->setDefault("enable_mapgen_debug_info", "false");

Diff for: ‎src/environment.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -426,13 +426,15 @@ bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, float stepsize, v3s16
426426
return true;
427427
}
428428

429-
void ServerEnvironment::kickAllPlayers(const std::string &reason)
429+
void ServerEnvironment::kickAllPlayers(AccessDeniedCode reason,
430+
const std::string &str_reason, bool reconnect)
430431
{
431-
std::wstring wreason = utf8_to_wide(reason);
432432
for (std::vector<Player*>::iterator it = m_players.begin();
433433
it != m_players.end();
434434
++it) {
435-
((Server*)m_gamedef)->DenyAccess_Legacy((*it)->peer_id, wreason);
435+
((Server*)m_gamedef)->DenyAccessVerCompliant((*it)->peer_id,
436+
(*it)->protocol_version, (AccessDeniedCode)reason,
437+
str_reason, reconnect);
436438
}
437439
}
438440

Diff for: ‎src/environment.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
4040
#include "mapnode.h"
4141
#include "mapblock.h"
4242
#include "jthread/jmutex.h"
43+
#include "network/networkprotocol.h" // for AccessDeniedCode
4344

4445
class ServerEnvironment;
4546
class ActiveBlockModifier;
@@ -221,7 +222,8 @@ class ServerEnvironment : public Environment
221222
float getSendRecommendedInterval()
222223
{ return m_recommended_send_interval; }
223224

224-
void kickAllPlayers(const std::string &reason);
225+
void kickAllPlayers(AccessDeniedCode reason,
226+
const std::string &str_reason, bool reconnect);
225227
// Save players
226228
void saveLoadedPlayers();
227229
void savePlayer(const std::string &playername);

Diff for: ‎src/game.cpp

+16-10
Original file line numberDiff line numberDiff line change
@@ -1417,8 +1417,7 @@ struct VolatileRunFlags {
14171417
* hides most of the stuff in this class (nothing in this class is required
14181418
* by any other file) but exposes the public methods/data only.
14191419
*/
1420-
class Game
1421-
{
1420+
class Game {
14221421
public:
14231422
Game();
14241423
~Game();
@@ -1434,6 +1433,7 @@ class Game
14341433
std::string *address,
14351434
u16 port,
14361435
std::string &error_message,
1436+
bool *reconnect,
14371437
ChatBackend *chat_backend,
14381438
const SubgameSpec &gamespec, // Used for local game
14391439
bool simple_singleplayer_mode);
@@ -1588,6 +1588,7 @@ class Game
15881588
scene::ISceneManager *smgr;
15891589
bool *kill;
15901590
std::string *error_message;
1591+
bool *reconnect_requested;
15911592
IGameDef *gamedef; // Convenience (same as *client)
15921593
scene::ISceneNode *skybox;
15931594

@@ -1716,17 +1717,19 @@ bool Game::startup(bool *kill,
17161717
std::string *address, // can change if simple_singleplayer_mode
17171718
u16 port,
17181719
std::string &error_message,
1720+
bool *reconnect,
17191721
ChatBackend *chat_backend,
17201722
const SubgameSpec &gamespec,
17211723
bool simple_singleplayer_mode)
17221724
{
17231725
// "cache"
1724-
this->device = device;
1725-
this->kill = kill;
1726-
this->error_message = &error_message;
1727-
this->random_input = random_input;
1728-
this->input = input;
1729-
this->chat_backend = chat_backend;
1726+
this->device = device;
1727+
this->kill = kill;
1728+
this->error_message = &error_message;
1729+
this->reconnect_requested = reconnect;
1730+
this->random_input = random_input;
1731+
this->input = input;
1732+
this->chat_backend = chat_backend;
17301733
this->simple_singleplayer_mode = simple_singleplayer_mode;
17311734

17321735
driver = device->getVideoDriver();
@@ -2239,6 +2242,7 @@ bool Game::connectToServer(const std::string &playername,
22392242
if (client->accessDenied()) {
22402243
*error_message = "Access denied. Reason: "
22412244
+ client->accessDeniedReason();
2245+
*reconnect_requested = client->reconnectRequested();
22422246
errorstream << *error_message << std::endl;
22432247
break;
22442248
}
@@ -2376,6 +2380,7 @@ inline bool Game::checkConnection()
23762380
if (client->accessDenied()) {
23772381
*error_message = "Access denied. Reason: "
23782382
+ client->accessDeniedReason();
2383+
*reconnect_requested = client->reconnectRequested();
23792384
errorstream << *error_message << std::endl;
23802385
return false;
23812386
}
@@ -4330,6 +4335,7 @@ void the_game(bool *kill,
43304335

43314336
std::string &error_message,
43324337
ChatBackend &chat_backend,
4338+
bool *reconnect_requested,
43334339
const SubgameSpec &gamespec, // Used for local game
43344340
bool simple_singleplayer_mode)
43354341
{
@@ -4344,8 +4350,8 @@ void the_game(bool *kill,
43444350
try {
43454351

43464352
if (game.startup(kill, random_input, input, device, map_dir,
4347-
playername, password, &server_address, port,
4348-
error_message, &chat_backend, gamespec,
4353+
playername, password, &server_address, port, error_message,
4354+
reconnect_requested, &chat_backend, gamespec,
43494355
simple_singleplayer_mode)) {
43504356
game.run();
43514357
game.shutdown();

Diff for: ‎src/game.h

+1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ void the_game(bool *kill,
147147
u16 port,
148148
std::string &error_message,
149149
ChatBackend &chat_backend,
150+
bool *reconnect_requested,
150151
const SubgameSpec &gamespec, // Used for local game
151152
bool simple_singleplayer_mode);
152153

Diff for: ‎src/guiEngine.cpp

+4-7
Original file line numberDiff line numberDiff line change
@@ -208,21 +208,18 @@ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev,
208208
m_script = new MainMenuScripting(this);
209209

210210
try {
211-
if (m_data->errormessage != "") {
212-
m_script->setMainMenuErrorMessage(m_data->errormessage);
213-
m_data->errormessage = "";
214-
}
211+
m_script->setMainMenuData(&m_data->script_data);
212+
m_data->script_data.errormessage = "";
215213

216214
if (!loadMainMenuScript()) {
217215
errorstream << "No future without mainmenu" << std::endl;
218216
abort();
219217
}
220218

221219
run();
222-
}
223-
catch(LuaError &e) {
220+
} catch (LuaError &e) {
224221
errorstream << "MAINMENU ERROR: " << e.what() << std::endl;
225-
m_data->errormessage = e.what();
222+
m_data->script_data.errormessage = e.what();
226223
}
227224

228225
m_menu->quitMenu();

0 commit comments

Comments
 (0)
Please sign in to comment.