Ticket #3293: t3293_show_who_is_oos_v1.1_16876.patch

File t3293_show_who_is_oos_v1.1_16876.patch, 11.1 KB (added by elexis, 9 years ago)

Some cleaning (mostly references instead of copies) and added comma to message.

  • 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 std::string& 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 std::string& hash, const std::string& expectedHash, bool isReplay, std::vector<CSyncErrorMessage::S_m_Playernames>* playerNames = NULL, OsPath* path = NULL)
    245246{
    246247    m_HasSyncError = true;
    247248
    248     std::stringstream msg;
    249     msg << "Out of sync on turn " << turn << ": expected hash " << expectedHash << "\n";
     249    std::wstringstream msg;
     250    msg << L"Out of sync on turn " << turn << L"\n";
    250251
    251     if (expectedHash != hash || m_CurrentTurn != turn)
    252         msg << "\nCurrent state: turn " << m_CurrentTurn << ", hash " << hash << "\n\n";
     252    if (playerNames)
     253    {
     254        bool first = true;
     255        msg << L"Players:";
     256        for (const CSyncErrorMessage::S_m_Playernames& playername : *playerNames)
     257        {
     258            if (first)
     259                first = false;
     260            else
     261                msg << L",";
     262            msg << L" " << playername.m_Name;
     263        }
     264        msg << L"\n";
     265    }
    253266
    254267    if (isReplay)
    255         msg << "\nThe current game state is different from the original game state.\n\n";
     268        msg << L"\nThe current game state is different from the original game state.\n\n";
    256269    else
    257270    {
    258271        if (expectedHash == hash)
    259             msg << "Your game state is identical to the hosts game state.\n\n";
     272            msg << L"Your game state is identical to the hosts game state.\n\n";
    260273        else
    261             msg << "Your game state is different from the hosts game state.\n\n";
     274            msg << L"Your game state is different from the hosts game state.\n\n";
    262275    }
    263276
    264277    if (path)
    265         msg << "Dumping current state to " << utf8_from_wstring(OsPath(*path).string());
     278        msg << L"Dumping current state to " << OsPath(*path).string();
    266279
    267     LOGERROR("%s", msg.str());
     280    LOGERROR("%s", utf8_from_wstring(msg.str()));
    268281
    269282    if (g_GUI)
    270         g_GUI->DisplayMessageBox(600, 350, L"Sync error", wstring_from_utf8(msg.str()));
     283        g_GUI->DisplayMessageBox(600, 350, L"Sync error", msg.str());
    271284}
    272285
    273286void CNetTurnManager::Interpolate(float simFrameLength, float realFrameLength)
    274287{
    275288    // TODO: using m_TurnLength might be a bit dodgy when length changes - maybe
     
    428441
    429442    NETTURN_LOG((L"NotifyFinishedUpdate(%d, %hs)\n", turn, Hexify(hash).c_str()));
    430443
    431444    m_Replay.Hash(hash, quick);
    432445
    433     // Send message to the server
    434     CSyncCheckMessage msg;
    435     msg.m_Turn = turn;
    436     msg.m_Hash = hash;
    437     m_NetClient.SendMessage(&msg);
     446    if (!m_HasSyncError)
     447    {
     448        // Send message to the server
     449        CSyncCheckMessage msg;
     450        msg.m_Turn = turn;
     451        msg.m_Hash = hash;
     452        m_NetClient.SendMessage(&msg);
     453    }
    438454}
    439455
    440456void CNetClientTurnManager::OnDestroyConnection()
    441457{
    442458    NotifyFinishedOwnCommands(m_CurrentTurn + COMMAND_DELAY);
     
    550566        AddCommand(m_ClientId, pair.first, command, m_CurrentTurn + 1);
    551567    }
    552568}
    553569
    554570CNetServerTurnManager::CNetServerTurnManager(CNetServerWorker& server) :
    555     m_NetServer(server), m_ReadyTurn(1), m_TurnLength(DEFAULT_TURN_LENGTH_MP)
     571    m_NetServer(server), m_ReadyTurn(1), m_TurnLength(DEFAULT_TURN_LENGTH_MP), m_HasSyncError(false)
    556572{
    557573    // The first turn we will actually execute is number 2,
    558574    // so store dummy values into the saved lengths list
    559575    m_SavedTurnLengths.push_back(0);
    560576    m_SavedTurnLengths.push_back(0);
     
    599615    // Save the turn length in case it's needed later
    600616    ENSURE(m_SavedTurnLengths.size() == m_ReadyTurn);
    601617    m_SavedTurnLengths.push_back(m_TurnLength);
    602618}
    603619
    604 void CNetServerTurnManager::NotifyFinishedClientUpdate(int client, u32 turn, const std::string& hash)
     620void CNetServerTurnManager::NotifyFinishedClientUpdate(int client, const CStrW& playername, u32 turn, const std::string& hash)
    605621{
    606622    // Clients must advance one turn at a time
    607623    ENSURE(turn == m_ClientsSimulated[client] + 1);
    608624    m_ClientsSimulated[client] = turn;
    609625
     626    // Check for oos only if in sync
     627    if (m_HasSyncError)
     628        return;
     629
     630    m_ClientPlayernames[client] = playername;
    610631    m_ClientStateHashes[turn][client] = hash;
    611632
    612633    // Find the newest turn which we know all clients have simulated
    613634    u32 newest = std::numeric_limits<u32>::max();
    614635    for (std::map<int, u32>::iterator it = m_ClientsSimulated.begin(); it != m_ClientsSimulated.end(); ++it)
     
    624645            break;
    625646
    626647        // Assume the host is correct (maybe we should choose the most common instead to help debugging)
    627648        std::string expected = it->second.begin()->second;
    628649
     650        std::vector<CStrW> oos_Playernames;
    629651        for (std::map<int, std::string>::iterator cit = it->second.begin(); cit != it->second.end(); ++cit)
    630652        {
    631653            NETTURN_LOG((L"sync check %d: %d = %hs\n", it->first, cit->first, Hexify(cit->second).c_str()));
    632654            if (cit->second != expected)
    633655            {
    634656                // Oh no, out of sync
     657                m_HasSyncError = true;
     658                oos_Playernames.push_back(m_ClientPlayernames[cit->first]);
     659            }
     660        }
    635661
    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;
     662        // Tell everyone about out it
     663        if (m_HasSyncError)
     664        {
     665            CSyncErrorMessage msg;
     666            msg.m_Turn = it->first;
     667            msg.m_HashExpected = expected;
     668            for (const CStrW& playername : oos_Playernames)
     669            {
     670                CSyncErrorMessage::S_m_Playernames h;
     671                h.m_Name = playername;
     672                msg.m_Playernames.push_back(h);
    643673            }
     674            m_NetServer.Broadcast(&msg);
     675            break;
    644676        }
    645677    }
    646678
    647679    // Delete the saved hashes for all turns that we've already verified
    648680    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 std::string& 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 std::string& hash, const std::string& 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 std::string& 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