Changeset 25170

Timestamp:
Mar 31, 2021, 5:55:19 PM (3 years ago)
Author:
wraitii
Message:

Remember OOS on a per-client basis.

Change the OOS notification logic to remember the OOS-ness of each client. Reset it on client leave.
The server will thus continue checking for OOS if the OOS-client leaves.
This is convenient to ignore observer OOS, or wait for an OOS player without restarting the game.

Also add the turn number to the OOS dump, to fix #3348: particularly following rP25001 the turn is likely to not be the same between different clients.

Agree by: asterix

Differential Revision: https://code.wildfiregames.com/D3753

Location:
ps/trunk/source
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • ps/trunk/source/network/NetClientTurnManager.cpp

    r25003 r25170  
    8585    m_Replay.Hash(hash, quick);
    8686
    87     // Don't send the hash if OOS
    88     if (m_HasSyncError)
    89         return;
    90 
    9187    // Send message to the server
    9288    CSyncCheckMessage msg;
     
    115111    NETCLIENTTURN_LOG("OnSyncError(%d, %hs)\n", turn, expectedHashHex.c_str());
    116112
    117     // Only complain the first time
    118     if (m_HasSyncError)
    119         return;
    120 
    121     m_HasSyncError = true;
    122 
    123113    std::string hash;
    124114    ENSURE(m_Simulation2.ComputeStateHash(hash, !TurnNeedsFullHash(turn)));
     
    126116    OsPath oosdumpPath(psLogDir() / (L"oos_dump" + g_UniqueLogPostfix + L".txt"));
    127117    std::ofstream file (OsString(oosdumpPath).c_str(), std::ofstream::out | std::ofstream::trunc);
     118
     119
    128120    m_Simulation2.DumpDebugState(file);
    129121    file.close();
  • ps/trunk/source/network/NetServerTurnManager.cpp

    r25156 r25170  
    3636
    3737CNetServerTurnManager::CNetServerTurnManager(CNetServerWorker& server)
    38     : m_NetServer(server), m_ReadyTurn(COMMAND_DELAY_MP - 1), m_TurnLength(DEFAULT_TURN_LENGTH), m_HasSyncError(false)
     38    : m_NetServer(server), m_ReadyTurn(COMMAND_DELAY_MP - 1), m_TurnLength(DEFAULT_TURN_LENGTH)
    3939{
    4040    // Turn 0 is not actually executed, store a dummy value.
     
    5353
    5454    // Must be a client we've already heard of
    55     ENSURE(m_ClientsReady.find(client) != m_ClientsReady.end());
     55    ENSURE(m_Clients.end());
    5656
    5757    // Clients must advance one turn at a time
    58     if (turn != m_ClientsReady[client] + 1)
     58    if (turn != m_Clients + 1)
    5959    {
    6060        LOGERROR("NotifyFinishedClientCommands: Client %d (%s) is ready for turn %d, but expected %d",
     
    6262            utf8_from_wstring(session.GetUserName()).c_str(),
    6363            turn,
    64             m_ClientsReady[client] + 1);
     64            m_Clients + 1);
    6565
    6666        session.Disconnect(NDR_INCORRECT_READY_TURN_COMMANDS);
    6767    }
    6868
    69     m_ClientsReady[client] = turn;
     69    m_Clients = turn;
    7070
    7171    // Check whether this was the final client to become ready
     
    8181
    8282    // See if all clients (including self) are ready for a new turn
    83     for (const std::pair<const int, u32>& clientReady : m_ClientsReady)
     83    for (const std::pair<const int, )
    8484    {
    8585        // Observers are allowed to lag more than regular clients.
    86         if (m_ClientsObserver[clientReady.first] && (max_observer_lag == -1 || clientReady.second > m_ReadyTurn - max_observer_lag))
     86        if ( > m_ReadyTurn - max_observer_lag))
    8787            continue;
    8888        NETSERVERTURN_LOG("  %d: %d <=? %d\n", clientReady.first, clientReady.second, m_ReadyTurn);
    89         if (clientReady.second <= m_ReadyTurn)
     89        if (client <= m_ReadyTurn)
    9090            return; // wasn't ready for m_ReadyTurn+1
    9191    }
     
    112112
    113113    // Clients must advance one turn at a time
    114     if (turn != m_ClientsSimulated[client] + 1)
     114    if (turn != m_Clients + 1)
    115115    {
    116116        LOGERROR("NotifyFinishedClientUpdate: Client %d (%s) is ready for turn %d, but expected %d",
     
    118118            utf8_from_wstring(playername).c_str(),
    119119            turn,
    120             m_ClientsReady[client] + 1);
     120            m_Clients + 1);
    121121
    122122        session.Disconnect(NDR_INCORRECT_READY_TURN_SIMULATED);
    123123    }
    124124
    125     m_ClientsSimulated[client] = turn;
     125    m_Clients = turn;
    126126
    127127    // Check for OOS only if in sync
     
    129129        return;
    130130
    131     m_ClientPlayernames[client] = playername;
     131    m_Client = playername;
    132132    m_ClientStateHashes[turn][client] = hash;
    133133
    134134    // Find the newest turn which we know all clients have simulated
    135135    u32 newest = std::numeric_limits<u32>::max();
    136     for (const std::pair<const int, u32>& clientSimulated : m_ClientsSimulated)
    137         if (clientSimulated.second < newest)
    138             newest = clientSimulated.second;
     136    for (const std::pair<const int, )
     137        if (client < newest)
     138            newest = client;
    139139
    140140    // For every set of state hashes that all clients have simulated, check for OOS
     
    156156                // Oh no, out of sync
    157157                m_HasSyncError = true;
    158                 OOSPlayerNames.push_back(m_ClientPlayernames[hashPair.first]);
     158                m_ClientsData[hashPair.first].isOOS = true;
     159                OOSPlayerNames.push_back(m_ClientsData[hashPair.first].playerName);
    159160            }
    160161        }
     
    185186    NETSERVERTURN_LOG("InitialiseClient(client=%d, turn=%d)\n", client, turn);
    186187
    187     ENSURE(m_ClientsReady.find(client) == m_ClientsReady.end());
    188     m_ClientsReady[client] = turn + COMMAND_DELAY_MP - 1;
    189     m_ClientsSimulated[client] = turn;
    190     m_ClientsObserver[client] = observer;
     188    ENSURE(m_ClientsData.find(client) == m_ClientsData.end());
     189    Client& data = m_ClientsData[client];
     190    data.readyTurn = turn + COMMAND_DELAY_MP - 1;
     191    data.simulatedTurn = turn;
     192    data.isObserver = observer;
    191193}
    192194
     
    195197    NETSERVERTURN_LOG("UninitialiseClient(client=%d)\n", client);
    196198
    197     ENSURE(m_ClientsReady.find(client) != m_ClientsReady.end());
    198     m_ClientsReady.erase(client);
    199     m_ClientsSimulated.erase(client);
    200     m_ClientsObserver.erase(client);
     199    ENSURE(m_ClientsData.find(client) != m_ClientsData.end());
     200    bool checkOOS = m_ClientsData[client].isOOS;
     201    m_ClientsData.erase(client);
    201202
    202203    // Check whether we're ready for the next turn now that we're not
    203204    // waiting for this client any more
    204205    CheckClientsReady();
     206
     207
     208
     209
     210
     211
     212
     213
     214
    205215}
    206216
  • ps/trunk/source/network/NetServerTurnManager.h

    r25156 r25170  
    7373    void CheckClientsReady();
    7474
    75     /// The latest turn for which we have received all commands from all clients
    76     u32 m_ReadyTurn;
     75    struct Client
     76    {
     77        CStrW playerName;
     78        // Latest turn for which all commands have been received.
     79        u32 readyTurn;
     80        // Last known simulated turn.
     81        u32 simulatedTurn;
     82        bool isObserver;
     83        bool isOOS = false;
     84    };
    7785
    78     // Client ID -> whether they are only an observer.
    79     std::unordered_map<int, bool> m_ClientsObserver;
     86    std::unordered_map<int, Client> m_ClientsData;
    8087
    81     // Client ID -> ready turn number (the latest turn for which all commands have been received from that client)
    82     std::map<int, u32> m_ClientsReady;
    83 
    84     // Client ID -> last known simulated turn number (for which we have the state hash)
    85     // (the client has reached the start of this turn, not done the update for it yet)
    86     std::map<int, u32> m_ClientsSimulated;
     88    // Cached value - is any client OOS? This is reset when the OOS client leaves.
     89    bool m_HasSyncError = false;
    8790
    8891    // Map of turn -> {Client ID -> state hash}; old indexes <= min(m_ClientsSimulated) are deleted
    8992    std::map<u32, std::map<int, std::string>> m_ClientStateHashes;
    9093
    91     // Map of client ID -> playername
    92     std::map<int, CStrW> m_ClientPlayernames;
     94    //
     95    ;
    9396
    9497    // Current turn length
     
    99102
    100103    CNetServerWorker& m_NetServer;
    101 
    102     bool m_HasSyncError;
    103104};
    104105
  • ps/trunk/source/simulation2/Simulation2.cpp

    r25003 r25170  
    886886bool CSimulation2::DumpDebugState(std::ostream& stream)
    887887{
     888
    888889    return m->m_ComponentManager.DumpDebugState(stream, true);
    889890}
  • ps/trunk/source/simulation2/system/ReplayTurnManager.h

    r24764 r25170  
    1 /* Copyright (C) 2020 Wildfire Games.
     1/* Copyright (C) 202 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
     
    4545    static const CStr EventNameReplayOutOfSync;
    4646
     47
     48
    4749    // Contains the commands of every player on each turn
    4850    std::map<u32, std::vector<std::pair<player_id_t, std::string>>> m_ReplayCommands;
  • ps/trunk/source/simulation2/system/TurnManager.cpp

    r25156 r25170  
    4141CTurnManager::CTurnManager(CSimulation2& simulation, u32 defaultTurnLength, u32 commandDelay, int clientId, IReplayLogger& replay)
    4242    : m_Simulation2(simulation), m_CurrentTurn(0), m_CommandDelay(commandDelay), m_ReadyTurn(commandDelay - 1), m_TurnLength(defaultTurnLength),
    43     m_PlayerId(-1), m_ClientId(clientId), m_DeltaSimTime(0), m_HasSyncError(false), m_Replay(replay),
     43    m_PlayerId(-1), m_ClientId(clientId), m_DeltaSimTime(0), m_Replay(replay),
    4444    m_FinalTurn(std::numeric_limits<u32>::max()), m_TimeWarpNumTurns(0),
    4545    m_QuickSaveMetadata(m_Simulation2.GetScriptInterface().GetGeneralJSContext())
  • ps/trunk/source/simulation2/system/TurnManager.h

    r25156 r25170  
    210210    float m_DeltaSimTime;
    211211
    212     bool m_HasSyncError;
    213 
    214212    IReplayLogger& m_Replay;
    215213
Note: See TracChangeset for help on using the changeset viewer.