Ticket #3293: t3293_show_who_is_oos_v1_16870.patch

File t3293_show_who_is_oos_v1_16870.patch, 10.1 KB (added by elexis, 9 years ago)

Shows who is out of sync and doesn't display the hash value in the error message anymore. Also prevents the CSyncCheckMessage and CSyncErrorMessage from being sent after oos was discovered to improve network performance.

  • source/network/NetClient.cpp

     
    641641            client->m_ClientTurnManager->OnSimulationMessage(simMessage);
    642642        }
    643643        else if (message->GetType() == NMT_SYNC_ERROR)
    644644        {
    645645            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);
    647652        }
    648653        else if (message->GetType() == NMT_END_COMMAND_BATCH)
    649654        {
    650655            CEndCommandBatchMessage* endMessage = static_cast<CEndCommandBatchMessage*> (message);
    651656            client->m_ClientTurnManager->FinishedAllCommands(endMessage->m_Turn, endMessage->m_TurnLength);
  • source/network/NetMessages.h

     
    179179END_NMT_CLASS()
    180180
    181181START_NMT_CLASS_(SyncError, NMT_SYNC_ERROR)
    182182    NMT_FIELD_INT(m_Turn, u32, 4)
    183183    NMT_FIELD(CStr, m_HashExpected)
     184    NMT_START_ARRAY(m_Playernames)
     185        NMT_FIELD(CStrW, m_Name)
     186    NMT_END_ARRAY()
    184187END_NMT_CLASS()
    185188
    186189END_NMTS()
    187190
    188191#else
  • source/network/NetServer.cpp

     
    878878        // TODO: we shouldn't send the message back to the client that first sent it
    879879    }
    880880    else if (message->GetType() == (uint)NMT_SYNC_CHECK)
    881881    {
    882882        CSyncCheckMessage* syncMessage = static_cast<CSyncCheckMessage*> (message);
    883         server.m_ServerTurnManager->NotifyFinishedClientUpdate(session->GetHostID(), syncMessage->m_Turn, syncMessage->m_Hash);
     883        server.m_ServerTurnManager->NotifyFinishedClientUpdate(session->GetHostID(), session->GetUserName(), syncMessage->m_Turn, syncMessage->m_Hash);
    884884    }
    885885    else if (message->GetType() == (uint)NMT_END_COMMAND_BATCH)
    886886    {
    887887        CEndCommandBatchMessage* endMessage = static_cast<CEndCommandBatchMessage*> (message);
    888888        server.m_ServerTurnManager->NotifyFinishedClientCommands(session->GetHostID(), endMessage->m_Turn);
  • source/network/NetTurnManager.cpp

     
    216216    }
    217217
    218218    return true;
    219219}
    220220
    221 void CNetTurnManager::OnSyncError(u32 turn, const std::string& expectedHash)
     221void CNetTurnManager::OnSyncError(u32 turn, const std::string& expectedHash, std::vector<CStrW> playerNames)
    222222{
    223223    NETTURN_LOG((L"OnSyncError(%d, %hs)\n", turn, Hexify(expectedHash).c_str()));
    224224
    225225    // Only complain the first time
    226226    if (m_HasSyncError)
     
    236236    file.close();
    237237
    238238    hash = Hexify(hash);
    239239    const std::string& expectedHashHex = Hexify(expectedHash);
    240240
    241     DisplayOOSError(turn, hash, expectedHashHex, false, &path);
     241    DisplayOOSError(turn, hash, expectedHashHex, false, &playerNames, &path);
    242242}
    243243
    244 void CNetTurnManager::DisplayOOSError(u32 turn, const std::string& hash, const std::string& expectedHash, bool isReplay, OsPath* path = NULL)
     244void CNetTurnManager::DisplayOOSError(u32 turn, const std::string& hash, const std::string& expectedHash, bool isReplay, std::vector<CStrW>* playerNames = NULL, OsPath* path = NULL)
    245245{
    246246    m_HasSyncError = true;
    247247
    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";
    250250
    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    }
    253258
    254259    if (isReplay)
    255260        msg << "\nThe current game state is different from the original game state.\n\n";
    256261    else
    257262    {
     
    262267    }
    263268
    264269    if (path)
    265270        msg << "Dumping current state to " << utf8_from_wstring(OsPath(*path).string());
    266271
    267     LOGERROR("%s", msg.str());
     272    LOGERROR("%s", utf8_from_wstring(msg.str()));
    268273
    269274    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());
    271276}
    272277
    273278void CNetTurnManager::Interpolate(float simFrameLength, float realFrameLength)
    274279{
    275280    // TODO: using m_TurnLength might be a bit dodgy when length changes - maybe
     
    428433
    429434    NETTURN_LOG((L"NotifyFinishedUpdate(%d, %hs)\n", turn, Hexify(hash).c_str()));
    430435
    431436    m_Replay.Hash(hash, quick);
    432437
    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    }
    438446}
    439447
    440448void CNetClientTurnManager::OnDestroyConnection()
    441449{
    442450    NotifyFinishedOwnCommands(m_CurrentTurn + COMMAND_DELAY);
     
    550558        AddCommand(m_ClientId, pair.first, command, m_CurrentTurn + 1);
    551559    }
    552560}
    553561
    554562CNetServerTurnManager::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)
    556564{
    557565    // The first turn we will actually execute is number 2,
    558566    // so store dummy values into the saved lengths list
    559567    m_SavedTurnLengths.push_back(0);
    560568    m_SavedTurnLengths.push_back(0);
     
    599607    // Save the turn length in case it's needed later
    600608    ENSURE(m_SavedTurnLengths.size() == m_ReadyTurn);
    601609    m_SavedTurnLengths.push_back(m_TurnLength);
    602610}
    603611
    604 void CNetServerTurnManager::NotifyFinishedClientUpdate(int client, u32 turn, const std::string& hash)
     612void CNetServerTurnManager::NotifyFinishedClientUpdate(int client, const CStrW playername, u32 turn, const std::string& hash)
    605613{
    606614    // Clients must advance one turn at a time
    607615    ENSURE(turn == m_ClientsSimulated[client] + 1);
    608616    m_ClientsSimulated[client] = turn;
    609617
     618    // Check for oos only if in sync
     619    if (m_HasSyncError)
     620        return;
     621
     622    m_ClientPlayernames[client] = playername;
    610623    m_ClientStateHashes[turn][client] = hash;
    611624
    612625    // Find the newest turn which we know all clients have simulated
    613626    u32 newest = std::numeric_limits<u32>::max();
    614627    for (std::map<int, u32>::iterator it = m_ClientsSimulated.begin(); it != m_ClientsSimulated.end(); ++it)
     
    624637            break;
    625638
    626639        // Assume the host is correct (maybe we should choose the most common instead to help debugging)
    627640        std::string expected = it->second.begin()->second;
    628641
     642        std::vector<CStrW> oos_Playernames;
    629643        for (std::map<int, std::string>::iterator cit = it->second.begin(); cit != it->second.end(); ++cit)
    630644        {
    631645            NETTURN_LOG((L"sync check %d: %d = %hs\n", it->first, cit->first, Hexify(cit->second).c_str()));
    632646            if (cit->second != expected)
    633647            {
    634648                // Oh no, out of sync
     649                m_HasSyncError = true;
     650                oos_Playernames.push_back(m_ClientPlayernames[cit->first]);
     651            }
     652        }
    635653
    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);
    643665            }
     666            m_NetServer.Broadcast(&msg);
     667            break;
    644668        }
    645669    }
    646670
    647671    // Delete the saved hashes for all turns that we've already verified
    648672    m_ClientStateHashes.erase(m_ClientStateHashes.begin(), m_ClientStateHashes.lower_bound(newest+1));
  • source/network/NetTurnManager.h

     
    105105    virtual void OnSimulationMessage(CSimulationMessage* msg) = 0;
    106106
    107107    /**
    108108     * Called when there has been an out-of-sync error.
    109109     */
    110     virtual void OnSyncError(u32 turn, const std::string& expectedHash);
     110    virtual void OnSyncError(u32 turn, const std::string& expectedHash, std::vector<CStrW>);
    111111
    112112    /**
    113113     * Shows a message box when an out of sync error has been detected in the session or visual replay.
    114114     */
    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);
    116116
    117117    /**
    118118     * Called by simulation code, to add a new command to be distributed to all clients and executed soon.
    119119     */
    120120    virtual void PostCommand(JS::HandleValue data) = 0;
     
    291291public:
    292292    CNetServerTurnManager(CNetServerWorker& server);
    293293
    294294    void NotifyFinishedClientCommands(int client, u32 turn);
    295295
    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);
    297297
    298298    /**
    299299     * Inform the turn manager of a new client who will be sending commands.
    300300     */
    301301    void InitialiseClient(int client, u32 turn);
     
    334334    std::map<int, u32> m_ClientsSimulated;
    335335
    336336    // Map of turn -> {Client ID -> state hash}; old indexes <= min(m_ClientsSimulated) are deleted
    337337    std::map<u32, std::map<int, std::string> > m_ClientStateHashes;
    338338
     339    // Map of client ID -> playername
     340    std::map<u32, CStrW> m_ClientPlayernames;
     341
    339342    // Current turn length
    340343    u32 m_TurnLength;
    341344
    342345    // Turn lengths for all previously executed turns
    343346    std::vector<u32> m_SavedTurnLengths;
    344347
    345348    CNetServerWorker& m_NetServer;
     349
     350    bool m_HasSyncError;
    346351};
    347352
    348353#endif // INCLUDED_NETTURNMANAGER