Index: binaries/data/mods/public/gui/gamesetup/Controls/StartGameControl.js =================================================================== --- binaries/data/mods/public/gui/gamesetup/Controls/StartGameControl.js +++ binaries/data/mods/public/gui/gamesetup/Controls/StartGameControl.js @@ -20,6 +20,7 @@ this.gameStarted = false; netMessages.registerNetMessageHandler("start", this.switchToLoadingPage.bind(this)); + netMessages.registerNetMessageHandler("startfailed", this.switchBack.bind(this)); } registerLaunchGameHandler(handler) @@ -37,17 +38,23 @@ if (g_IsNetworked) Engine.StartNetworkGame(); else - { Engine.StartGame(g_GameAttributes, g_PlayerAssignments.local.player); - this.switchToLoadingPage(); - } + this.switchToLoadingPage(); } switchToLoadingPage() { - Engine.SwitchGuiPage("page_loading.xml", { + Engine.PushGuiPage("page_loading.xml", { "attribs": g_GameAttributes, "playerAssignments": g_PlayerAssignments }); } + + switchBack(msg) + { + error(sprintf(translate("Game start failed: %s"), + msg.reason || translate("Unknown reason"))); + Engine.PopGuiPage(); + Engine.ResetCursor(); + } } Index: binaries/data/mods/public/gui/gamesetup/NetMessages/NetMessages.js =================================================================== --- binaries/data/mods/public/gui/gamesetup/NetMessages/NetMessages.js +++ binaries/data/mods/public/gui/gamesetup/NetMessages/NetMessages.js @@ -67,5 +67,6 @@ "netstatus", "netwarn", "players", - "start" + "start", + "startfailed" ]; Index: binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/Panels/Buttons/StartGameButton.js =================================================================== --- binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/Panels/Buttons/StartGameButton.js +++ binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/Panels/Buttons/StartGameButton.js @@ -30,7 +30,7 @@ update() { let isEveryoneReady = this.isEveryoneReady(); - this.startGameButton.enabled = !this.gameStarted && isEveryoneReady; + this.startGameButton.enabled = true;//!this.gameStarted && isEveryoneReady; this.startGameButton.tooltip = !g_IsNetworked || isEveryoneReady ? this.ReadyTooltip : Index: source/network/NetClient.h =================================================================== --- source/network/NetClient.h +++ source/network/NetClient.h @@ -249,6 +249,7 @@ static bool OnPlayerAssignment(void* context, CFsmEvent* event); static bool OnInGame(void* context, CFsmEvent* event); static bool OnGameStart(void* context, CFsmEvent* event); + static bool OnGameStartFailed(void* context, CFsmEvent* event); static bool OnJoinSyncStart(void* context, CFsmEvent* event); static bool OnJoinSyncEndCommandBatch(void* context, CFsmEvent* event); static bool OnRejoined(void* context, CFsmEvent* event); Index: source/network/NetClient.cpp =================================================================== --- source/network/NetClient.cpp +++ source/network/NetClient.cpp @@ -102,6 +102,7 @@ AddTransition(NCS_PREGAME, (uint)NMT_CLIENT_TIMEOUT, NCS_PREGAME, (void*)&OnClientTimeout, context); AddTransition(NCS_PREGAME, (uint)NMT_CLIENT_PERFORMANCE, NCS_PREGAME, (void*)&OnClientPerformance, context); AddTransition(NCS_PREGAME, (uint)NMT_GAME_START, NCS_LOADING, (void*)&OnGameStart, context); + AddTransition(NCS_PREGAME, (uint)NMT_GAME_START_FAILED, NCS_PREGAME, (void*)&OnGameStartFailed, context); AddTransition(NCS_PREGAME, (uint)NMT_JOIN_SYNC_START, NCS_JOIN_SYNCING, (void*)&OnJoinSyncStart, context); AddTransition(NCS_JOIN_SYNCING, (uint)NMT_CHAT, NCS_JOIN_SYNCING, (void*)&OnChat, context); @@ -663,6 +664,21 @@ return true; } +bool CNetClient::OnGameStartFailed(void* context, CFsmEvent* event) +{ + ENSURE(event->GetType() == (uint)NMT_GAME_START_FAILED); + + CNetClient* client = static_cast(context); + CGameStartFailedMessage* message = static_cast(event->GetParamRef()); + + client->PushGuiMessage( + "type", "startfailed", + "reason", message->m_Reason + ); + + return true; +} + bool CNetClient::OnJoinSyncStart(void* context, CFsmEvent* event) { ENSURE(event->GetType() == (uint)NMT_JOIN_SYNC_START); Index: source/network/NetMessage.cpp =================================================================== --- source/network/NetMessage.cpp +++ source/network/NetMessage.cpp @@ -183,6 +183,10 @@ pNewMessage = new CGameStartMessage; break; + case NMT_GAME_START_FAILED: + pNewMessage = new CGameStartFailedMessage; + break; + case NMT_END_COMMAND_BATCH: pNewMessage = new CEndCommandBatchMessage; break; Index: source/network/NetMessages.h =================================================================== --- source/network/NetMessages.h +++ source/network/NetMessages.h @@ -28,13 +28,14 @@ #define PS_PROTOCOL_MAGIC 0x5073013f // 'P', 's', 0x01, '?' #define PS_PROTOCOL_MAGIC_RESPONSE 0x50630121 // 'P', 'c', 0x01, '!' -#define PS_PROTOCOL_VERSION 0x01010015 // Arbitrary protocol +#define PS_PROTOCOL_VERSION 0x01010016 // Arbitrary protocol #define PS_DEFAULT_PORT 0x5073 // 'P', 's' // Set when lobby authentication is required. Used in the SrvHandshakeResponseMessage. #define PS_NETWORK_FLAG_REQUIRE_LOBBYAUTH 0x1 -// Defines the list of message types. The order of the list must not change. +// Defines the list of message types. +// The order of the list must not change (unless the protocol version is changed). // The message types having a negative value are used internally and not sent // over the network. The message types used for network communication have // positive values. @@ -75,6 +76,7 @@ NMT_LOADED_GAME, NMT_GAME_START, + NMT_GAME_START_FAILED, NMT_END_COMMAND_BATCH, NMT_SYNC_CHECK, // OOS-detection hash checking @@ -215,6 +217,10 @@ START_NMT_CLASS_(GameStart, NMT_GAME_START) END_NMT_CLASS() +START_NMT_CLASS_(GameStartFailed, NMT_GAME_START_FAILED) + NMT_FIELD(CStr, m_Reason) +END_NMT_CLASS() + START_NMT_CLASS_(EndCommandBatch, NMT_END_COMMAND_BATCH) NMT_FIELD_INT(m_Turn, u32, 4) NMT_FIELD_INT(m_TurnLength, u32, 2) Index: source/network/NetServer.cpp =================================================================== --- source/network/NetServer.cpp +++ source/network/NetServer.cpp @@ -1485,7 +1485,10 @@ for (std::pair& player : m_PlayerAssignments) if (player.second.m_Enabled && player.second.m_PlayerID != -1 && player.second.m_Status == 0) { - LOGERROR("Tried to start the game without player \"%s\" being ready!", utf8_from_wstring(player.second.m_Name).c_str()); + CGameStartFailedMessage gameStartFailed; + gameStartFailed.m_Reason = "Player " + player.second.m_Name.ToUTF8() + " is not ready"; + Broadcast(&gameStartFailed, { NSS_PREGAME }); + return; }