Ticket #1949: rejoined_message_v3.patch

File rejoined_message_v3.patch, 32.6 KB (added by elexis, 9 years ago)

Removed braces in loading.js, moved c++ functions to more logical place. Tested with r16528.

  • binaries/data/mods/public/gui/gamesetup/gamesetup_mp.js

     
    9494                    return;
    9595
    9696                default:
    9797                    error(sprintf("Unrecognised netstatus type %(netType)s", { netType: message.status }));
    9898                    break;
    9999                }
    100100                break;
    101101
    102102            case "gamesetup":
    103103                g_GameAttributes = message.data;
    104104                break;
    105105
    106106            case "players":
    107107                g_PlayerAssignments = message.hosts;
    108108                break;
    109109
    110110            case "start":
    111111                Engine.SwitchGuiPage("page_loading.xml", {
    112112                    "attribs": g_GameAttributes,
    113113                    "isNetworked" : true,
     114                    "isRejoining" : g_IsRejoining,
    114115                    "playerAssignments": g_PlayerAssignments
    115116                });
    116117                break;
    117118
    118119            case "chat":
    119120                // Ignore, since we have nowhere to display chat messages
    120121                break;
    121122
    122123            default:
    123124                error(sprintf("Unrecognised net message type %(messageType)s", { messageType: message.type }));
    124125            }
    125126        }
    126127        else
    127128        {
    128129            // Not rejoining - just trying to connect to server
    129130
    130131            switch (message.type)
    131132            {
    132133            case "netstatus":
    133134                switch (message.status)
  • binaries/data/mods/public/gui/loading/loading.js

     
    9696        rightSide.size = size;
    9797    }
    9898}
    9999
    100100// ====================================================================
    101101function reallyStartGame()
    102102{
    103103    // Stop the music
    104104//  if (global.curr_music)
    105105//      global.curr_music.fade(-1, 0.0, 5.0); // fade to 0 over 5 seconds
    106106
    107107
    108108    // This is a reserved function name that is executed by the engine when it is ready
    109109    // to start the game (i.e. loading progress has reached 100%).
    110110
    111111    // Switch GUI from loading screen to game session.
    112112    Engine.SwitchGuiPage("page_session.xml", g_Data);
    113113
    114114    // Restore default cursor.
    115115    Engine.SetCursor("arrow-default");
     116   
     117    // Notify the other clients that we have finished the loading screen
     118    if (g_Data.isNetworked && g_Data.isRejoining)
     119        Engine.SendNetworkRejoined();
    116120}
  • binaries/data/mods/public/gui/session/messages.js

     
    274274            }
    275275        }
    276276
    277277        g_PlayerAssignments = message.hosts;
    278278
    279279        if (g_IsController && Engine.HasXmppClient())
    280280        {
    281281            var players = [ assignment.name for each (assignment in g_PlayerAssignments) ]
    282282            Engine.SendChangeStateGame(Object.keys(g_PlayerAssignments).length, players.join(", "));
    283283        }
    284284
    285285        break;
    286286
    287287    case "chat":
    288288        addChatMessage({ "type": "message", "guid": message.guid, "text": message.text });
    289289        break;
    290290
    291291    case "aichat":
    292292        addChatMessage({ "type": "message", "guid": message.guid, "text": message.text, "translate": true });
    293293        break;
    294 
     294       
     295    case "rejoined":
     296        addChatMessage({ "type": "rejoined", "guid": message.guid});
     297        break;
     298       
    295299    // To prevent errors, ignore these message types that occur during autostart
    296300    case "gamesetup":
    297301    case "start":
    298302        break;
    299303
    300304    default:
    301305        error("Unrecognised net message type '" + message.type + "'");
    302306    }
    303307}
    304308
    305309function submitChatDirectly(text)
    306310{
    307311    if (text.length)
    308312    {
    309313        if (g_IsNetworked)
    310314            Engine.SendNetworkChat(text);
    311315        else
    312316            addChatMessage({ "type": "message", "guid": "local", "text": text });
    313317    }
    314318}
     
    414418    else if (msg.type == "defeat" && msg.player)
    415419    {
    416420        [username, playerColor] = getUsernameAndColor(msg.player);
    417421    }
    418422    else if (msg.type == "message")
    419423    {
    420424        [username, playerColor] = getUsernameAndColor(msg.player);
    421425        parseChatCommands(msg, playerAssignments);
    422426    }
    423427    else
    424428    {
    425429        playerColor = "255 255 255";
    426430        username = translate("Unknown player");
    427431    }
    428432
    429433    var formatted;
    430434
    431435    switch (msg.type)
    432436    {
    433437    case "connect":
    434         formatted = sprintf(translate("%(player)s has joined the game."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
     438        formatted = sprintf(translate("%(player)s is connecting..."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
    435439        break;
    436440    case "disconnect":
    437441        formatted = sprintf(translate("%(player)s has left the game."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
    438442        break;
     443    case "rejoined":
     444        formatted = sprintf(translate("%(player)s has rejoined the game."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
     445        break;
    439446    case "defeat":
    440447        // In singleplayer, the local player is "You". "You has" is incorrect.
    441448        if (!g_IsNetworked && msg.player == Engine.GetPlayerID())
    442449            formatted = translate("You have been defeated.");
    443450        else
    444451            formatted = sprintf(translate("%(player)s has been defeated."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
    445452        break;
    446453    case "diplomacy":
    447454        var status = (msg.status == "ally" ? "allied" : (msg.status == "enemy" ? "at war" : "neutral"));
    448455        if (msg.player == Engine.GetPlayerID())
    449456        {
    450457            [username, playerColor] = getUsernameAndColor(msg.player1);
    451458            if (msg.status == "ally")
    452459                formatted = sprintf(translate("You are now allied with %(player)s."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
    453460            else if (msg.status == "enemy")
    454461                formatted = sprintf(translate("You are now at war with %(player)s."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
    455462            else // (msg.status == "neutral")
    456463                formatted = sprintf(translate("You are now neutral with %(player)s."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
    457464        }
    458465        else if (msg.player1 == Engine.GetPlayerID())
  • source/gui/scripting/ScriptFunctions.cpp

     
    371371{
    372372    ENSURE(g_NetServer);
    373373
    374374    g_NetServer->SetPlayerReady(guid, ready);
    375375}
    376376
    377377void ClearAllPlayerReady (ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
    378378{
    379379    ENSURE(g_NetServer);
    380380
    381381    g_NetServer->ClearAllPlayerReady();
    382382}
    383383
    384384void SendNetworkChat(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::wstring message)
    385385{
    386386    ENSURE(g_NetClient);
    387387
    388388    g_NetClient->SendChatMessage(message);
    389389}
    390390
     391void SendNetworkRejoined(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
     392{
     393    ENSURE(g_NetClient);
     394
     395    g_NetClient->SendRejoinedMessage();
     396}
     397
    391398void SendNetworkReady(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int message)
    392399{
    393400    ENSURE(g_NetClient);
    394401
    395402    g_NetClient->SendReadyMessage(message);
    396403}
    397404
    398405JS::Value GetAIs(ScriptInterface::CxPrivate* pCxPrivate)
    399406{
    400407    return ICmpAIManager::GetAIs(*(pCxPrivate->pScriptInterface));
    401408}
    402409
    403410JS::Value GetSavedGames(ScriptInterface::CxPrivate* pCxPrivate)
    404411{
    405412    return SavedGames::GetSavedGames(*(pCxPrivate->pScriptInterface));
    406413}
    407414
    408415bool DeleteSavedGame(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::wstring name)
    409416{
    410417    return SavedGames::DeleteSavedGame(name);
     
    934941    scriptInterface.RegisterFunction<entity_id_t, int, int, &PickEntityAtPoint>("PickEntityAtPoint");
    935942    scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, int, int, int, int, &PickFriendlyEntitiesInRect>("PickFriendlyEntitiesInRect");
    936943    scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, &PickFriendlyEntitiesOnScreen>("PickFriendlyEntitiesOnScreen");
    937944    scriptInterface.RegisterFunction<std::vector<entity_id_t>, std::string, bool, bool, bool, &PickSimilarFriendlyEntities>("PickSimilarFriendlyEntities");
    938945    scriptInterface.RegisterFunction<CFixedVector3D, int, int, &GetTerrainAtScreenPoint>("GetTerrainAtScreenPoint");
    939946
    940947    // Network / game setup functions
    941948    scriptInterface.RegisterFunction<void, &StartNetworkGame>("StartNetworkGame");
    942949    scriptInterface.RegisterFunction<void, JS::HandleValue, int, &StartGame>("StartGame");
    943950    scriptInterface.RegisterFunction<void, &Script_EndGame>("EndGame");
    944951    scriptInterface.RegisterFunction<void, std::wstring, &StartNetworkHost>("StartNetworkHost");
    945952    scriptInterface.RegisterFunction<void, std::wstring, std::string, &StartNetworkJoin>("StartNetworkJoin");
    946953    scriptInterface.RegisterFunction<void, &DisconnectNetworkGame>("DisconnectNetworkGame");
    947954    scriptInterface.RegisterFunction<JS::Value, &PollNetworkClient>("PollNetworkClient");
    948955    scriptInterface.RegisterFunction<void, JS::HandleValue, &SetNetworkGameAttributes>("SetNetworkGameAttributes");
    949956    scriptInterface.RegisterFunction<void, int, std::string, &AssignNetworkPlayer>("AssignNetworkPlayer");
    950957    scriptInterface.RegisterFunction<void, std::string, int, &SetNetworkPlayerStatus>("SetNetworkPlayerStatus");
    951958    scriptInterface.RegisterFunction<void, &ClearAllPlayerReady>("ClearAllPlayerReady");
    952959    scriptInterface.RegisterFunction<void, std::wstring, &SendNetworkChat>("SendNetworkChat");
    953960    scriptInterface.RegisterFunction<void, int, &SendNetworkReady>("SendNetworkReady");
     961    scriptInterface.RegisterFunction<void, &SendNetworkRejoined>("SendNetworkRejoined");
    954962    scriptInterface.RegisterFunction<JS::Value, &GetAIs>("GetAIs");
    955963    scriptInterface.RegisterFunction<JS::Value, &GetEngineInfo>("GetEngineInfo");
    956964
    957965    // Saved games
    958966    scriptInterface.RegisterFunction<JS::Value, std::wstring, &StartSavedGame>("StartSavedGame");
    959967    scriptInterface.RegisterFunction<JS::Value, &GetSavedGames>("GetSavedGames");
    960968    scriptInterface.RegisterFunction<bool, std::wstring, &DeleteSavedGame>("DeleteSavedGame");
    961969    scriptInterface.RegisterFunction<void, std::wstring, std::wstring, JS::HandleValue, &SaveGame>("SaveGame");
    962970    scriptInterface.RegisterFunction<void, std::wstring, std::wstring, JS::HandleValue, &SaveGamePrefix>("SaveGamePrefix");
    963971    scriptInterface.RegisterFunction<void, &QuickSave>("QuickSave");
    964972    scriptInterface.RegisterFunction<void, &QuickLoad>("QuickLoad");
    965973
    966974    // Misc functions
    967975    scriptInterface.RegisterFunction<std::wstring, std::wstring, &SetCursor>("SetCursor");
    968976    scriptInterface.RegisterFunction<int, &GetPlayerID>("GetPlayerID");
    969977    scriptInterface.RegisterFunction<void, int, &SetPlayerID>("SetPlayerID");
    970978    scriptInterface.RegisterFunction<void, std::string, &OpenURL>("OpenURL");
    971979    scriptInterface.RegisterFunction<std::wstring, &GetMatchID>("GetMatchID");
    972980    scriptInterface.RegisterFunction<void, &RestartInAtlas>("RestartInAtlas");
    973981    scriptInterface.RegisterFunction<bool, &AtlasIsAvailable>("AtlasIsAvailable");
  • source/network/NetClient.cpp

     
    9898
    9999    AddTransition(NCS_JOIN_SYNCING, (uint)NMT_CHAT, NCS_JOIN_SYNCING, (void*)&OnChat, context);
    100100    AddTransition(NCS_JOIN_SYNCING, (uint)NMT_GAME_SETUP, NCS_JOIN_SYNCING, (void*)&OnGameSetup, context);
    101101    AddTransition(NCS_JOIN_SYNCING, (uint)NMT_PLAYER_ASSIGNMENT, NCS_JOIN_SYNCING, (void*)&OnPlayerAssignment, context);
    102102    AddTransition(NCS_JOIN_SYNCING, (uint)NMT_GAME_START, NCS_JOIN_SYNCING, (void*)&OnGameStart, context);
    103103    AddTransition(NCS_JOIN_SYNCING, (uint)NMT_SIMULATION_COMMAND, NCS_JOIN_SYNCING, (void*)&OnInGame, context);
    104104    AddTransition(NCS_JOIN_SYNCING, (uint)NMT_END_COMMAND_BATCH, NCS_JOIN_SYNCING, (void*)&OnJoinSyncEndCommandBatch, context);
    105105    AddTransition(NCS_JOIN_SYNCING, (uint)NMT_LOADED_GAME, NCS_INGAME, (void*)&OnLoadedGame, context);
    106106
    107107    AddTransition(NCS_LOADING, (uint)NMT_CHAT, NCS_LOADING, (void*)&OnChat, context);
    108108    AddTransition(NCS_LOADING, (uint)NMT_GAME_SETUP, NCS_LOADING, (void*)&OnGameSetup, context);
    109109    AddTransition(NCS_LOADING, (uint)NMT_PLAYER_ASSIGNMENT, NCS_LOADING, (void*)&OnPlayerAssignment, context);
    110110    AddTransition(NCS_LOADING, (uint)NMT_LOADED_GAME, NCS_INGAME, (void*)&OnLoadedGame, context);
    111111
    112112    AddTransition(NCS_INGAME, (uint)NMT_CHAT, NCS_INGAME, (void*)&OnChat, context);
    113113    AddTransition(NCS_INGAME, (uint)NMT_GAME_SETUP, NCS_INGAME, (void*)&OnGameSetup, context);
    114114    AddTransition(NCS_INGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_INGAME, (void*)&OnPlayerAssignment, context);
    115115    AddTransition(NCS_INGAME, (uint)NMT_SIMULATION_COMMAND, NCS_INGAME, (void*)&OnInGame, context);
    116116    AddTransition(NCS_INGAME, (uint)NMT_SYNC_ERROR, NCS_INGAME, (void*)&OnInGame, context);
    117117    AddTransition(NCS_INGAME, (uint)NMT_END_COMMAND_BATCH, NCS_INGAME, (void*)&OnInGame, context);
     118    AddTransition(NCS_INGAME, (uint)NMT_REJOINED, NCS_INGAME, (void*)&OnRejoined, context);
    118119
    119120    // Set first state
    120121    SetFirstState(NCS_UNCONNECTED);
    121122}
    122123
    123124CNetClient::~CNetClient()
    124125{
    125126    DestroyConnection();
    126127    JS_RemoveExtraGCRootsTracer(GetScriptInterface().GetJSRuntime(), CNetClient::Trace, this);
    127128}
    128129
    129130void CNetClient::TraceMember(JSTracer *trc)
    130131{
    131132    std::deque<JS::Heap<JS::Value> >::iterator itr;
    132133    for (itr=m_GuiMessageQueue.begin(); itr != m_GuiMessageQueue.end(); ++itr)
    133134        JS_CallHeapValueTracer(trc, &*itr, "m_GuiMessageQueue");
    134135}
    135136
    136137void CNetClient::SetUserName(const CStrW& username)
    137138{
     
    269270
    270271    // Update the state immediately to UNCONNECTED (don't bother with FSM transitions since
    271272    // we'd need one for every single state, and we don't need to use per-state actions)
    272273    SetCurrState(NCS_UNCONNECTED);
    273274}
    274275
    275276void CNetClient::SendChatMessage(const std::wstring& text)
    276277{
    277278    CChatMessage chat;
    278279    chat.m_Message = text;
    279280    SendMessage(&chat);
    280281}
    281282
    282283void CNetClient::SendReadyMessage(const int status)
    283284{
    284285    CReadyMessage readyStatus;
    285286    readyStatus.m_Status = status;
    286287    SendMessage(&readyStatus);
    287288}
    288289
     290void CNetClient::SendRejoinedMessage()
     291{
     292    CRejoinedMessage rejoinedMessage;
     293    SendMessage(&rejoinedMessage);
     294}
     295
    289296bool CNetClient::HandleMessage(CNetMessage* message)
    290297{
    291298    // Handle non-FSM messages first
    292299
    293300    Status status = m_Session->GetFileTransferer().HandleMessageReceive(message);
    294301    if (status == INFO::OK)
    295302        return true;
    296303    if (status != INFO::SKIPPED)
    297304        return false;
    298305
    299306    if (message->GetType() == NMT_FILE_TRANSFER_REQUEST)
    300307    {
    301308        CFileTransferRequestMessage* reqMessage = (CFileTransferRequestMessage*)message;
    302309
    303310        // TODO: we should support different transfer request types, instead of assuming
    304311        // it's always requesting the simulation state
    305312
    306313        std::stringstream stream;
    307314
    308315        LOGMESSAGERENDER("Serializing game at turn %u for rejoining player", m_ClientTurnManager->GetCurrentTurn());
     
    567574
    568575    return true;
    569576}
    570577
    571578bool CNetClient::OnJoinSyncEndCommandBatch(void* context, CFsmEvent* event)
    572579{
    573580    ENSURE(event->GetType() == (uint)NMT_END_COMMAND_BATCH);
    574581
    575582    CNetClient* client = (CNetClient*)context;
    576583
    577584    CEndCommandBatchMessage* endMessage = (CEndCommandBatchMessage*)event->GetParamRef();
    578585
    579586    client->m_ClientTurnManager->FinishedAllCommands(endMessage->m_Turn, endMessage->m_TurnLength);
    580587
    581588    // Execute all the received commands for the latest turn
    582589    client->m_ClientTurnManager->UpdateFastForward();
    583590
    584591    return true;
    585592}
    586593
     594bool CNetClient::OnRejoined(void *context, CFsmEvent* event)
     595{
     596    ENSURE(event->GetType() == (uint)NMT_REJOINED);
     597
     598    CNetClient* client = (CNetClient*)context;
     599    JSContext* cx = client->GetScriptInterface().GetContext();
     600
     601    CRejoinedMessage* message = (CRejoinedMessage*)event->GetParamRef();
     602    JS::RootedValue msg(cx);
     603    client->GetScriptInterface().Eval("({'type':'rejoined'})", &msg);
     604    client->GetScriptInterface().SetProperty(msg, "guid", std::string(message->m_GUID), false);
     605    client->PushGuiMessage(msg);
     606
     607    return true;
     608}
     609
    587610bool CNetClient::OnLoadedGame(void* context, CFsmEvent* event)
    588611{
    589612    ENSURE(event->GetType() == (uint)NMT_LOADED_GAME);
    590613
    591614    CNetClient* client = (CNetClient*)context;
    592615    JSContext* cx = client->GetScriptInterface().GetContext();
    593616    JSAutoRequest rq(cx);
    594617
    595618    // All players have loaded the game - start running the turn manager
    596619    // so that the game begins
    597620    client->m_Game->SetTurnManager(client->m_ClientTurnManager);
    598621
    599622    JS::RootedValue msg(cx);
    600623    client->GetScriptInterface().Eval("({'type':'netstatus','status':'active'})", &msg);
    601624    client->PushGuiMessage(msg);
    602625
    603626    return true;
    604627}
    605628
    606629bool CNetClient::OnInGame(void *context, CFsmEvent* event)
     
    614637    {
    615638        if (message->GetType() == NMT_SIMULATION_COMMAND)
    616639        {
    617640            CSimulationMessage* simMessage = static_cast<CSimulationMessage*> (message);
    618641            client->m_ClientTurnManager->OnSimulationMessage(simMessage);
    619642        }
    620643        else if (message->GetType() == NMT_SYNC_ERROR)
    621644        {
    622645            CSyncErrorMessage* syncMessage = static_cast<CSyncErrorMessage*> (message);
    623646            client->m_ClientTurnManager->OnSyncError(syncMessage->m_Turn, syncMessage->m_HashExpected);
    624647        }
    625648        else if (message->GetType() == NMT_END_COMMAND_BATCH)
    626649        {
    627650            CEndCommandBatchMessage* endMessage = static_cast<CEndCommandBatchMessage*> (message);
    628651            client->m_ClientTurnManager->FinishedAllCommands(endMessage->m_Turn, endMessage->m_TurnLength);
    629652        }
    630653    }
    631654
    632655    return true;
    633656}
     657
  • source/network/NetClient.h

     
    163163    /**
    164164     * Call when the network connection has been lost.
    165165     */
    166166    void HandleDisconnect(u32 reason);
    167167
    168168    /**
    169169     * Call when a message has been received from the network.
    170170     */
    171171    bool HandleMessage(CNetMessage* message);
    172172
    173173    /**
    174174     * Call when the game has started and all data files have been loaded,
    175175     * to signal to the server that we are ready to begin the game.
    176176     */
    177177    void LoadFinished();
    178178
    179179    void SendChatMessage(const std::wstring& text);
    180180   
    181181    void SendReadyMessage(const int status);
    182182
     183    /**
     184     * Call when the client has rejoined a running match and finished
     185     * the loading screen.
     186     */
     187    void SendRejoinedMessage();
     188
     189
    183190private:
    184191    // Net message / FSM transition handlers
    185192    static bool OnConnect(void* context, CFsmEvent* event);
    186193    static bool OnHandshake(void* context, CFsmEvent* event);
    187194    static bool OnHandshakeResponse(void* context, CFsmEvent* event);
    188195    static bool OnAuthenticate(void* context, CFsmEvent* event);
    189196    static bool OnChat(void* context, CFsmEvent* event);
    190197    static bool OnReady(void* context, CFsmEvent* event);
    191198    static bool OnGameSetup(void* context, CFsmEvent* event);
    192199    static bool OnPlayerAssignment(void* context, CFsmEvent* event);
    193200    static bool OnInGame(void* context, CFsmEvent* event);
    194201    static bool OnGameStart(void* context, CFsmEvent* event);
    195202    static bool OnJoinSyncStart(void* context, CFsmEvent* event);
    196203    static bool OnJoinSyncEndCommandBatch(void* context, CFsmEvent* event);
    197204    static bool OnLoadedGame(void* context, CFsmEvent* event);
     205    static bool OnRejoined(void* context, CFsmEvent* event);
    198206
    199207    /**
    200208     * Take ownership of a session object, and use it for all network communication.
    201209     */
    202210    void SetAndOwnSession(CNetClientSession* session);
    203211
    204212    /**
    205213     * Push a message onto the GUI queue listing the current player assignments.
    206214     */
    207215    void PostPlayerAssignmentsToScript();
    208216
    209217    CGame *m_Game;
    210218    CStrW m_UserName;
    211219
    212220    /// Current network session (or NULL if not connected)
    213221    CNetClientSession* m_Session;
    214222
    215223    /// Turn manager associated with the current game (or NULL if we haven't started the game yet)
    216224    CNetClientTurnManager* m_ClientTurnManager;
    217225
  • source/network/NetMessage.cpp

     
    114114    case NMT_FILE_TRANSFER_REQUEST:
    115115        pNewMessage = new CFileTransferRequestMessage;
    116116        break;
    117117
    118118    case NMT_FILE_TRANSFER_RESPONSE:
    119119        pNewMessage = new CFileTransferResponseMessage;
    120120        break;
    121121
    122122    case NMT_FILE_TRANSFER_DATA:
    123123        pNewMessage = new CFileTransferDataMessage;
    124124        break;
    125125
    126126    case NMT_FILE_TRANSFER_ACK:
    127127        pNewMessage = new CFileTransferAckMessage;
    128128        break;
    129129
    130130    case NMT_JOIN_SYNC_START:
    131131        pNewMessage = new CJoinSyncStartMessage;
    132132        break;
    133133
     134    case NMT_REJOINED:
     135        pNewMessage = new CRejoinedMessage;
     136        break;
     137
    134138    case NMT_LOADED_GAME:
    135139        pNewMessage = new CLoadedGameMessage;
    136140        break;
    137141
    138142    case NMT_SERVER_HANDSHAKE:
    139143        pNewMessage = new CSrvHandshakeMessage;
    140144        break;
    141145
    142146    case NMT_SERVER_HANDSHAKE_RESPONSE:
    143147        pNewMessage = new CSrvHandshakeResponseMessage;
    144148        break;
    145149
    146150    case NMT_CLIENT_HANDSHAKE:
    147151        pNewMessage = new CCliHandshakeMessage;
    148152        break;
    149153
    150154    case NMT_AUTHENTICATE:
    151155        pNewMessage = new CAuthenticateMessage;
    152156        break;
    153157
     
    157161
    158162    case NMT_GAME_START:
    159163        pNewMessage = new CGameStartMessage;
    160164        break;
    161165
    162166    case NMT_END_COMMAND_BATCH:
    163167        pNewMessage = new CEndCommandBatchMessage;
    164168        break;
    165169
    166170    case NMT_SYNC_CHECK:
    167171        pNewMessage = new CSyncCheckMessage;
    168172        break;
    169173
    170174    case NMT_SYNC_ERROR:
    171175        pNewMessage = new CSyncErrorMessage;
    172176        break;
    173177
    174178    case NMT_CHAT:
    175179        pNewMessage = new CChatMessage;
    176180        break;
    177    
     181
    178182    case NMT_READY:
    179183        pNewMessage = new CReadyMessage;
    180184        break;
    181185
    182186    case NMT_SIMULATION_COMMAND:
    183187        pNewMessage = new CSimulationMessage(scriptInterface);
    184188        break;
    185189
    186190    default:
    187191        LOGERROR("CNetMessageFactory::CreateMessage(): Unknown message type '%d' received", header.GetType());
    188192        break;
    189193    }
    190194
    191195    if (pNewMessage)
    192196        pNewMessage->Deserialize((const u8*)pData, (const u8*)pData + dataSize);
    193197
    194198    return pNewMessage;
    195199}
  • source/network/NetMessages.h

     
    3030#define PS_PROTOCOL_MAGIC_RESPONSE      0x50630121      // 'P', 'c', 0x01, '!'
    3131#define PS_PROTOCOL_VERSION             0x01010005      // 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.
    3535// The message types having a negative value are used internally and not sent
    3636// over the network. The message types used for network communication have
    3737// positive values.
    3838enum NetMessageType
    3939{
    4040    NMT_CONNECT_COMPLETE = -256,    // Connection is complete
    4141    NMT_CONNECTION_LOST,
    4242    NMT_INVALID = 0,        // Invalid message
    4343    NMT_SERVER_HANDSHAKE,   // Handshake stage
    4444    NMT_CLIENT_HANDSHAKE,
    4545    NMT_SERVER_HANDSHAKE_RESPONSE,
    4646    NMT_AUTHENTICATE,       // Authentication stage
    4747    NMT_AUTHENTICATE_RESULT,
    4848    NMT_CHAT,       // Common chat message
    4949    NMT_READY,
     50    NMT_REJOINED,
    5051    NMT_GAME_SETUP,
    5152    NMT_PLAYER_ASSIGNMENT,
    5253
    5354    NMT_FILE_TRANSFER_REQUEST,
    5455    NMT_FILE_TRANSFER_RESPONSE,
    5556    NMT_FILE_TRANSFER_DATA,
    5657    NMT_FILE_TRANSFER_ACK,
    5758
    5859    NMT_JOIN_SYNC_START,
    5960
    6061    NMT_LOADED_GAME,
    6162    NMT_GAME_START,
    6263    NMT_END_COMMAND_BATCH,
    6364    NMT_SYNC_CHECK, // OOS-detection hash checking
    6465    NMT_SYNC_ERROR, // OOS-detection error
    6566    NMT_SIMULATION_COMMAND,
    6667    NMT_LAST                // Last message in the list
    6768};
    6869
    6970// Authentication result codes
     
    138139END_NMT_CLASS()
    139140
    140141START_NMT_CLASS_(FileTransferResponse, NMT_FILE_TRANSFER_RESPONSE)
    141142    NMT_FIELD_INT(m_RequestID, u32, 4)
    142143    NMT_FIELD_INT(m_Length, u32, 4)
    143144END_NMT_CLASS()
    144145
    145146START_NMT_CLASS_(FileTransferData, NMT_FILE_TRANSFER_DATA)
    146147    NMT_FIELD_INT(m_RequestID, u32, 4)
    147148    NMT_FIELD(CStr8, m_Data)
    148149END_NMT_CLASS()
    149150
    150151START_NMT_CLASS_(FileTransferAck, NMT_FILE_TRANSFER_ACK)
    151152    NMT_FIELD_INT(m_RequestID, u32, 4)
    152153    NMT_FIELD_INT(m_NumPackets, u32, 4)
    153154END_NMT_CLASS()
    154155
    155156START_NMT_CLASS_(JoinSyncStart, NMT_JOIN_SYNC_START)
    156157END_NMT_CLASS()
    157158
     159START_NMT_CLASS_(Rejoined, NMT_REJOINED)
     160    NMT_FIELD(CStr8, m_GUID)
     161END_NMT_CLASS()
     162
    158163START_NMT_CLASS_(LoadedGame, NMT_LOADED_GAME)
    159164    NMT_FIELD_INT(m_CurrentTurn, u32, 4)
    160165END_NMT_CLASS()
    161166
    162167START_NMT_CLASS_(GameStart, NMT_GAME_START)
    163168END_NMT_CLASS()
    164169
    165170START_NMT_CLASS_(EndCommandBatch, NMT_END_COMMAND_BATCH)
    166171    NMT_FIELD_INT(m_Turn, u32, 4)
    167172    NMT_FIELD_INT(m_TurnLength, u32, 2)
    168173END_NMT_CLASS()
    169174
    170175START_NMT_CLASS_(SyncCheck, NMT_SYNC_CHECK)
    171176    NMT_FIELD_INT(m_Turn, u32, 4)
    172177    NMT_FIELD(CStr, m_Hash)
    173178END_NMT_CLASS()
    174179
    175180START_NMT_CLASS_(SyncError, NMT_SYNC_ERROR)
    176181    NMT_FIELD_INT(m_Turn, u32, 4)
    177182    NMT_FIELD(CStr, m_HashExpected)
  • source/network/NetServer.cpp

     
    581581
    582582    session->AddTransition(NSS_HANDSHAKE, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED);
    583583    session->AddTransition(NSS_HANDSHAKE, (uint)NMT_CLIENT_HANDSHAKE, NSS_AUTHENTICATE, (void*)&OnClientHandshake, context);
    584584
    585585    session->AddTransition(NSS_AUTHENTICATE, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED);
    586586    session->AddTransition(NSS_AUTHENTICATE, (uint)NMT_AUTHENTICATE, NSS_PREGAME, (void*)&OnAuthenticate, context);
    587587
    588588    session->AddTransition(NSS_PREGAME, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context);
    589589    session->AddTransition(NSS_PREGAME, (uint)NMT_CHAT, NSS_PREGAME, (void*)&OnChat, context);
    590590    session->AddTransition(NSS_PREGAME, (uint)NMT_READY, NSS_PREGAME, (void*)&OnReady, context);
    591591    session->AddTransition(NSS_PREGAME, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnLoadedGame, context);
    592592
    593593    session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context);
    594594    session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnJoinSyncingLoadedGame, context);
    595595
    596596    session->AddTransition(NSS_INGAME, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context);
    597597    session->AddTransition(NSS_INGAME, (uint)NMT_CHAT, NSS_INGAME, (void*)&OnChat, context);
    598598    session->AddTransition(NSS_INGAME, (uint)NMT_SIMULATION_COMMAND, NSS_INGAME, (void*)&OnInGame, context);
    599599    session->AddTransition(NSS_INGAME, (uint)NMT_SYNC_CHECK, NSS_INGAME, (void*)&OnInGame, context);
    600600    session->AddTransition(NSS_INGAME, (uint)NMT_END_COMMAND_BATCH, NSS_INGAME, (void*)&OnInGame, context);
     601    session->AddTransition(NSS_INGAME, (uint)NMT_REJOINED, NSS_INGAME, (void*)&OnRejoined, context);
    601602
    602603    // Set first state
    603604    session->SetFirstState(NSS_HANDSHAKE);
    604605}
    605606
    606607bool CNetServerWorker::HandleConnect(CNetServerSession* session)
    607608{
    608609    CSrvHandshakeMessage handshake;
    609610    handshake.m_Magic = PS_PROTOCOL_MAGIC;
    610611    handshake.m_ProtocolVersion = PS_PROTOCOL_VERSION;
    611612    handshake.m_SoftwareVersion = PS_PROTOCOL_VERSION;
    612613    return session->SendMessage(&handshake);
    613614}
    614615
    615616void CNetServerWorker::OnUserJoin(CNetServerSession* session)
    616617{
    617618    AddPlayer(session->GetGUID(), session->GetUserName());
    618619
    619620    CGameSetupMessage gameSetupMessage(GetScriptInterface());
    620621    gameSetupMessage.m_Data = m_GameAttributes.get();
     
    905906
    906907    return true;
    907908}
    908909
    909910bool CNetServerWorker::OnReady(void* context, CFsmEvent* event)
    910911{
    911912    ENSURE(event->GetType() == (uint)NMT_READY);
    912913
    913914    CNetServerSession* session = (CNetServerSession*)context;
    914915    CNetServerWorker& server = session->GetServer();
    915916
    916917    CReadyMessage* message = (CReadyMessage*)event->GetParamRef();
    917918
    918919    message->m_GUID = session->GetGUID();
    919920
    920921    server.Broadcast(message);
    921922
    922923    return true;
    923924}
    924925
     926
    925927bool CNetServerWorker::OnLoadedGame(void* context, CFsmEvent* event)
    926928{
    927929    ENSURE(event->GetType() == (uint)NMT_LOADED_GAME);
    928930
    929931    CNetServerSession* session = (CNetServerSession*)context;
    930932    CNetServerWorker& server = session->GetServer();
    931933
    932934    // We're in the loading state, so wait until every player has loaded before
    933935    // starting the game
    934936    ENSURE(server.m_State == SERVER_STATE_LOADING);
    935937    server.CheckGameLoadStatus(session);
    936938
    937939    return true;
    938940}
    939941
    940942bool CNetServerWorker::OnJoinSyncingLoadedGame(void* context, CFsmEvent* event)
    941943{
    942944    // A client rejoining an in-progress game has now finished loading the
    943945    // map and deserialized the initial state.
    944946    // The simulation may have progressed since then, so send any subsequent
     
    971973        if (i <= readyTurn)
    972974        {
    973975            CEndCommandBatchMessage endMessage;
    974976            endMessage.m_Turn = i;
    975977            endMessage.m_TurnLength = server.m_ServerTurnManager->GetSavedTurnLength(i);
    976978            session->SendMessage(&endMessage);
    977979        }
    978980    }
    979981
    980982    // Tell the turn manager to expect commands from this new client
    981983    server.m_ServerTurnManager->InitialiseClient(session->GetHostID(), readyTurn);
    982984
    983985    // Tell the client that everything has finished loading and it should start now
    984986    CLoadedGameMessage loaded;
    985987    loaded.m_CurrentTurn = readyTurn;
    986988    session->SendMessage(&loaded);
    987989
    988990    return true;
    989991}
    990992
     993bool CNetServerWorker::OnRejoined(void* context, CFsmEvent* event)
     994{
     995
     996    // A client has finished rejoining and his/her loading screen disappeared.
     997
     998    ENSURE(event->GetType() == (uint)NMT_REJOINED);
     999
     1000    CNetServerSession* session = (CNetServerSession*)context;
     1001    CNetServerWorker& server = session->GetServer();
     1002
     1003    CRejoinedMessage* message = (CRejoinedMessage*)event->GetParamRef();
     1004
     1005    message->m_GUID = session->GetGUID();
     1006
     1007    server.Broadcast(message);
     1008
     1009    return true;
     1010}
     1011
    9911012bool CNetServerWorker::OnDisconnect(void* context, CFsmEvent* event)
    9921013{
    9931014    ENSURE(event->GetType() == (uint)NMT_CONNECTION_LOST);
    9941015
    9951016    CNetServerSession* session = (CNetServerSession*)context;
    9961017    CNetServerWorker& server = session->GetServer();
    9971018
    9981019    server.OnUserLeave(session);
    9991020
    10001021    return true;
    10011022}
    10021023
    10031024void CNetServerWorker::CheckGameLoadStatus(CNetServerSession* changedSession)
    10041025{
    10051026    for (size_t i = 0; i < m_Sessions.size(); ++i)
    10061027    {
    10071028        if (m_Sessions[i] != changedSession && m_Sessions[i]->GetCurrState() != NSS_INGAME)
    10081029            return;
    10091030    }
    10101031
  • source/network/NetServer.h

     
    245245
    246246    void AddPlayer(const CStr& guid, const CStrW& name);
    247247    void RemovePlayer(const CStr& guid);
    248248    void SetPlayerReady(const CStr& guid, const int ready);
    249249    void SendPlayerAssignments();
    250250    void ClearAllPlayerReady();
    251251
    252252    void SetupSession(CNetServerSession* session);
    253253    bool HandleConnect(CNetServerSession* session);
    254254
    255255    void OnUserJoin(CNetServerSession* session);
    256256    void OnUserLeave(CNetServerSession* session);
    257257
    258258    static bool OnClientHandshake(void* context, CFsmEvent* event);
    259259    static bool OnAuthenticate(void* context, CFsmEvent* event);
    260260    static bool OnInGame(void* context, CFsmEvent* event);
    261261    static bool OnChat(void* context, CFsmEvent* event);
    262262    static bool OnReady(void* context, CFsmEvent* event);
    263263    static bool OnLoadedGame(void* context, CFsmEvent* event);
    264264    static bool OnJoinSyncingLoadedGame(void* context, CFsmEvent* event);
     265    static bool OnRejoined(void* context, CFsmEvent* event);
    265266    static bool OnDisconnect(void* context, CFsmEvent* event);
    266267
    267268    void CheckGameLoadStatus(CNetServerSession* changedSession);
    268269
    269270    void ConstructPlayerAssignmentMessage(CPlayerAssignmentMessage& message);
    270271
    271272    void HandleMessageReceive(const CNetMessage* message, CNetServerSession* session);
    272273
    273274
    274275    /**
    275276     * Internal script context for (de)serializing script messages,
    276277     * and for storing game attributes.
    277278     * (TODO: we shouldn't bother deserializing (except for debug printing of messages),
    278279     * we should just forward messages blindly and efficiently.)
    279280     */
    280281    ScriptInterface* m_ScriptInterface;
    281282
    282283    PlayerAssignmentMap m_PlayerAssignments;
    283284
    284285    /**
  • source/ps/Game.cpp

     
    218218            m_Simulation2->PreInitGame();
    219219
    220220        JS::RootedValue settings(cx);
    221221        JS::RootedValue tmpInitAttributes(cx, m_Simulation2->GetInitAttributes());
    222222        m_Simulation2->GetScriptInterface().GetProperty(tmpInitAttributes, "settings", &settings);
    223223        m_Simulation2->InitGame(settings);
    224224    }
    225225
    226226    // We need to do an initial Interpolate call to set up all the models etc,
    227227    // because Update might never interpolate (e.g. if the game starts paused)
    228228    // and we could end up rendering before having set up any models (so they'd
    229229    // all be invisible)
    230230    Interpolate(0, 0);
    231231
    232232    m_GameStarted=true;
    233233   
    234234    // Render a frame to begin loading assets
    235235    if (CRenderer::IsInitialised())
    236236        Render();
    237237
     238    if (g_NetClient)
     239        g_NetClient->LoadFinished();
     240
    238241    // Call the reallyStartGame GUI function, but only if it exists
    239242    if (g_GUI && g_GUI->HasPages())
    240243    {
    241244        JS::RootedValue global(cx, g_GUI->GetActiveGUI()->GetGlobalObject());
    242245        if (g_GUI->GetActiveGUI()->GetScriptInterface()->HasProperty(global, "reallyStartGame"))
    243246            g_GUI->GetActiveGUI()->GetScriptInterface()->CallFunctionVoid(global, "reallyStartGame");
    244247    }
    245248
    246     if (g_NetClient)
    247         g_NetClient->LoadFinished();
    248 
    249249    debug_printf("GAME STARTED, ALL INIT COMPLETE\n");
    250250
    251251    // The call tree we've built for pregame probably isn't useful in-game.
    252252    if (CProfileManager::IsInitialised())
    253253        g_Profiler.StructuralReset();
    254254
    255255    // Mark terrain as modified so the minimap can repaint (is there a cleaner way of handling this?)
    256256    g_GameRestarted = true;
    257257
    258258    return 0;
    259259}
    260260
    261261int CGame::GetPlayerID()
    262262{
    263263    return m_PlayerID;
    264264}
    265265
    266266void CGame::SetPlayerID(int playerID)
    267267{
    268268    m_PlayerID = playerID;