Ticket #3293: t3293_show_who_is_oos_v1_16870.patch
File t3293_show_who_is_oos_v1_16870.patch, 10.1 KB (added by , 9 years ago) |
---|
-
source/network/NetClient.cpp
641 641 client->m_ClientTurnManager->OnSimulationMessage(simMessage); 642 642 } 643 643 else if (message->GetType() == NMT_SYNC_ERROR) 644 644 { 645 645 CSyncErrorMessage* syncMessage = static_cast<CSyncErrorMessage*> (message); 646 client->m_ClientTurnManager->OnSyncError(syncMessage->m_Turn, syncMessage->m_HashExpected); 646 647 std::vector<CStrW> playernames; 648 for (size_t i = 0; i < syncMessage->m_Playernames.size(); ++i) 649 playernames.push_back(syncMessage->m_Playernames[i].m_Name); 650 651 client->m_ClientTurnManager->OnSyncError(syncMessage->m_Turn, syncMessage->m_HashExpected, playernames); 647 652 } 648 653 else if (message->GetType() == NMT_END_COMMAND_BATCH) 649 654 { 650 655 CEndCommandBatchMessage* endMessage = static_cast<CEndCommandBatchMessage*> (message); 651 656 client->m_ClientTurnManager->FinishedAllCommands(endMessage->m_Turn, endMessage->m_TurnLength); -
source/network/NetMessages.h
179 179 END_NMT_CLASS() 180 180 181 181 START_NMT_CLASS_(SyncError, NMT_SYNC_ERROR) 182 182 NMT_FIELD_INT(m_Turn, u32, 4) 183 183 NMT_FIELD(CStr, m_HashExpected) 184 NMT_START_ARRAY(m_Playernames) 185 NMT_FIELD(CStrW, m_Name) 186 NMT_END_ARRAY() 184 187 END_NMT_CLASS() 185 188 186 189 END_NMTS() 187 190 188 191 #else -
source/network/NetServer.cpp
878 878 // TODO: we shouldn't send the message back to the client that first sent it 879 879 } 880 880 else if (message->GetType() == (uint)NMT_SYNC_CHECK) 881 881 { 882 882 CSyncCheckMessage* syncMessage = static_cast<CSyncCheckMessage*> (message); 883 server.m_ServerTurnManager->NotifyFinishedClientUpdate(session->GetHostID(), s yncMessage->m_Turn, syncMessage->m_Hash);883 server.m_ServerTurnManager->NotifyFinishedClientUpdate(session->GetHostID(), session->GetUserName(), syncMessage->m_Turn, syncMessage->m_Hash); 884 884 } 885 885 else if (message->GetType() == (uint)NMT_END_COMMAND_BATCH) 886 886 { 887 887 CEndCommandBatchMessage* endMessage = static_cast<CEndCommandBatchMessage*> (message); 888 888 server.m_ServerTurnManager->NotifyFinishedClientCommands(session->GetHostID(), endMessage->m_Turn); -
source/network/NetTurnManager.cpp
216 216 } 217 217 218 218 return true; 219 219 } 220 220 221 void CNetTurnManager::OnSyncError(u32 turn, const std::string& expectedHash )221 void CNetTurnManager::OnSyncError(u32 turn, const std::string& expectedHash, std::vector<CStrW> playerNames) 222 222 { 223 223 NETTURN_LOG((L"OnSyncError(%d, %hs)\n", turn, Hexify(expectedHash).c_str())); 224 224 225 225 // Only complain the first time 226 226 if (m_HasSyncError) … … 236 236 file.close(); 237 237 238 238 hash = Hexify(hash); 239 239 const std::string& expectedHashHex = Hexify(expectedHash); 240 240 241 DisplayOOSError(turn, hash, expectedHashHex, false, &p ath);241 DisplayOOSError(turn, hash, expectedHashHex, false, &playerNames, &path); 242 242 } 243 243 244 void CNetTurnManager::DisplayOOSError(u32 turn, const std::string& hash, const std::string& expectedHash, bool isReplay, OsPath* path = NULL)244 void CNetTurnManager::DisplayOOSError(u32 turn, const std::string& hash, const std::string& expectedHash, bool isReplay, std::vector<CStrW>* playerNames = NULL, OsPath* path = NULL) 245 245 { 246 246 m_HasSyncError = true; 247 247 248 std:: stringstream msg;249 msg << "Out of sync on turn " << turn << ": expected hash " << expectedHash <<"\n";248 std::wstringstream msg; 249 msg << L"Out of sync on turn " << turn << L"\n"; 250 250 251 if (expectedHash != hash || m_CurrentTurn != turn) 252 msg << "\nCurrent state: turn " << m_CurrentTurn << ", hash " << hash << "\n\n"; 251 if (playerNames) 252 { 253 msg << L"Players:"; 254 for(const CStrW player : *playerNames) 255 msg << L" " << player; 256 msg << "L\n"; 257 } 253 258 254 259 if (isReplay) 255 260 msg << "\nThe current game state is different from the original game state.\n\n"; 256 261 else 257 262 { … … 262 267 } 263 268 264 269 if (path) 265 270 msg << "Dumping current state to " << utf8_from_wstring(OsPath(*path).string()); 266 271 267 LOGERROR("%s", msg.str());272 LOGERROR("%s", utf8_from_wstring(msg.str())); 268 273 269 274 if (g_GUI) 270 g_GUI->DisplayMessageBox(600, 350, L"Sync error", wstring_from_utf8(msg.str()));275 g_GUI->DisplayMessageBox(600, 350, L"Sync error", msg.str()); 271 276 } 272 277 273 278 void CNetTurnManager::Interpolate(float simFrameLength, float realFrameLength) 274 279 { 275 280 // TODO: using m_TurnLength might be a bit dodgy when length changes - maybe … … 428 433 429 434 NETTURN_LOG((L"NotifyFinishedUpdate(%d, %hs)\n", turn, Hexify(hash).c_str())); 430 435 431 436 m_Replay.Hash(hash, quick); 432 437 433 // Send message to the server 434 CSyncCheckMessage msg; 435 msg.m_Turn = turn; 436 msg.m_Hash = hash; 437 m_NetClient.SendMessage(&msg); 438 if (!m_HasSyncError) 439 { 440 // Send message to the server 441 CSyncCheckMessage msg; 442 msg.m_Turn = turn; 443 msg.m_Hash = hash; 444 m_NetClient.SendMessage(&msg); 445 } 438 446 } 439 447 440 448 void CNetClientTurnManager::OnDestroyConnection() 441 449 { 442 450 NotifyFinishedOwnCommands(m_CurrentTurn + COMMAND_DELAY); … … 550 558 AddCommand(m_ClientId, pair.first, command, m_CurrentTurn + 1); 551 559 } 552 560 } 553 561 554 562 CNetServerTurnManager::CNetServerTurnManager(CNetServerWorker& server) : 555 m_NetServer(server), m_ReadyTurn(1), m_TurnLength(DEFAULT_TURN_LENGTH_MP) 563 m_NetServer(server), m_ReadyTurn(1), m_TurnLength(DEFAULT_TURN_LENGTH_MP), m_HasSyncError(false) 556 564 { 557 565 // The first turn we will actually execute is number 2, 558 566 // so store dummy values into the saved lengths list 559 567 m_SavedTurnLengths.push_back(0); 560 568 m_SavedTurnLengths.push_back(0); … … 599 607 // Save the turn length in case it's needed later 600 608 ENSURE(m_SavedTurnLengths.size() == m_ReadyTurn); 601 609 m_SavedTurnLengths.push_back(m_TurnLength); 602 610 } 603 611 604 void CNetServerTurnManager::NotifyFinishedClientUpdate(int client, u32 turn, const std::string& hash)612 void CNetServerTurnManager::NotifyFinishedClientUpdate(int client, const CStrW playername, u32 turn, const std::string& hash) 605 613 { 606 614 // Clients must advance one turn at a time 607 615 ENSURE(turn == m_ClientsSimulated[client] + 1); 608 616 m_ClientsSimulated[client] = turn; 609 617 618 // Check for oos only if in sync 619 if (m_HasSyncError) 620 return; 621 622 m_ClientPlayernames[client] = playername; 610 623 m_ClientStateHashes[turn][client] = hash; 611 624 612 625 // Find the newest turn which we know all clients have simulated 613 626 u32 newest = std::numeric_limits<u32>::max(); 614 627 for (std::map<int, u32>::iterator it = m_ClientsSimulated.begin(); it != m_ClientsSimulated.end(); ++it) … … 624 637 break; 625 638 626 639 // Assume the host is correct (maybe we should choose the most common instead to help debugging) 627 640 std::string expected = it->second.begin()->second; 628 641 642 std::vector<CStrW> oos_Playernames; 629 643 for (std::map<int, std::string>::iterator cit = it->second.begin(); cit != it->second.end(); ++cit) 630 644 { 631 645 NETTURN_LOG((L"sync check %d: %d = %hs\n", it->first, cit->first, Hexify(cit->second).c_str())); 632 646 if (cit->second != expected) 633 647 { 634 648 // Oh no, out of sync 649 m_HasSyncError = true; 650 oos_Playernames.push_back(m_ClientPlayernames[cit->first]); 651 } 652 } 635 653 636 // Tell everyone about it 637 CSyncErrorMessage msg; 638 msg.m_Turn = it->first; 639 msg.m_HashExpected = expected; 640 m_NetServer.Broadcast(&msg); 641 642 break; 654 // Tell everyone about out it 655 if (m_HasSyncError) 656 { 657 CSyncErrorMessage msg; 658 msg.m_Turn = it->first; 659 msg.m_HashExpected = expected; 660 for(const CStrW& playername : oos_Playernames) 661 { 662 CSyncErrorMessage::S_m_Playernames h; 663 h.m_Name = playername; 664 msg.m_Playernames.push_back(h); 643 665 } 666 m_NetServer.Broadcast(&msg); 667 break; 644 668 } 645 669 } 646 670 647 671 // Delete the saved hashes for all turns that we've already verified 648 672 m_ClientStateHashes.erase(m_ClientStateHashes.begin(), m_ClientStateHashes.lower_bound(newest+1)); -
source/network/NetTurnManager.h
105 105 virtual void OnSimulationMessage(CSimulationMessage* msg) = 0; 106 106 107 107 /** 108 108 * Called when there has been an out-of-sync error. 109 109 */ 110 virtual void OnSyncError(u32 turn, const std::string& expectedHash );110 virtual void OnSyncError(u32 turn, const std::string& expectedHash, std::vector<CStrW>); 111 111 112 112 /** 113 113 * Shows a message box when an out of sync error has been detected in the session or visual replay. 114 114 */ 115 virtual void DisplayOOSError(u32 turn, const std::string& hash, const std::string& expectedHash, bool isReplay, OsPath* path);115 virtual void DisplayOOSError(u32 turn, const std::string& hash, const std::string& expectedHash, bool isReplay, std::vector<CStrW>* playerNames, OsPath* path); 116 116 117 117 /** 118 118 * Called by simulation code, to add a new command to be distributed to all clients and executed soon. 119 119 */ 120 120 virtual void PostCommand(JS::HandleValue data) = 0; … … 291 291 public: 292 292 CNetServerTurnManager(CNetServerWorker& server); 293 293 294 294 void NotifyFinishedClientCommands(int client, u32 turn); 295 295 296 void NotifyFinishedClientUpdate(int client, u32 turn, const std::string& hash);296 void NotifyFinishedClientUpdate(int client, const CStrW playername, u32 turn, const std::string& hash); 297 297 298 298 /** 299 299 * Inform the turn manager of a new client who will be sending commands. 300 300 */ 301 301 void InitialiseClient(int client, u32 turn); … … 334 334 std::map<int, u32> m_ClientsSimulated; 335 335 336 336 // Map of turn -> {Client ID -> state hash}; old indexes <= min(m_ClientsSimulated) are deleted 337 337 std::map<u32, std::map<int, std::string> > m_ClientStateHashes; 338 338 339 // Map of client ID -> playername 340 std::map<u32, CStrW> m_ClientPlayernames; 341 339 342 // Current turn length 340 343 u32 m_TurnLength; 341 344 342 345 // Turn lengths for all previously executed turns 343 346 std::vector<u32> m_SavedTurnLengths; 344 347 345 348 CNetServerWorker& m_NetServer; 349 350 bool m_HasSyncError; 346 351 }; 347 352 348 353 #endif // INCLUDED_NETTURNMANAGER