Index: binaries/data/mods/public/gui/session/messages.js
===================================================================
--- binaries/data/mods/public/gui/session/messages.js
+++ binaries/data/mods/public/gui/session/messages.js
@@ -39,6 +39,9 @@
"netwarn": msg => {
addNetworkWarning(msg);
},
+ "out-of-sync": msg => {
+ onNetworkOutOfSync(msg);
+ },
"players": msg => {
handlePlayerAssignmentsMessage(msg);
},
@@ -599,6 +602,47 @@
}
}
+function onNetworkOutOfSync(msg)
+{
+ let txt = [
+ sprintf(translate("Out of synchronization error on turn %(turn)s."), {
+ "turn": msg.turn
+ }),
+
+ sprintf(translateWithContext("Out-Of-Sync", "Players: %(players)s"), {
+ "players": msg.players.join(translate(", "))
+ }),
+
+ msg.hash == msg.expectedHash ?
+ translateWithContext("Out-Of-Sync", "Your game state is identical to the hosts game state.") :
+ translateWithContext("Out-Of-Sync", "Your game state is different from the hosts game state."),
+
+ sprintf(translateWithContext("Out-Of-Sync", "Dumping current state to %(filepath)s"), {
+ "filepath": escapeText(msg.path)
+ })
+ ];
+
+ if (msg.turn > 1 && g_GameAttributes.settings.PlayerData.some(pData => pData && pData.AI))
+ txt.push(translate("Rejoining Multiplayer games with AIs is not supported yet!"));
+
+ messageBox(
+ 600, 200,
+ txt.join("\n"),
+ translate("Out Of Sync")
+ );
+}
+
+function onReplayOutOfSync()
+{
+ messageBox(
+ 500, 140,
+ translate("Out of synchronization error!") + "\n" +
+ // Translation: This is shown if replay is out of sync
+ translateWithContext("Out-Of-Sync", "The current game state is different from the original game state."),
+ translate("Out Of Sync")
+ );
+}
+
function handlePlayerAssignmentsMessage(message)
{
for (let guid in g_PlayerAssignments)
Index: binaries/data/mods/public/gui/session/session.xml
===================================================================
--- binaries/data/mods/public/gui/session/session.xml
+++ binaries/data/mods/public/gui/session/session.xml
@@ -30,6 +30,10 @@
onReplayFinished();
+
+ onReplayOutOfSync();
+
+
this.hidden = !this.hidden;
Index: source/network/NetClientTurnManager.cpp
===================================================================
--- source/network/NetClientTurnManager.cpp
+++ source/network/NetClientTurnManager.cpp
@@ -122,18 +122,27 @@
hash = Hexify(hash);
- std::stringstream msg;
- msg << "Out of sync on turn " << turn;
-
+ CStr playerNamesString;
+ std::vector playerNamesStrings;
for (size_t i = 0; i < playerNames.size(); ++i)
- msg << (i == 0 ? "\nPlayers: " : ", ") << utf8_from_wstring(playerNames[i].m_Name);
-
- msg << "\n\n" << "Your game state is " << (expectedHash == hash ? "identical to" : "different from") << " the hosts game state.";
-
- msg << "\n\n" << "Dumping current state to " << CStr(path.string8()).EscapeToPrintableASCII();
+ {
+ CStr name = utf8_from_wstring(playerNames[i].m_Name);
+ playerNamesString += (i == 0 ? "" : ", ") + name;
+ playerNamesStrings.push_back(name);
+ }
- LOGERROR("%s", msg.str());
+ LOGERROR("Out-Of-Sync on turn %d\nPlayers: %s\nDumping state to %s", turn, playerNamesString, path.string8());
- if (g_GUI)
- g_GUI->DisplayMessageBox(600, 350, L"Sync error", wstring_from_utf8(msg.str()));
+ ScriptInterface& scriptInterface = m_NetClient.GetScriptInterface();
+ JSContext* cx = scriptInterface.GetContext();
+ JSAutoRequest rq(cx);
+
+ JS::RootedValue msg(cx);
+ scriptInterface.Eval("({ 'type':'out-of-sync' })", &msg);
+ scriptInterface.SetProperty(msg, "turn", turn);
+ scriptInterface.SetProperty(msg, "players", playerNamesStrings);
+ scriptInterface.SetProperty(msg, "expectedHash", expectedHash);
+ scriptInterface.SetProperty(msg, "hash", hash);
+ scriptInterface.SetProperty(msg, "path", path.string8());
+ m_NetClient.PushGuiMessage(msg);
}
Index: source/simulation2/system/ReplayTurnManager.h
===================================================================
--- source/simulation2/system/ReplayTurnManager.h
+++ source/simulation2/system/ReplayTurnManager.h
@@ -41,8 +41,6 @@
void DoTurn(u32 turn);
- void OnSyncError(u32 turn);
-
// Contains the commands of every player on each turn
std::map>> m_ReplayCommands;
Index: source/simulation2/system/ReplayTurnManager.cpp
===================================================================
--- source/simulation2/system/ReplayTurnManager.cpp
+++ source/simulation2/system/ReplayTurnManager.cpp
@@ -77,7 +77,11 @@
hash = Hexify(hash);
if (hash != expectedHash)
- OnSyncError(turn);
+ {
+ m_HasSyncError = true;
+ LOGERROR("Replay out of sync on turn %d", turn);
+ g_GUI->SendEventToAll("ReplayOutOfSync");
+ }
}
void CReplayTurnManager::DoTurn(u32 turn)
@@ -100,16 +104,3 @@
if (turn == m_FinalTurn)
g_GUI->SendEventToAll("ReplayFinished");
}
-
-void CReplayTurnManager::OnSyncError(u32 turn)
-{
- m_HasSyncError = true;
-
- std::stringstream msg;
- msg << "Out of sync on turn " << turn << "\n\n" << "The current game state is different from the original game state.";
-
- LOGERROR("%s", msg.str());
-
- if (g_GUI)
- g_GUI->DisplayMessageBox(600, 350, L"Sync error", wstring_from_utf8(msg.str()));
-}