Ticket #1950: pausing.patch

File pausing.patch, 14.2 KB (added by echotangoecho, 8 years ago)
  • binaries/data/mods/public/gui/common/functions_global_object.js

     
    149149    let messages = [];
    150150    let maxTextWidth = 0;
    151151
    152     // TODO: Players who paused the game should be added here
    153 
    154152    // Add network warnings
    155153    if (Engine.ConfigDB_GetValue("user", "overlay.netwarnings") == "true")
    156154    {
  • binaries/data/mods/public/gui/session/menu.js

     
    682682    Engine.SetPaused(true);
    683683}
    684684
     685/**
     686 * Resume the game in single player mode.
     687 */
    685688function resumeGame()
    686689{
     690    if (g_IsNetworked)
     691        return;
     692
    687693    Engine.GetGUIObjectByName("pauseButtonText").caption = translate("Pause");
    688694    Engine.GetGUIObjectByName("pauseOverlay").hidden = true;
    689695    Engine.SetPaused(false);
     
    696702
    697703    closeOpenDialogs();
    698704
     705    Engine.GetGUIObjectByName("pauseOverlayNotPausing").hidden = true;
     706
    699707    let pauseOverlay = Engine.GetGUIObjectByName("pauseOverlay");
    700708
    701709    Engine.SetPaused(pauseOverlay.hidden);
  • binaries/data/mods/public/gui/session/messages.js

     
    2525var g_ChatTimers = [];
    2626
    2727/**
     28 * The list of GUIDs of players who have currently paused the game.
     29 */
     30var g_PausingPlayers = [];
     31
     32/**
    2833 * Handle all netmessage types that can occur.
    2934 */
    3035var g_NetMessageTypes = {
     
    3136    "netstatus": msg => handleNetStatusMessage(msg),
    3237    "netwarn": msg => addNetworkWarning(msg),
    3338    "players": msg => handlePlayerAssignmentsMessage(msg),
     39    "paused": msg => handlePlayerPausedMessage(msg),
    3440    "rejoined": msg => addChatMessage({ "type": "rejoined", "guid": msg.guid }),
    3541    "kicked": msg => addChatMessage({ "type": "system", "text": sprintf(translate("%(username)s has been kicked"), { "username": msg.username }) }),
    3642    "banned": msg => addChatMessage({ "type": "system", "text": sprintf(translate("%(username)s has been banned"), { "username": msg.username }) }),
     
    496502    }
    497503}
    498504
     505function handlePlayerPausedMessage(message)
     506{
     507    // Update list of pausing players.
     508    if (message.pause)
     509        g_PausingPlayers.push(message.guid);
     510    else
     511        g_PausingPlayers.splice(g_PausingPlayers.indexOf(message.guid));
     512
     513    var pausingListText = "";
     514
     515    g_PausingPlayers.forEach(player => {
     516        pausingListText += colorizePlayernameByGUID(player) + "\n";
     517    });
     518
     519    Engine.GetGUIObjectByName("pausingListText").caption = pausingListText;
     520
     521    // Display the overlay for players who didn't pause the game.
     522    if (g_PausingPlayers.indexOf(Engine.GetPlayerGUID()) == -1)
     523    {
     524        let pauseOverlay = Engine.GetGUIObjectByName("pauseOverlayNotPausing");
     525
     526        closeOpenDialogs();
     527
     528        pauseOverlay.hidden = g_PausingPlayers.length == 0 || g_PausingPlayers == null;
     529        Engine.PauseLocalSimulation(!pauseOverlay.hidden);
     530    }
     531}
     532
    499533function updateChatAddressees()
    500534{
    501535    let addressees = [
  • binaries/data/mods/public/gui/session/session.xml

     
    192192    </object>
    193193
    194194    <!-- ================================  ================================ -->
     195    <!-- Pause Overlay for other players who have not paused. -->
     196    <!-- ================================  ================================ -->
     197    <object name="pauseOverlayNotPausing" size="0 0 100% 100%" type="image" sprite="devCommandsBackground" ghost="false" hidden="true" z="0">
     198        <object size="50%-128 50%-20 50%+128 50%+20" type="text" style="PauseText" ghost="true" z="0">
     199            <translatableAttribute id="caption">Game Paused by:</translatableAttribute>
     200        </object>
     201
     202        <object name="pausingListText" size="50%-128 50%+20 50%+128 80%" type="text" style="PausingListText" ghost="true" z="0"/>
     203    </object>
     204
     205    <!-- ================================  ================================ -->
    195206    <!-- Notification Area -->
    196207    <!-- ================================  ================================ -->
    197208    <object name="notificationPanel" type="image" size="50%-300 60 50%+300 120" ghost="true">
  • binaries/data/mods/public/gui/session/styles.xml

     
    1919       text_valign="center"
    2020    />
    2121
     22    <style name="PausingListText"
     23       font="sans-stroke-16"
     24       textcolor="white"
     25       text_align="center"
     26       text_valign="top"
     27    />
     28
    2229    <style name="BuildNameText"
    2330       font="sans-stroke-12"
    2431       textcolor="white"
  • source/gui/scripting/ScriptFunctions.cpp

     
    780780        return;
    781781    }
    782782    g_Game->m_Paused = pause;
     783
     784    // Only send a message over the network if the game is networked.
     785    if (g_NetClient)
     786        g_NetClient->SendPausedMessage(pause);
     787
    783788#if CONFIG2_AUDIO
    784789    if (g_SoundManager)
    785790        g_SoundManager->Pause(pause);
     
    786791#endif
    787792}
    788793
     794// Pause the local simulation (does not send a paused message over the network).
     795void PauseLocalSimulation(ScriptInterface::CxPrivate* pCxPrivate, bool pause)
     796{
     797    if (!g_Game)
     798    {
     799        JS_ReportError(pCxPrivate->pScriptInterface->GetContext(), "Game is not started");
     800        return;
     801    }
     802    g_Game->m_Paused = pause;
     803
     804#if CONFIG2_AUDIO
     805    if (g_SoundManager)
     806        g_SoundManager->Pause(pause);
     807#endif
     808}
     809
    789810// Return the global frames-per-second value.
    790811// params:
    791812// returns: FPS [int]
     
    10881109    scriptInterface.RegisterFunction<void, &ExitProgram>("Exit");
    10891110    scriptInterface.RegisterFunction<bool, &IsPaused>("IsPaused");
    10901111    scriptInterface.RegisterFunction<void, bool, &SetPaused>("SetPaused");
     1112    scriptInterface.RegisterFunction<void, bool, &PauseLocalSimulation>("PauseLocalSimulation");
    10911113    scriptInterface.RegisterFunction<int, &GetFps>("GetFPS");
    10921114    scriptInterface.RegisterFunction<std::wstring, int, &GetBuildTimestamp>("GetBuildTimestamp");
    10931115    scriptInterface.RegisterFunction<JS::Value, std::wstring, &ReadJSONFile>("ReadJSONFile");
  • source/network/NetClient.cpp

     
    121121    AddTransition(NCS_INGAME, (uint)NMT_KICKED, NCS_INGAME, (void*)&OnKicked, context);
    122122    AddTransition(NCS_INGAME, (uint)NMT_CLIENT_TIMEOUT, NCS_INGAME, (void*)&OnClientTimeout, context);
    123123    AddTransition(NCS_INGAME, (uint)NMT_CLIENT_PERFORMANCE, NCS_INGAME, (void*)&OnClientPerformance, context);
     124    AddTransition(NCS_INGAME, (uint)NMT_CLIENT_PAUSED, NCS_INGAME, (void*)&OnClientPaused, context);
    124125    AddTransition(NCS_INGAME, (uint)NMT_CHAT, NCS_INGAME, (void*)&OnChat, context);
    125126    AddTransition(NCS_INGAME, (uint)NMT_GAME_SETUP, NCS_INGAME, (void*)&OnGameSetup, context);
    126127    AddTransition(NCS_INGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_INGAME, (void*)&OnPlayerAssignment, context);
     
    340341    SendMessage(&rejoinedMessage);
    341342}
    342343
     344void CNetClient::SendPausedMessage(bool pause)
     345{
     346    CClientPausedMessage pausedMessage;
     347    pausedMessage.m_Pause = pause;
     348    SendMessage(&pausedMessage);
     349}
     350
    343351bool CNetClient::HandleMessage(CNetMessage* message)
    344352{
    345353    // Handle non-FSM messages first
     
    725733    return true;
    726734}
    727735
     736bool CNetClient::OnClientPaused(void *context, CFsmEvent *event)
     737{
     738    ENSURE(event->GetType() == (uint)NMT_CLIENT_PAUSED);
     739
     740    CNetClient* client = (CNetClient*)context;
     741    JSContext* cx = client->GetScriptInterface().GetContext();
     742    CClientPausedMessage* message = (CClientPausedMessage*)event->GetParamRef();
     743
     744    JS::RootedValue msg(cx);
     745    client->GetScriptInterface().Eval("({ 'type':'paused' })", &msg);
     746    client->GetScriptInterface().SetProperty(msg, "pause", message->m_Pause);
     747    client->GetScriptInterface().SetProperty(msg, "guid", message->m_GUID);
     748    client->PushGuiMessage(msg);
     749
     750    return true;
     751}
     752
    728753bool CNetClient::OnLoadedGame(void* context, CFsmEvent* event)
    729754{
    730755    ENSURE(event->GetType() == (uint)NMT_LOADED_GAME);
  • source/network/NetClient.h

     
    197197     */
    198198    void SendRejoinedMessage();
    199199
     200    /**
     201     * Call when the client has paused or unpaused the game.
     202     */
     203    void SendPausedMessage(bool pause);
     204
    200205private:
    201206    // Net message / FSM transition handlers
    202207    static bool OnConnect(void* context, CFsmEvent* event);
     
    215220    static bool OnKicked(void* context, CFsmEvent* event);
    216221    static bool OnClientTimeout(void* context, CFsmEvent* event);
    217222    static bool OnClientPerformance(void* context, CFsmEvent* event);
     223    static bool OnClientPaused(void* context, CFsmEvent* event);
    218224    static bool OnLoadedGame(void* context, CFsmEvent* event);
    219225
    220226    /**
  • source/network/NetMessage.cpp

     
    147147        pNewMessage = new CClientPerformanceMessage;
    148148        break;
    149149
     150    case NMT_CLIENT_PAUSED:
     151        pNewMessage = new CClientPausedMessage;
     152        break;
     153
    150154    case NMT_LOADED_GAME:
    151155        pNewMessage = new CLoadedGameMessage;
    152156        break;
  • source/network/NetMessages.h

     
    2828
    2929#define PS_PROTOCOL_MAGIC               0x5073013f      // 'P', 's', 0x01, '?'
    3030#define PS_PROTOCOL_MAGIC_RESPONSE      0x50630121      // 'P', 'c', 0x01, '!'
    31 #define PS_PROTOCOL_VERSION             0x01010011      // Arbitrary protocol
     31#define PS_PROTOCOL_VERSION             0x01010012      // Arbitrary protocol
    3232#define PS_DEFAULT_PORT                 0x5073          // 'P', 's'
    3333
    3434// Defines the list of message types. The order of the list must not change.
     
    6262
    6363    NMT_CLIENT_TIMEOUT,
    6464    NMT_CLIENT_PERFORMANCE,
     65    NMT_CLIENT_PAUSED,
    6566
    6667    NMT_LOADED_GAME,
    6768    NMT_GAME_START,
     
    182183    NMT_END_ARRAY()
    183184END_NMT_CLASS()
    184185
     186START_NMT_CLASS_(ClientPaused, NMT_CLIENT_PAUSED)
     187    NMT_FIELD(CStr, m_GUID)
     188    NMT_FIELD_INT(m_Pause, u8, 1)
     189END_NMT_CLASS()
     190
    185191START_NMT_CLASS_(LoadedGame, NMT_LOADED_GAME)
    186192    NMT_FIELD_INT(m_CurrentTurn, u32, 4)
    187193END_NMT_CLASS()
  • source/network/NetServer.cpp

     
    661661    session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnJoinSyncingLoadedGame, context);
    662662
    663663    session->AddTransition(NSS_INGAME, (uint)NMT_REJOINED, NSS_INGAME, (void*)&OnRejoined, context);
     664    session->AddTransition(NSS_INGAME, (uint)NMT_CLIENT_PAUSED, NSS_INGAME, (void*)&OnClientPaused, context);
    664665    session->AddTransition(NSS_INGAME, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context);
    665666    session->AddTransition(NSS_INGAME, (uint)NMT_CHAT, NSS_INGAME, (void*)&OnChat, context);
    666667    session->AddTransition(NSS_INGAME, (uint)NMT_SIMULATION_COMMAND, NSS_INGAME, (void*)&OnInGame, context);
     
    704705
    705706void CNetServerWorker::OnUserLeave(CNetServerSession* session)
    706707{
     708    std::vector<CStr>::iterator pausing = std::find(m_PausingPlayers.begin(), m_PausingPlayers.end(), session->GetGUID());
     709    if (pausing != m_PausingPlayers.end())
     710    {
     711        // Unpause for the leaving player.
     712        m_PausingPlayers.erase(pausing);
     713
     714        CClientPausedMessage pausedMsg;
     715        pausedMsg.m_GUID = session->GetGUID();
     716        pausedMsg.m_Pause = false;
     717        Broadcast(&pausedMsg);
     718    }
     719
    707720    RemovePlayer(session->GetGUID());
    708721
    709722    if (m_ServerTurnManager && session->GetCurrState() != NSS_JOIN_SYNCING)
     
    12061219    return true;
    12071220}
    12081221
     1222bool CNetServerWorker::OnClientPaused(void *context, CFsmEvent *event)
     1223{
     1224    ENSURE(event->GetType() == (uint)NMT_CLIENT_PAUSED);
     1225
     1226    CNetServerSession* session = (CNetServerSession*)context;
     1227    CNetServerWorker& server = session->GetServer();
     1228
     1229    CClientPausedMessage* message = (CClientPausedMessage*)event->GetParamRef();
     1230
     1231    message->m_GUID = session->GetGUID();
     1232
     1233    // Update the list of pausing players.
     1234    std::vector<CStr>::iterator player = std::find(server.m_PausingPlayers.begin(), server.m_PausingPlayers.end(), session->GetGUID());
     1235
     1236    if (message->m_Pause)
     1237    {
     1238        if (player != server.m_PausingPlayers.end())
     1239        {
     1240            LOGERROR("Player paused, but is already included in the list of paused players on the server.");
     1241            return true;
     1242        }
     1243
     1244        server.m_PausingPlayers.push_back(session->GetGUID());
     1245    }
     1246    else
     1247    {
     1248        if (player == server.m_PausingPlayers.end())
     1249        {
     1250            LOGERROR("Player unpaused, but is not included in the list of paused players on the server.");
     1251            return true;
     1252        }
     1253
     1254        server.m_PausingPlayers.erase(player);
     1255    }
     1256
     1257    server.Broadcast(message);
     1258
     1259    return true;
     1260}
     1261
    12091262void CNetServerWorker::CheckGameLoadStatus(CNetServerSession* changedSession)
    12101263{
    12111264    for (const CNetServerSession* session : m_Sessions)
  • source/network/NetServer.h

     
    274274    static bool OnJoinSyncingLoadedGame(void* context, CFsmEvent* event);
    275275    static bool OnRejoined(void* context, CFsmEvent* event);
    276276    static bool OnDisconnect(void* context, CFsmEvent* event);
     277    static bool OnClientPaused(void* context, CFsmEvent* event);
    277278
    278279    void CheckGameLoadStatus(CNetServerSession* changedSession);
    279280
     
    316317    std::vector<CStr> m_BannedIPs;
    317318    std::vector<CStrW> m_BannedPlayers;
    318319
     320    /**
     321     * Holds the GUIDs of all currently paused players.
     322     */
     323    std::vector<CStr> m_PausingPlayers;
     324
    319325    u32 m_NextHostID;
    320326
    321327    CNetServerTurnManager* m_ServerTurnManager;