Ticket #3293: t3293_show_who_is_oos_v1.2.patch

File t3293_show_who_is_oos_v1.2.patch, 10.9 KB (added by elexis, 9 years ago)

Some cleanup.

  • 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            client->m_ClientTurnManager->OnSyncError(syncMessage->m_Turn, syncMessage->m_HashExpected, syncMessage->m_PlayerNames);
    647647        }
    648648        else if (message->GetType() == NMT_END_COMMAND_BATCH)
    649649        {
    650650            CEndCommandBatchMessage* endMessage = static_cast<CEndCommandBatchMessage*> (message);
    651651            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

     
    1616 */
    1717
    1818#include "precompiled.h"
    1919
    2020#include "NetTurnManager.h"
     21#include "NetMessage.h"
    2122
    2223#include "network/NetServer.h"
    2324#include "network/NetClient.h"
    2425#include "network/NetMessage.h"
    2526
     
    216217    }
    217218
    218219    return true;
    219220}
    220221
    221 void CNetTurnManager::OnSyncError(u32 turn, const std::string& expectedHash)
     222void CNetTurnManager::OnSyncError(u32 turn, const CStr& expectedHash, std::vector<CSyncErrorMessage::S_m_PlayerNames>& playerNames)
    222223{
    223224    NETTURN_LOG((L"OnSyncError(%d, %hs)\n", turn, Hexify(expectedHash).c_str()));
    224225
    225226    // Only complain the first time
    226227    if (m_HasSyncError)
     
    236237    file.close();
    237238
    238239    hash = Hexify(hash);
    239240    const std::string& expectedHashHex = Hexify(expectedHash);
    240241
    241     DisplayOOSError(turn, hash, expectedHashHex, false, &path);
     242    DisplayOOSError(turn, hash, expectedHashHex, false, &playerNames, &path);
    242243}
    243244
    244 void CNetTurnManager::DisplayOOSError(u32 turn, const std::string& hash, const std::string& expectedHash, bool isReplay, OsPath* path = NULL)
     245void CNetTurnManager::DisplayOOSError(u32 turn, const CStr& hash, const CStr& expectedHash, bool isReplay, std::vector<CSyncErrorMessage::S_m_PlayerNames>* playerNames = NULL, OsPath* path = NULL)
    245246{
    246247    m_HasSyncError = true;
    247248
    248249    std::stringstream msg;
    249     msg << "Out of sync on turn " << turn << ": expected hash " << expectedHash << "\n";
     250    msg << "Out of sync on turn " << turn;
    250251
    251     if (expectedHash != hash || m_CurrentTurn != turn)
    252         msg << "\nCurrent state: turn " << m_CurrentTurn << ", hash " << hash << "\n\n";
     252    if (playerNames)
     253        for (size_t i = 0; i < playerNames->size(); ++i)
     254            msg << (i == 0 ? "\nPlayers: " : ", ") << utf8_from_wstring((*playerNames)[i].m_Name);
    253255
    254256    if (isReplay)
    255         msg << "\nThe current game state is different from the original game state.\n\n";
     257        msg << "\n\n" << "The current game state is different from the original game state.";
    256258    else
    257     {
    258         if (expectedHash == hash)
    259             msg << "Your game state is identical to the hosts game state.\n\n";
    260         else
    261             msg << "Your game state is different from the hosts game state.\n\n";
    262     }
     259        msg << "\n\n" << "Your game state is " << (expectedHash == hash ? "identical to" : "different from") << " the hosts game state.";
    263260
    264261    if (path)
    265         msg << "Dumping current state to " << utf8_from_wstring(OsPath(*path).string());
     262        msg << "\n\n" << "Dumping current state to " << OsString(OsPath(*path));
    266263
    267264    LOGERROR("%s", msg.str());
    268265
    269266    if (g_GUI)
    270267        g_GUI->DisplayMessageBox(600, 350, L"Sync error", wstring_from_utf8(msg.str()));
     
    427424
    428425    NETTURN_LOG((L"NotifyFinishedUpdate(%d, %hs)\n", turn, Hexify(hash).c_str()));
    429426
    430427    m_Replay.Hash(hash, quick);
    431428
     429    // Don't send the hash if OOS
     430    if (m_HasSyncError)
     431        return;
     432
    432433    // Send message to the server
    433434    CSyncCheckMessage msg;
    434435    msg.m_Turn = turn;
    435436    msg.m_Hash = hash;
    436437    m_NetClient.SendMessage(&msg);
     
    518519        return;
    519520
    520521    debug_printf("Executing turn %d of %d\n", turn, m_FinalReplayTurn);
    521522    DoTurn(turn);
    522523
    523     // Compare hash if it exists in the replay and if we didn't have an oos already
     524    // Compare hash if it exists in the replay and if we didn't have an OOS already
    524525    if (m_HasSyncError || m_ReplayHash.find(turn) == m_ReplayHash.end())
    525526        return;
    526527
    527528    std::string expectedHash = m_ReplayHash[turn].first;
    528529    bool quickHash = m_ReplayHash[turn].second;
     
    552553    if (turn == m_FinalReplayTurn)
    553554        g_GUI->SendEventToAll("ReplayFinished");
    554555}
    555556
    556557CNetServerTurnManager::CNetServerTurnManager(CNetServerWorker& server) :
    557     m_NetServer(server), m_ReadyTurn(1), m_TurnLength(DEFAULT_TURN_LENGTH_MP)
     558    m_NetServer(server), m_ReadyTurn(1), m_TurnLength(DEFAULT_TURN_LENGTH_MP), m_HasSyncError(false)
    558559{
    559560    // The first turn we will actually execute is number 2,
    560561    // so store dummy values into the saved lengths list
    561562    m_SavedTurnLengths.push_back(0);
    562563    m_SavedTurnLengths.push_back(0);
     
    601602    // Save the turn length in case it's needed later
    602603    ENSURE(m_SavedTurnLengths.size() == m_ReadyTurn);
    603604    m_SavedTurnLengths.push_back(m_TurnLength);
    604605}
    605606
    606 void CNetServerTurnManager::NotifyFinishedClientUpdate(int client, u32 turn, const std::string& hash)
     607void CNetServerTurnManager::NotifyFinishedClientUpdate(int client, const CStrW& playername, u32 turn, const CStr& hash)
    607608{
    608609    // Clients must advance one turn at a time
    609610    ENSURE(turn == m_ClientsSimulated[client] + 1);
    610611    m_ClientsSimulated[client] = turn;
    611612
     613    // Check for OOS only if in sync
     614    if (m_HasSyncError)
     615        return;
     616
     617    m_ClientPlayernames[client] = playername;
    612618    m_ClientStateHashes[turn][client] = hash;
    613619
    614620    // Find the newest turn which we know all clients have simulated
    615621    u32 newest = std::numeric_limits<u32>::max();
    616622    for (std::map<int, u32>::iterator it = m_ClientsSimulated.begin(); it != m_ClientsSimulated.end(); ++it)
     
    626632            break;
    627633
    628634        // Assume the host is correct (maybe we should choose the most common instead to help debugging)
    629635        std::string expected = it->second.begin()->second;
    630636
     637        // Find all players that are OOS on that turn
     638        std::vector<CStrW> OOSPlayerNames;
    631639        for (std::map<int, std::string>::iterator cit = it->second.begin(); cit != it->second.end(); ++cit)
    632640        {
    633641            NETTURN_LOG((L"sync check %d: %d = %hs\n", it->first, cit->first, Hexify(cit->second).c_str()));
    634642            if (cit->second != expected)
    635643            {
    636644                // Oh no, out of sync
     645                m_HasSyncError = true;
     646                OOSPlayerNames.push_back(m_ClientPlayernames[cit->first]);
     647            }
     648        }
    637649
    638                 // Tell everyone about it
    639                 CSyncErrorMessage msg;
    640                 msg.m_Turn = it->first;
    641                 msg.m_HashExpected = expected;
    642                 m_NetServer.Broadcast(&msg);
    643 
    644                 break;
     650        // Tell everyone about it
     651        if (m_HasSyncError)
     652        {
     653            CSyncErrorMessage msg;
     654            msg.m_Turn = it->first;
     655            msg.m_HashExpected = expected;
     656            for (const CStrW& playername : OOSPlayerNames)
     657            {
     658                CSyncErrorMessage::S_m_PlayerNames h;
     659                h.m_Name = playername;
     660                msg.m_PlayerNames.push_back(h);
    645661            }
     662            m_NetServer.Broadcast(&msg);
     663            break;
    646664        }
    647665    }
    648666
    649667    // Delete the saved hashes for all turns that we've already verified
    650668    m_ClientStateHashes.erase(m_ClientStateHashes.begin(), m_ClientStateHashes.lower_bound(newest+1));
  • source/network/NetTurnManager.h

     
    1818#ifndef INCLUDED_NETTURNMANAGER
    1919#define INCLUDED_NETTURNMANAGER
    2020
    2121#include "simulation2/helpers/SimulationCommand.h"
    2222#include "lib/os_path.h"
     23#include "NetMessage.h"
    2324
    2425#include <list>
    2526#include <map>
    2627#include <vector>
    2728
     
    105106    virtual void OnSimulationMessage(CSimulationMessage* msg) = 0;
    106107
    107108    /**
    108109     * Called when there has been an out-of-sync error.
    109110     */
    110     virtual void OnSyncError(u32 turn, const std::string& expectedHash);
     111    virtual void OnSyncError(u32 turn, const CStr& expectedHash, std::vector<CSyncErrorMessage::S_m_PlayerNames>& playerNames);
    111112
    112113    /**
    113114     * Shows a message box when an out of sync error has been detected in the session or visual replay.
    114115     */
    115     virtual void DisplayOOSError(u32 turn, const std::string& hash, const std::string& expectedHash, bool isReplay, OsPath* path);
     116    virtual void DisplayOOSError(u32 turn, const CStr& hash, const CStr& expectedHash, bool isReplay, std::vector<CSyncErrorMessage::S_m_PlayerNames>* playerNames, OsPath* path);
    116117
    117118    /**
    118119     * Called by simulation code, to add a new command to be distributed to all clients and executed soon.
    119120     */
    120121    virtual void PostCommand(JS::HandleValue data) = 0;
     
    291292public:
    292293    CNetServerTurnManager(CNetServerWorker& server);
    293294
    294295    void NotifyFinishedClientCommands(int client, u32 turn);
    295296
    296     void NotifyFinishedClientUpdate(int client, u32 turn, const std::string& hash);
     297    void NotifyFinishedClientUpdate(int client, const CStrW& playername, u32 turn, const CStr& hash);
    297298
    298299    /**
    299300     * Inform the turn manager of a new client who will be sending commands.
    300301     */
    301302    void InitialiseClient(int client, u32 turn);
     
    334335    std::map<int, u32> m_ClientsSimulated;
    335336
    336337    // Map of turn -> {Client ID -> state hash}; old indexes <= min(m_ClientsSimulated) are deleted
    337338    std::map<u32, std::map<int, std::string> > m_ClientStateHashes;
    338339
     340    // Map of client ID -> playername
     341    std::map<u32, CStrW> m_ClientPlayernames;
     342
    339343    // Current turn length
    340344    u32 m_TurnLength;
    341345
    342346    // Turn lengths for all previously executed turns
    343347    std::vector<u32> m_SavedTurnLengths;
    344348
    345349    CNetServerWorker& m_NetServer;
     350
     351    bool m_HasSyncError;
    346352};
    347353
    348354#endif // INCLUDED_NETTURNMANAGER