Skip to content

Commit

Permalink
Optional reconnect functionality
Browse files Browse the repository at this point in the history
Enable the server to request the client to reconnect.

This can be done with the now extended minetest.request_shutdown([reason], [reconnect]) setting.
  • Loading branch information
est31 committed Jul 23, 2015
1 parent 1e0e85f commit 3b50b27
Show file tree
Hide file tree
Showing 25 changed files with 233 additions and 110 deletions.
65 changes: 39 additions & 26 deletions builtin/fstk/ui.lua
Expand Up @@ -54,29 +54,42 @@ end
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

local function wordwrap_quickhack(str)
local res = ""
local ar = str:split("\n")
for i = 1, #ar do
local text = ar[i]
-- Hack to add word wrapping.
-- TODO: Add engine support for wrapping in formspecs
while #text > 80 do
if res ~= "" then
res = res .. ","
end
res = res .. core.formspec_escape(string.sub(text, 1, 79))
text = string.sub(text, 80, #text)
end
if res ~= "" then
res = res .. ","
end
res = res .. core.formspec_escape(text)
end
return res
end

--------------------------------------------------------------------------------
function ui.update()
local formspec = ""

-- handle errors
if gamedata ~= nil and gamedata.errormessage ~= nil then
local ar = gamedata.errormessage:split("\n")
for i = 1, #ar do
local text = ar[i]
-- Hack to add word wrapping.
-- TODO: Add engine support for wrapping in formspecs
while #text > 80 do
if formspec ~= "" then
formspec = formspec .. ","
end
formspec = formspec .. core.formspec_escape(string.sub(text, 1, 79))
text = string.sub(text, 80, #text)
end
if formspec ~= "" then
formspec = formspec .. ","
end
formspec = formspec .. core.formspec_escape(text)
end
if gamedata ~= nil and gamedata.reconnect_requested then
formspec = wordwrap_quickhack(gamedata.errormessage or "")
formspec = "size[12,5]" ..
"label[0.5,0;" .. fgettext("The server has requested a reconnect:") ..
"]textlist[0.2,0.8;11.5,3.5;;" .. formspec ..
"]button[6,4.6;3,0.5;btn_reconnect_no;" .. fgettext("Main menu") .. "]" ..
"button[3,4.6;3,0.5;btn_reconnect_yes;" .. fgettext("Reconnect") .. "]"
elseif gamedata ~= nil and gamedata.errormessage ~= nil then
formspec = wordwrap_quickhack(gamedata.errormessage)
local error_title
if string.find(gamedata.errormessage, "ModError") then
error_title = fgettext("An error occured in a Lua script, such as a mod:")
Expand Down Expand Up @@ -128,13 +141,6 @@ end

--------------------------------------------------------------------------------
function ui.handle_buttons(fields)

if fields["btn_error_confirm"] then
gamedata.errormessage = nil
update_menu()
return
end

for key,value in pairs(ui.childlist) do

local retval = value:handle_buttons(fields)
Expand Down Expand Up @@ -168,8 +174,15 @@ end
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
core.button_handler = function(fields)
if fields["btn_error_confirm"] then
if fields["btn_reconnect_yes"] then
gamedata.reconnect_requested = false
gamedata.errormessage = nil
gamedata.do_reconnect = true
core.start()
return
elseif fields["btn_reconnect_no"] or fields["btn_error_confirm"] then
gamedata.errormessage = nil
gamedata.reconnect_requested = false
ui.update()
return
end
Expand Down
3 changes: 2 additions & 1 deletion doc/lua_api.txt
Expand Up @@ -2174,7 +2174,8 @@ These functions return the leftover itemstack.
* Optional: Variable number of arguments that are passed to `func`

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

### Bans
Expand Down
3 changes: 3 additions & 0 deletions minetest.conf.example
Expand Up @@ -393,6 +393,9 @@
# A message to be displayed to all clients when the server shuts down
#kick_msg_crash = This server has experienced an internal error. You will now be disconnected.
# A message to be displayed to all clients when the server crashes
#ask_reconnect_on_crash = false
# Whether to ask clients to reconnect after a (lua) crash.
# Set this to true if your server is set up to restart automatically.

# Mod profiler
#mod_profiling = false
Expand Down
1 change: 1 addition & 0 deletions src/client.cpp
Expand Up @@ -244,6 +244,7 @@ Client::Client(
m_chosen_auth_mech(AUTH_MECHANISM_NONE),
m_auth_data(NULL),
m_access_denied(false),
m_access_denied_reconnect(false),
m_itemdef_received(false),
m_nodedef_received(false),
m_media_downloader(new ClientMediaDownloader()),
Expand Down
3 changes: 3 additions & 0 deletions src/client.h
Expand Up @@ -489,6 +489,8 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
bool accessDenied()
{ return m_access_denied; }

bool reconnectRequested() { return m_access_denied_reconnect; }

std::string accessDeniedReason()
{ return m_access_denied_reason; }

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


bool m_access_denied;
bool m_access_denied_reconnect;
std::string m_access_denied_reason;
std::queue<ClientEvent> m_client_event_queue;
bool m_itemdef_received;
Expand Down
24 changes: 15 additions & 9 deletions src/client/clientlauncher.cpp
Expand Up @@ -168,8 +168,9 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
ChatBackend chat_backend;

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

bool first_loop = true;

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

bool game_has_run = launch_game(error_message, game_params, cmd_args);
bool game_has_run = launch_game(error_message, reconnect_requested,
game_params, cmd_args);

// If skip_main_menu, we only want to startup once
if (skip_main_menu && !first_loop)
Expand Down Expand Up @@ -233,6 +235,7 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
receiver->m_touchscreengui = new TouchScreenGUI(device, receiver);
g_touchscreengui = receiver->m_touchscreengui;
#endif

the_game(
kill,
random_input,
Expand All @@ -245,6 +248,7 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
current_port,
error_message,
chat_backend,
&reconnect_requested,
gamespec,
simple_singleplayer_mode
);
Expand Down Expand Up @@ -325,14 +329,16 @@ bool ClientLauncher::init_engine(int log_level)
}

bool ClientLauncher::launch_game(std::string &error_message,
GameParams &game_params, const Settings &cmd_args)
bool reconnect_requested, GameParams &game_params,
const Settings &cmd_args)
{
// Initialize menu data
MainMenuData menudata;
menudata.address = address;
menudata.name = playername;
menudata.port = itos(game_params.socket_port);
menudata.errormessage = error_message;
menudata.address = address;
menudata.name = playername;
menudata.port = itos(game_params.socket_port);
menudata.script_data.errormessage = error_message;
menudata.script_data.reconnect_requested = reconnect_requested;

error_message.clear();

Expand Down Expand Up @@ -379,11 +385,11 @@ bool ClientLauncher::launch_game(std::string &error_message,
}
}

if (!menudata.errormessage.empty()) {
if (!menudata.script_data.errormessage.empty()) {
/* The calling function will pass this back into this function upon the
* next iteration (if any) causing it to be displayed by the GUI
*/
error_message = menudata.errormessage;
error_message = menudata.script_data.errormessage;
return false;
}

Expand Down
4 changes: 2 additions & 2 deletions src/client/clientlauncher.h
Expand Up @@ -92,8 +92,8 @@ class ClientLauncher
void init_args(GameParams &game_params, const Settings &cmd_args);
bool init_engine(int log_level);

bool launch_game(std::string &error_message, GameParams &game_params,
const Settings &cmd_args);
bool launch_game(std::string &error_message, bool reconnect_requested,
GameParams &game_params, const Settings &cmd_args);

void main_menu(MainMenuData *menudata);
bool create_engine_device(int log_level);
Expand Down
1 change: 1 addition & 0 deletions src/defaultsettings.cpp
Expand Up @@ -254,6 +254,7 @@ void set_default_settings(Settings *settings)

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

settings->setDefault("profiler_print_interval", "0");
settings->setDefault("enable_mapgen_debug_info", "false");
Expand Down
8 changes: 5 additions & 3 deletions src/environment.cpp
Expand Up @@ -426,13 +426,15 @@ bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, float stepsize, v3s16
return true;
}

void ServerEnvironment::kickAllPlayers(const std::string &reason)
void ServerEnvironment::kickAllPlayers(AccessDeniedCode reason,
const std::string &str_reason, bool reconnect)
{
std::wstring wreason = utf8_to_wide(reason);
for (std::vector<Player*>::iterator it = m_players.begin();
it != m_players.end();
++it) {
((Server*)m_gamedef)->DenyAccess_Legacy((*it)->peer_id, wreason);
((Server*)m_gamedef)->DenyAccessVerCompliant((*it)->peer_id,
(*it)->protocol_version, (AccessDeniedCode)reason,
str_reason, reconnect);
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/environment.h
Expand Up @@ -40,6 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapnode.h"
#include "mapblock.h"
#include "jthread/jmutex.h"
#include "network/networkprotocol.h" // for AccessDeniedCode

class ServerEnvironment;
class ActiveBlockModifier;
Expand Down Expand Up @@ -221,7 +222,8 @@ class ServerEnvironment : public Environment
float getSendRecommendedInterval()
{ return m_recommended_send_interval; }

void kickAllPlayers(const std::string &reason);
void kickAllPlayers(AccessDeniedCode reason,
const std::string &str_reason, bool reconnect);
// Save players
void saveLoadedPlayers();
void savePlayer(const std::string &playername);
Expand Down
26 changes: 16 additions & 10 deletions src/game.cpp
Expand Up @@ -1417,8 +1417,7 @@ struct VolatileRunFlags {
* hides most of the stuff in this class (nothing in this class is required
* by any other file) but exposes the public methods/data only.
*/
class Game
{
class Game {
public:
Game();
~Game();
Expand All @@ -1434,6 +1433,7 @@ class Game
std::string *address,
u16 port,
std::string &error_message,
bool *reconnect,
ChatBackend *chat_backend,
const SubgameSpec &gamespec, // Used for local game
bool simple_singleplayer_mode);
Expand Down Expand Up @@ -1588,6 +1588,7 @@ class Game
scene::ISceneManager *smgr;
bool *kill;
std::string *error_message;
bool *reconnect_requested;
IGameDef *gamedef; // Convenience (same as *client)
scene::ISceneNode *skybox;

Expand Down Expand Up @@ -1716,17 +1717,19 @@ bool Game::startup(bool *kill,
std::string *address, // can change if simple_singleplayer_mode
u16 port,
std::string &error_message,
bool *reconnect,
ChatBackend *chat_backend,
const SubgameSpec &gamespec,
bool simple_singleplayer_mode)
{
// "cache"
this->device = device;
this->kill = kill;
this->error_message = &error_message;
this->random_input = random_input;
this->input = input;
this->chat_backend = chat_backend;
this->device = device;
this->kill = kill;
this->error_message = &error_message;
this->reconnect_requested = reconnect;
this->random_input = random_input;
this->input = input;
this->chat_backend = chat_backend;
this->simple_singleplayer_mode = simple_singleplayer_mode;

driver = device->getVideoDriver();
Expand Down Expand Up @@ -2239,6 +2242,7 @@ bool Game::connectToServer(const std::string &playername,
if (client->accessDenied()) {
*error_message = "Access denied. Reason: "
+ client->accessDeniedReason();
*reconnect_requested = client->reconnectRequested();
errorstream << *error_message << std::endl;
break;
}
Expand Down Expand Up @@ -2376,6 +2380,7 @@ inline bool Game::checkConnection()
if (client->accessDenied()) {
*error_message = "Access denied. Reason: "
+ client->accessDeniedReason();
*reconnect_requested = client->reconnectRequested();
errorstream << *error_message << std::endl;
return false;
}
Expand Down Expand Up @@ -4330,6 +4335,7 @@ void the_game(bool *kill,

std::string &error_message,
ChatBackend &chat_backend,
bool *reconnect_requested,
const SubgameSpec &gamespec, // Used for local game
bool simple_singleplayer_mode)
{
Expand All @@ -4344,8 +4350,8 @@ void the_game(bool *kill,
try {

if (game.startup(kill, random_input, input, device, map_dir,
playername, password, &server_address, port,
error_message, &chat_backend, gamespec,
playername, password, &server_address, port, error_message,
reconnect_requested, &chat_backend, gamespec,
simple_singleplayer_mode)) {
game.run();
game.shutdown();
Expand Down
1 change: 1 addition & 0 deletions src/game.h
Expand Up @@ -147,6 +147,7 @@ void the_game(bool *kill,
u16 port,
std::string &error_message,
ChatBackend &chat_backend,
bool *reconnect_requested,
const SubgameSpec &gamespec, // Used for local game
bool simple_singleplayer_mode);

Expand Down
11 changes: 4 additions & 7 deletions src/guiEngine.cpp
Expand Up @@ -208,21 +208,18 @@ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev,
m_script = new MainMenuScripting(this);

try {
if (m_data->errormessage != "") {
m_script->setMainMenuErrorMessage(m_data->errormessage);
m_data->errormessage = "";
}
m_script->setMainMenuData(&m_data->script_data);
m_data->script_data.errormessage = "";

if (!loadMainMenuScript()) {
errorstream << "No future without mainmenu" << std::endl;
abort();
}

run();
}
catch(LuaError &e) {
} catch (LuaError &e) {
errorstream << "MAINMENU ERROR: " << e.what() << std::endl;
m_data->errormessage = e.what();
m_data->script_data.errormessage = e.what();
}

m_menu->quitMenu();
Expand Down

0 comments on commit 3b50b27

Please sign in to comment.