Fix race between network client disconnect and network window deletion
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
#include "../network_internal.h"
|
||||
#include "../../debug.h"
|
||||
#include "../../error.h"
|
||||
#include "../../window_func.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
@@ -109,6 +110,7 @@ NetworkRecvStatus NetworkGameSocketHandler::CloseConnection(bool error)
|
||||
if (!_network_server && _networking) {
|
||||
extern void ClientNetworkEmergencySave(); // from network_client.cpp
|
||||
ClientNetworkEmergencySave();
|
||||
DeleteNetworkClientWindows();
|
||||
_switch_mode = SM_MENU;
|
||||
_networking = false;
|
||||
ShowErrorMessage(STR_NETWORK_ERROR_LOSTCONNECTION, INVALID_STRING_ID, WL_CRITICAL);
|
||||
|
@@ -522,7 +522,7 @@ static const NWidgetPart _nested_chat_window_widgets[] = {
|
||||
static WindowDesc _chat_window_desc(
|
||||
WDP_MANUAL, nullptr, 0, 0,
|
||||
WC_SEND_NETWORK_MSG, WC_NONE,
|
||||
0,
|
||||
WDF_NETWORK,
|
||||
_nested_chat_window_widgets, lengthof(_nested_chat_window_widgets)
|
||||
);
|
||||
|
||||
|
@@ -257,6 +257,7 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res)
|
||||
ClientNetworkEmergencySave();
|
||||
}
|
||||
|
||||
DeleteNetworkClientWindows();
|
||||
_switch_mode = SM_MENU;
|
||||
_networking = false;
|
||||
}
|
||||
|
@@ -1016,7 +1016,7 @@ static const NWidgetPart _nested_network_game_widgets[] = {
|
||||
static WindowDesc _network_game_window_desc(
|
||||
WDP_CENTER, "list_servers", 1000, 730,
|
||||
WC_NETWORK_WINDOW, WC_NONE,
|
||||
0,
|
||||
WDF_NETWORK,
|
||||
_nested_network_game_widgets, lengthof(_nested_network_game_widgets)
|
||||
);
|
||||
|
||||
@@ -1289,7 +1289,7 @@ static const NWidgetPart _nested_network_start_server_window_widgets[] = {
|
||||
static WindowDesc _network_start_server_window_desc(
|
||||
WDP_CENTER, nullptr, 0, 0,
|
||||
WC_NETWORK_WINDOW, WC_NONE,
|
||||
0,
|
||||
WDF_NETWORK,
|
||||
_nested_network_start_server_window_widgets, lengthof(_nested_network_start_server_window_widgets)
|
||||
);
|
||||
|
||||
@@ -1366,7 +1366,7 @@ static const NWidgetPart _nested_client_list_widgets[] = {
|
||||
static WindowDesc _client_list_desc(
|
||||
WDP_AUTO, "list_clients", 220, 300,
|
||||
WC_CLIENT_LIST, WC_NONE,
|
||||
0,
|
||||
WDF_NETWORK,
|
||||
_nested_client_list_widgets, lengthof(_nested_client_list_widgets)
|
||||
);
|
||||
|
||||
@@ -2259,7 +2259,7 @@ static const NWidgetPart _nested_network_join_status_window_widgets[] = {
|
||||
static WindowDesc _network_join_status_window_desc(
|
||||
WDP_CENTER, nullptr, 0, 0,
|
||||
WC_NETWORK_STATUS_WINDOW, WC_NONE,
|
||||
WDF_MODAL,
|
||||
WDF_MODAL | WDF_NETWORK,
|
||||
_nested_network_join_status_window_widgets, lengthof(_nested_network_join_status_window_widgets)
|
||||
);
|
||||
|
||||
@@ -2382,7 +2382,7 @@ static const NWidgetPart _nested_network_company_password_window_widgets[] = {
|
||||
static WindowDesc _network_company_password_window_desc(
|
||||
WDP_AUTO, nullptr, 0, 0,
|
||||
WC_COMPANY_PASSWORD_WINDOW, WC_NONE,
|
||||
0,
|
||||
WDF_NETWORK,
|
||||
_nested_network_company_password_window_widgets, lengthof(_nested_network_company_password_window_widgets)
|
||||
);
|
||||
|
||||
@@ -2484,7 +2484,7 @@ static const NWidgetPart _nested_network_ask_relay_widgets[] = {
|
||||
static WindowDesc _network_ask_relay_desc(
|
||||
WDP_CENTER, nullptr, 0, 0,
|
||||
WC_NETWORK_ASK_RELAY, WC_NONE,
|
||||
WDF_MODAL,
|
||||
WDF_MODAL | WDF_NETWORK,
|
||||
_nested_network_ask_relay_widgets, lengthof(_nested_network_ask_relay_widgets)
|
||||
);
|
||||
|
||||
|
@@ -3510,6 +3510,19 @@ void DeleteConstructionWindows()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all windows that use network client functionality.
|
||||
*/
|
||||
void DeleteNetworkClientWindows()
|
||||
{
|
||||
/* Note: the container remains stable, even when deleting windows. */
|
||||
for (const Window *w : Window::IterateUnordered()) {
|
||||
if (w->window_desc->flags & WDF_NETWORK) {
|
||||
delete w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Delete all always on-top windows to get an empty screen */
|
||||
void HideVitalWindows()
|
||||
{
|
||||
|
@@ -40,6 +40,7 @@ void DeleteNonVitalWindows();
|
||||
void DeleteAllNonVitalWindows();
|
||||
void DeleteAllMessages();
|
||||
void DeleteConstructionWindows();
|
||||
void DeleteNetworkClientWindows();
|
||||
void HideVitalWindows();
|
||||
void ShowVitalWindows();
|
||||
|
||||
|
@@ -229,6 +229,7 @@ enum WindowDefaultFlag {
|
||||
WDF_CONSTRUCTION = 1 << 0, ///< This window is used for construction; close it whenever changing company.
|
||||
WDF_MODAL = 1 << 1, ///< The window is a modal child of some other window, meaning the parent is 'inactive'
|
||||
WDF_NO_FOCUS = 1 << 2, ///< This window won't get focus/make any other window lose focus when click
|
||||
WDF_NETWORK = 1 << 3, ///< This window is used for network client functionality
|
||||
};
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user