Ticket #3700: 3700.4.patch

File 3700.4.patch, 25.9 KB (added by Andy Alt, 7 years ago)

A few changes after discussion with elexis. WIP

  • source/gui/scripting/ScriptFunctions.cpp

     
    349349    }
    350350
    351351    g_Game = new CGame();
    352     g_NetClient = new CNetClient(g_Game, true);
     352    g_NetClient = new CNetClientWorker(g_Game, true);
    353353    g_NetClient->SetUserName(playerName);
    354354
    355355    if (!g_NetClient->SetupConnection("127.0.0.1", serverPort))
     
    367367    ENSURE(!g_Game);
    368368
    369369    g_Game = new CGame();
    370     g_NetClient = new CNetClient(g_Game, false);
     370    g_NetClient = new CNetClientWorker(g_Game, false);
    371371    g_NetClient->SetUserName(playerName);
    372372    if (!g_NetClient->SetupConnection(serverAddress, serverPort))
    373373    {
  • source/network/NetClient.cpp

     
    4545{
    4646    NONCOPYABLE(CNetFileReceiveTask_ClientRejoin);
    4747public:
    48     CNetFileReceiveTask_ClientRejoin(CNetClient& client)
     48    CNetFileReceiveTask_ClientRejoin(CNetClientWorker& client)
    4949        : m_Client(client)
    5050    {
    5151    }
     
    6363    }
    6464
    6565private:
    66     CNetClient& m_Client;
     66    CNetClientWorker& m_Client;
    6767};
    6868
    69 CNetClient::CNetClient(CGame* game, bool isLocalClient) :
     69CNetClientWorker::CNetClientWorker(CGame* game, bool isLocalClient) :
    7070    m_Session(NULL),
    7171    m_UserName(L"anonymous"),
    7272    m_GUID(ps_generate_guid()), m_HostID((u32)-1), m_ClientTurnManager(NULL), m_Game(game),
     
    7979
    8080    void* context = this;
    8181
    82     JS_AddExtraGCRootsTracer(GetScriptInterface().GetJSRuntime(), CNetClient::Trace, this);
    83 
    84     // Set up transitions for session
     82        // Set up transitions for session
    8583    AddTransition(NCS_UNCONNECTED, (uint)NMT_CONNECT_COMPLETE, NCS_CONNECT, (void*)&OnConnect, context);
    8684
    8785    AddTransition(NCS_CONNECT, (uint)NMT_SERVER_HANDSHAKE, NCS_HANDSHAKE, (void*)&OnHandshake, context);
     
    139137    SetFirstState(NCS_UNCONNECTED);
    140138}
    141139
    142 CNetClient::~CNetClient()
     140CNetClientWorker::~CNetClientWorker()
    143141{
    144142    DestroyConnection();
    145     JS_RemoveExtraGCRootsTracer(GetScriptInterface().GetJSRuntime(), CNetClient::Trace, this);
    146 }
    147143
    148 void CNetClient::TraceMember(JSTracer *trc)
    149 {
    150     for (JS::Heap<JS::Value>& guiMessage : m_GuiMessageQueue)
    151         JS_CallValueTracer(trc, &guiMessage, "m_GuiMessageQueue");
     144    /*  if (m_State != SERVER_STATE_UNCONNECTED)
     145    {
     146        // Tell the thread to shut down
     147        {
     148            CScopeLock lock(m_WorkerMutex);
     149            m_Shutdown = true;
     150        }
     151
     152        // Wait for it to shut down cleanly
     153        pthread_join(m_WorkerThread, NULL);
     154    }
     155
     156    // Clean up resources
     157
     158    delete m_Stats;
     159
     160    for (CNetServerSession* session : m_Sessions)
     161    {
     162        session->DisconnectNow(NDR_SERVER_SHUTDOWN);
     163        delete session;
     164    }
     165
     166    if (m_Host)
     167        enet_host_destroy(m_Host);
     168
     169    delete m_ServerTurnManager; */
    152170}
    153171
    154 void CNetClient::SetUserName(const CStrW& username)
     172void CNetClientWorker::SetUserName(const CStrW& username)
    155173{
    156174    ENSURE(!m_Session); // must be called before we start the connection
    157175
     
    158176    m_UserName = username;
    159177}
    160178
    161 bool CNetClient::SetupConnection(const CStr& server, const u16 port)
     179bool CNetClientWorker::SetupConnection(const CStr& server, const u16 port)
    162180{
    163181    CNetClientSession* session = new CNetClientSession(*this);
    164182    bool ok = session->Connect(server, port, m_IsLocalClient);
    165183    SetAndOwnSession(session);
     184
     185    //m_State = SERVER_STATE_PREGAME;
     186
     187    // Launch the worker thread
     188    int ret = pthread_create(&m_WorkerThread, NULL, &RunThread, this);
     189    ENSURE(ret == 0);
     190
    166191    return ok;
    167192}
    168193
    169 void CNetClient::SetAndOwnSession(CNetClientSession* session)
     194void CNetClientWorker::SetAndOwnSession(CNetClientSession* session)
    170195{
    171196    delete m_Session;
    172197    m_Session = session;
    173198}
    174199
    175 void CNetClient::DestroyConnection()
     200void CNetClientWorker::DestroyConnection()
    176201{
    177202    // Send network messages from the current frame before connection is destroyed.
    178203    if (m_ClientTurnManager)
     
    183208    SAFE_DELETE(m_Session);
    184209}
    185210
    186 void CNetClient::Poll()
     211void CNetClientWorker::Poll()
    187212{
    188213    if (!m_Session)
    189214        return;
     
    192217    m_Session->Poll();
    193218}
    194219
    195 void CNetClient::CheckServerConnection()
     220void* CNetClientWorker::RunThread(void* data)
    196221{
     222    debug_SetThreadName("NetClient");
     223
     224    static_cast<CNetClientWorker*>(data)->Run();
     225
     226    return NULL;
     227}
     228
     229void CNetClientWorker::Run()
     230{
     231    // The script runtime uses the profiler and therefore the thread must be registered before the runtime is created
     232    g_Profiler2.RegisterCurrentThread("Net client");
     233
     234    while (true)
     235    {
     236        if (!RunStep())
     237            break;
     238
     239        // Implement autostart mode
     240        //if (m_State == CLIENT_STATE_PREGAME && (int)m_PlayerAssignments.size() == m_AutostartPlayers)
     241        //  StartGame();
     242
     243        // Update profiler stats
     244        //m_Stats->LatchHostState(m_Host);
     245    }
     246}
     247
     248bool CNetClientWorker::RunStep()
     249{
     250    // Check for messages from the game thread.
     251    // (Do as little work as possible while the mutex is held open,
     252    // to avoid performance problems and deadlocks.)
     253
     254    CheckServerConnection();
     255
     256    return true;
     257}
     258
     259void CNetClientWorker::CheckServerConnection()
     260{
    197261    // Trigger local warnings if the connection to the server is bad.
    198262    // At most once per second.
    199263    std::time_t now = std::time(nullptr);
     
    227291    }
    228292}
    229293
    230 void CNetClient::Flush()
     294void CNetClientWorker::Flush()
    231295{
    232296    if (m_Session)
    233297        m_Session->Flush();
    234298}
    235299
    236 void CNetClient::GuiPoll(JS::MutableHandleValue ret)
     300void CNetClientWorker::GuiPoll(JS::MutableHandleValue ret)
    237301{
    238302    if (m_GuiMessageQueue.empty())
    239303    {
     
    245309    m_GuiMessageQueue.pop_front();
    246310}
    247311
    248 void CNetClient::PushGuiMessage(const JS::HandleValue message)
     312void CNetClientWorker::PushGuiMessage(const JS::HandleValue message)
    249313{
    250314    ENSURE(!message.isUndefined());
    251315
     
    252316    m_GuiMessageQueue.push_back(JS::Heap<JS::Value>(message));
    253317}
    254318
    255 std::string CNetClient::TestReadGuiMessages()
     319std::string CNetClientWorker::TestReadGuiMessages()
    256320{
    257321    JSContext* cx = GetScriptInterface().GetContext();
    258322    JSAutoRequest rq(cx);
     
    269333    return r;
    270334}
    271335
    272 ScriptInterface& CNetClient::GetScriptInterface()
     336ScriptInterface& CNetClientWorker::GetScriptInterface()
    273337{
    274338    return m_Game->GetSimulation2()->GetScriptInterface();
    275339}
    276340
    277 void CNetClient::PostPlayerAssignmentsToScript()
     341void CNetClientWorker::PostPlayerAssignmentsToScript()
    278342{
    279343    JSContext* cx = GetScriptInterface().GetContext();
    280344    JSAutoRequest rq(cx);
     
    298362    PushGuiMessage(msg);
    299363}
    300364
    301 bool CNetClient::SendMessage(const CNetMessage* message)
     365bool CNetClientWorker::SendMessage(const CNetMessage* message)
    302366{
    303367    if (!m_Session)
    304368        return false;
     
    306370    return m_Session->SendMessage(message);
    307371}
    308372
    309 void CNetClient::HandleConnect()
     373void CNetClientWorker::HandleConnect()
    310374{
    311375    Update((uint)NMT_CONNECT_COMPLETE, NULL);
    312376}
    313377
    314 void CNetClient::HandleDisconnect(u32 reason)
     378void CNetClientWorker::HandleDisconnect(u32 reason)
    315379{
    316380    JSContext* cx = GetScriptInterface().GetContext();
    317381    JSAutoRequest rq(cx);
     
    328392    SetCurrState(NCS_UNCONNECTED);
    329393}
    330394
    331 void CNetClient::SendGameSetupMessage(JS::MutableHandleValue attrs, ScriptInterface& scriptInterface)
     395void CNetClientWorker::SendGameSetupMessage(JS::MutableHandleValue attrs, ScriptInterface& scriptInterface)
    332396{
    333397    CGameSetupMessage gameSetup(scriptInterface);
    334398    gameSetup.m_Data = attrs;
     
    335399    SendMessage(&gameSetup);
    336400}
    337401
    338 void CNetClient::SendAssignPlayerMessage(const int playerID, const CStr& guid)
     402void CNetClientWorker::SendAssignPlayerMessage(const int playerID, const CStr& guid)
    339403{
    340404    CAssignPlayerMessage assignPlayer;
    341405    assignPlayer.m_PlayerID = playerID;
     
    343407    SendMessage(&assignPlayer);
    344408}
    345409
    346 void CNetClient::SendChatMessage(const std::wstring& text)
     410void CNetClientWorker::SendChatMessage(const std::wstring& text)
    347411{
    348412    CChatMessage chat;
    349413    chat.m_Message = text;
     
    350414    SendMessage(&chat);
    351415}
    352416
    353 void CNetClient::SendReadyMessage(const int status)
     417void CNetClientWorker::SendReadyMessage(const int status)
    354418{
    355419    CReadyMessage readyStatus;
    356420    readyStatus.m_Status = status;
     
    357421    SendMessage(&readyStatus);
    358422}
    359423
    360 void CNetClient::SendClearAllReadyMessage()
     424void CNetClientWorker::SendClearAllReadyMessage()
    361425{
    362426    CClearAllReadyMessage clearAllReady;
    363427    SendMessage(&clearAllReady);
    364428}
    365429
    366 void CNetClient::SendStartGameMessage()
     430void CNetClientWorker::SendStartGameMessage()
    367431{
    368432    CGameStartMessage gameStart;
    369433    SendMessage(&gameStart);
    370434}
    371435
    372 void CNetClient::SendRejoinedMessage()
     436void CNetClientWorker::SendRejoinedMessage()
    373437{
    374438    CRejoinedMessage rejoinedMessage;
    375439    SendMessage(&rejoinedMessage);
    376440}
    377441
    378 void CNetClient::SendKickPlayerMessage(const CStrW& playerName, bool ban)
     442void CNetClientWorker::SendKickPlayerMessage(const CStrW& playerName, bool ban)
    379443{
    380444    CKickedMessage kickPlayer;
    381445    kickPlayer.m_Name = playerName;
     
    383447    SendMessage(&kickPlayer);
    384448}
    385449
    386 void CNetClient::SendPausedMessage(bool pause)
     450void CNetClientWorker::SendPausedMessage(bool pause)
    387451{
    388452    CClientPausedMessage pausedMessage;
    389453    pausedMessage.m_Pause = pause;
     
    390454    SendMessage(&pausedMessage);
    391455}
    392456
    393 bool CNetClient::HandleMessage(CNetMessage* message)
     457bool CNetClientWorker::HandleMessage(CNetMessage* message)
    394458{
    395459    // Handle non-FSM messages first
    396460
     
    433497    return ok;
    434498}
    435499
    436 void CNetClient::LoadFinished()
     500void CNetClientWorker::LoadFinished()
    437501{
    438502    JSContext* cx = GetScriptInterface().GetContext();
    439503    JSAutoRequest rq(cx);
     
    476540    SendMessage(&loaded);
    477541}
    478542
    479 bool CNetClient::OnConnect(void* context, CFsmEvent* event)
     543bool CNetClientWorker::OnConnect(void* context, CFsmEvent* event)
    480544{
    481545    ENSURE(event->GetType() == (uint)NMT_CONNECT_COMPLETE);
    482546
    483     CNetClient* client = (CNetClient*)context;
     547    CNetClientWorker* client = (CNetClientWorker*)context;
    484548
    485549    JSContext* cx = client->GetScriptInterface().GetContext();
    486550    JSAutoRequest rq(cx);
     
    492556    return true;
    493557}
    494558
    495 bool CNetClient::OnHandshake(void* context, CFsmEvent* event)
     559bool CNetClientWorker::OnHandshake(void* context, CFsmEvent* event)
    496560{
    497561    ENSURE(event->GetType() == (uint)NMT_SERVER_HANDSHAKE);
    498562
    499     CNetClient* client = (CNetClient*)context;
     563    CNetClientWorker* client = (CNetClientWorker*)context;
    500564
    501565    CCliHandshakeMessage handshake;
    502566    handshake.m_MagicResponse = PS_PROTOCOL_MAGIC_RESPONSE;
     
    507571    return true;
    508572}
    509573
    510 bool CNetClient::OnHandshakeResponse(void* context, CFsmEvent* event)
     574bool CNetClientWorker::OnHandshakeResponse(void* context, CFsmEvent* event)
    511575{
    512576    ENSURE(event->GetType() == (uint)NMT_SERVER_HANDSHAKE_RESPONSE);
    513577
    514     CNetClient* client = (CNetClient*)context;
     578    CNetClientWorker* client = (CNetClientWorker*)context;
    515579
    516580    CAuthenticateMessage authenticate;
    517581    authenticate.m_GUID = client->m_GUID;
     
    523587    return true;
    524588}
    525589
    526 bool CNetClient::OnAuthenticate(void* context, CFsmEvent* event)
     590bool CNetClientWorker::OnAuthenticate(void* context, CFsmEvent* event)
    527591{
    528592    ENSURE(event->GetType() == (uint)NMT_AUTHENTICATE_RESULT);
    529593
    530     CNetClient* client = (CNetClient*)context;
     594    CNetClientWorker* client = (CNetClientWorker*)context;
    531595
    532596    JSContext* cx = client->GetScriptInterface().GetContext();
    533597    JSAutoRequest rq(cx);
     
    547611    return true;
    548612}
    549613
    550 bool CNetClient::OnChat(void* context, CFsmEvent* event)
     614bool CNetClientWorker::OnChat(void* context, CFsmEvent* event)
    551615{
    552616    ENSURE(event->GetType() == (uint)NMT_CHAT);
    553617
    554     CNetClient* client = (CNetClient*)context;
     618    CNetClientWorker* client = (CNetClientWorker*)context;
    555619    JSContext* cx = client->GetScriptInterface().GetContext();
    556620    JSAutoRequest rq(cx);
    557621
     
    566630    return true;
    567631}
    568632
    569 bool CNetClient::OnReady(void* context, CFsmEvent* event)
     633bool CNetClientWorker::OnReady(void* context, CFsmEvent* event)
    570634{
    571635    ENSURE(event->GetType() == (uint)NMT_READY);
    572636
    573     CNetClient* client = (CNetClient*)context;
     637    CNetClientWorker* client = (CNetClientWorker*)context;
    574638    JSContext* cx = client->GetScriptInterface().GetContext();
    575639    JSAutoRequest rq(cx);
    576640
     
    585649    return true;
    586650}
    587651
    588 bool CNetClient::OnGameSetup(void* context, CFsmEvent* event)
     652bool CNetClientWorker::OnGameSetup(void* context, CFsmEvent* event)
    589653{
    590654    ENSURE(event->GetType() == (uint)NMT_GAME_SETUP);
    591655
    592     CNetClient* client = (CNetClient*)context;
     656    CNetClientWorker* client = (CNetClientWorker*)context;
    593657    JSContext* cx = client->GetScriptInterface().GetContext();
    594658    JSAutoRequest rq(cx);
    595659
     
    605669    return true;
    606670}
    607671
    608 bool CNetClient::OnPlayerAssignment(void* context, CFsmEvent* event)
     672bool CNetClientWorker::OnPlayerAssignment(void* context, CFsmEvent* event)
    609673{
    610674    ENSURE(event->GetType() == (uint)NMT_PLAYER_ASSIGNMENT);
    611675
    612     CNetClient* client = (CNetClient*)context;
     676    CNetClientWorker* client = (CNetClientWorker*)context;
    613677
    614678    CPlayerAssignmentMessage* message = (CPlayerAssignmentMessage*)event->GetParamRef();
    615679
     
    632696    return true;
    633697}
    634698
    635 bool CNetClient::OnGameStart(void* context, CFsmEvent* event)
     699bool CNetClientWorker::OnGameStart(void* context, CFsmEvent* event)
    636700{
    637701    ENSURE(event->GetType() == (uint)NMT_GAME_START);
    638702
    639     CNetClient* client = (CNetClient*)context;
     703    CNetClientWorker* client = (CNetClientWorker*)context;
    640704    JSContext* cx = client->GetScriptInterface().GetContext();
    641705    JSAutoRequest rq(cx);
    642706
     
    658722    return true;
    659723}
    660724
    661 bool CNetClient::OnJoinSyncStart(void* context, CFsmEvent* event)
     725bool CNetClientWorker::OnJoinSyncStart(void* context, CFsmEvent* event)
    662726{
    663727    ENSURE(event->GetType() == (uint)NMT_JOIN_SYNC_START);
    664728
    665     CNetClient* client = (CNetClient*)context;
     729    CNetClientWorker* client = (CNetClientWorker*)context;
    666730
    667731    // The server wants us to start downloading the game state from it, so do so
    668732    client->m_Session->GetFileTransferer().StartTask(
     
    672736    return true;
    673737}
    674738
    675 bool CNetClient::OnJoinSyncEndCommandBatch(void* context, CFsmEvent* event)
     739bool CNetClientWorker::OnJoinSyncEndCommandBatch(void* context, CFsmEvent* event)
    676740{
    677741    ENSURE(event->GetType() == (uint)NMT_END_COMMAND_BATCH);
    678742
    679     CNetClient* client = (CNetClient*)context;
     743    CNetClientWorker* client = (CNetClientWorker*)context;
    680744
    681745    CEndCommandBatchMessage* endMessage = (CEndCommandBatchMessage*)event->GetParamRef();
    682746
     
    688752    return true;
    689753}
    690754
    691 bool CNetClient::OnRejoined(void* context, CFsmEvent* event)
     755bool CNetClientWorker::OnRejoined(void* context, CFsmEvent* event)
    692756{
    693757    ENSURE(event->GetType() == (uint)NMT_REJOINED);
    694758
    695     CNetClient* client = (CNetClient*)context;
     759    CNetClientWorker* client = (CNetClientWorker*)context;
    696760    JSContext* cx = client->GetScriptInterface().GetContext();
    697761    JSAutoRequest rq(cx);
    698762
     
    705769    return true;
    706770}
    707771
    708 bool CNetClient::OnKicked(void *context, CFsmEvent* event)
     772bool CNetClientWorker::OnKicked(void *context, CFsmEvent* event)
    709773{
    710774    ENSURE(event->GetType() == (uint)NMT_KICKED);
    711775
    712     CNetClient* client = (CNetClient*)context;
     776    CNetClientWorker* client = (CNetClientWorker*)context;
    713777    JSContext* cx = client->GetScriptInterface().GetContext();
    714778    JSAutoRequest rq(cx);
    715779
     
    725789    return true;
    726790}
    727791
    728 bool CNetClient::OnClientTimeout(void *context, CFsmEvent* event)
     792bool CNetClientWorker::OnClientTimeout(void *context, CFsmEvent* event)
    729793{
    730794    // Report the timeout of some other client
    731795
    732796    ENSURE(event->GetType() == (uint)NMT_CLIENT_TIMEOUT);
    733797
    734     CNetClient* client = (CNetClient*)context;
     798    CNetClientWorker* client = (CNetClientWorker*)context;
    735799    JSContext* cx = client->GetScriptInterface().GetContext();
    736800    JSAutoRequest rq(cx);
    737801
     
    749813    return true;
    750814}
    751815
    752 bool CNetClient::OnClientPerformance(void *context, CFsmEvent* event)
     816bool CNetClientWorker::OnClientPerformance(void *context, CFsmEvent* event)
    753817{
    754818    // Performance statistics for one or multiple clients
    755819
    756820    ENSURE(event->GetType() == (uint)NMT_CLIENT_PERFORMANCE);
    757821
    758     CNetClient* client = (CNetClient*)context;
     822    CNetClientWorker* client = (CNetClientWorker*)context;
    759823    JSContext* cx = client->GetScriptInterface().GetContext();
    760824    JSAutoRequest rq(cx);
    761825
     
    780844    return true;
    781845}
    782846
    783 bool CNetClient::OnClientsLoading(void *context, CFsmEvent *event)
     847bool CNetClientWorker::OnClientsLoading(void *context, CFsmEvent *event)
    784848{
    785849    ENSURE(event->GetType() == (uint)NMT_CLIENTS_LOADING);
    786850
     
    791855    for (const CClientsLoadingMessage::S_m_Clients& client : message->m_Clients)
    792856        guids.push_back(client.m_GUID);
    793857
    794     CNetClient* client = (CNetClient*)context;
     858    CNetClientWorker* client = (CNetClientWorker*)context;
    795859    JSContext* cx = client->GetScriptInterface().GetContext();
    796860    JSAutoRequest rq(cx);
    797861
     
    802866    return true;
    803867}
    804868
    805 bool CNetClient::OnClientPaused(void *context, CFsmEvent *event)
     869bool CNetClientWorker::OnClientPaused(void *context, CFsmEvent *event)
    806870{
    807871    ENSURE(event->GetType() == (uint)NMT_CLIENT_PAUSED);
    808872
    809     CNetClient* client = (CNetClient*)context;
     873    CNetClientWorker* client = (CNetClientWorker*)context;
    810874    JSContext* cx = client->GetScriptInterface().GetContext();
    811875    JSAutoRequest rq(cx);
    812876
     
    821885    return true;
    822886}
    823887
    824 bool CNetClient::OnLoadedGame(void* context, CFsmEvent* event)
     888bool CNetClientWorker::OnLoadedGame(void* context, CFsmEvent* event)
    825889{
    826890    ENSURE(event->GetType() == (uint)NMT_LOADED_GAME);
    827891
    828     CNetClient* client = (CNetClient*)context;
     892    CNetClientWorker* client = (CNetClientWorker*)context;
    829893    JSContext* cx = client->GetScriptInterface().GetContext();
    830894    JSAutoRequest rq(cx);
    831895
     
    844908    return true;
    845909}
    846910
    847 bool CNetClient::OnInGame(void *context, CFsmEvent* event)
     911bool CNetClientWorker::OnInGame(void *context, CFsmEvent* event)
    848912{
    849913    // TODO: should split each of these cases into a separate method
    850914
    851     CNetClient* client = (CNetClient*)context;
     915    CNetClientWorker* client = (CNetClientWorker*)context;
    852916
    853917    CNetMessage* message = (CNetMessage*)event->GetParamRef();
    854918    if (message)
     
    872936
    873937    return true;
    874938}
     939
     940CNetClient::CNetClient(CGame* game, bool isLocalClient) :
     941    m_Worker(new CNetClientWorker(game, isLocalClient))
     942{
     943}
     944
     945CNetClient::~CNetClient()
     946{
     947    delete m_Worker;
     948}
     949
     950void CNetClient::SetUserName(const CStrW& username)
     951{
     952    m_Worker->m_UserName = username;
     953}
     954
     955bool CNetClient::SetupConnection(const CStr& server, const u16 port)
     956{
     957    return m_Worker->SetupConnection(server, port);
     958}
     959
     960
     961
     962
  • source/network/NetClient.h

     
    2323#include "network/NetHost.h"
    2424#include "scriptinterface/ScriptVal.h"
    2525
     26#include "ps/ThreadUtil.h"
    2627#include "ps/CStr.h"
    2728
    2829#include <deque>
     
    3334class CNetServer;
    3435class ScriptInterface;
    3536
     37class CNetClientWorker;
     38
    3639// NetClient session FSM states
    3740enum
    3841{
     
    7073    virtual ~CNetClient();
    7174
    7275    /**
    73      * We assume that adding a tracing function that's only called
    74      * during GC is better for performance than using a
    75      * PersistentRooted<T> where each value needs to be added to
    76      * the root set.
    77      */
    78     static void Trace(JSTracer *trc, void *data)
    79     {
    80         reinterpret_cast<CNetClient*>(data)->TraceMember(trc);
    81     }
    82 
    83     void TraceMember(JSTracer *trc);
    84 
    85     /**
    8676     * Set the user's name that will be displayed to all players.
    8777     * This must not be called after the connection setup.
    8878     */
     
    10595     * Destroy the connection to the server.
    10696     * This client probably cannot be used again.
    10797     */
     98
     99private:
     100    CStr m_GUID;
     101    CNetClientWorker* m_Worker;
     102};
     103
     104/**
     105 * Network client worker thread.
     106 *
     107 * Thread-safety:
     108 *
     109 *
     110 */
     111class CNetClientWorker : public CFsm
     112{
     113    NONCOPYABLE(CNetClientWorker);
     114
     115public:
     116    /**
     117     * Returns the GUID of the local client.
     118     * Used for distinguishing observers.
     119     */
     120    CStr GetGUID() const { return m_GUID; }
     121
     122    /**
     123     * Send a message to the server.
     124     * @param message message to send
     125     * @return true on success
     126     */
     127    bool SendMessage(const CNetMessage* message);
     128
     129    /**
     130     * Call when the network connection has been successfully initiated.
     131     */
     132    void HandleConnect();
     133
     134    /**
     135     * Call when the network connection has been lost.
     136     */
     137    void HandleDisconnect(u32 reason);
     138
     139    /**
     140     * Call when a message has been received from the network.
     141     */
     142    bool HandleMessage(CNetMessage* message);
     143
     144    /**
     145     * Get the script interface associated with this network client,
     146     * which is equivalent to the one used by the CGame in the constructor.
     147     */
     148    ScriptInterface& GetScriptInterface();
     149
     150private:
     151    friend class CNetClient;
     152    friend class CNetFileReceiveTask_ClientRejoin;
     153
     154    CNetClientWorker(CGame* game, bool isLocalClient);
     155  ~CNetClientWorker();
     156
     157    void SetUserName(const CStrW& username);
     158
     159    bool SetupConnection(const CStr& server, const u16 port);
     160
     161    /**
     162     * Destroy the connection to the server.
     163     * This client probably cannot be used again.
     164     */
    108165    void DestroyConnection();
    109166
    110167    /**
     
    154211    std::string TestReadGuiMessages();
    155212
    156213    /**
    157      * Get the script interface associated with this network client,
    158      * which is equivalent to the one used by the CGame in the constructor.
    159      */
    160     ScriptInterface& GetScriptInterface();
    161 
    162     /**
    163      * Send a message to the server.
    164      * @param message message to send
    165      * @return true on success
    166      */
    167     bool SendMessage(const CNetMessage* message);
    168 
    169     /**
    170      * Call when the network connection has been successfully initiated.
    171      */
    172     void HandleConnect();
    173 
    174     /**
    175      * Call when the network connection has been lost.
    176      */
    177     void HandleDisconnect(u32 reason);
    178 
    179     /**
    180      * Call when a message has been received from the network.
    181      */
    182     bool HandleMessage(CNetMessage* message);
    183 
    184     /**
    185214     * Call when the game has started and all data files have been loaded,
    186215     * to signal to the server that we are ready to begin the game.
    187216     */
     
    215244     */
    216245    void SendPausedMessage(bool pause);
    217246
    218 private:
    219247    // Net message / FSM transition handlers
    220248    static bool OnConnect(void* context, CFsmEvent* event);
    221249    static bool OnHandshake(void* context, CFsmEvent* event);
     
    282310
    283311    /// Time when the server was last checked for timeouts and bad latency
    284312    std::time_t m_LastConnectionCheck;
     313
     314        // Thread-related stuff:
     315
     316    static void* RunThread(void* data);
     317    void Run();
     318    bool RunStep();
     319
     320    pthread_t m_WorkerThread;
     321    CMutex m_WorkerMutex;
     322
     323    bool m_Shutdown; // protected by m_WorkerMutex
     324
     325    // Queues for messages sent by the game thread:
     326    std::vector<bool> m_StartGameQueue; // protected by m_WorkerMutex
     327    std::vector<std::string> m_GameAttributesQueue; // protected by m_WorkerMutex
     328    std::vector<u32> m_TurnLengthQueue; // protected by m_WorkerMutex
    285329};
    286330
    287331/// Global network client for the standard game
  • source/network/NetClientTurnManager.cpp

     
    3333#define NETCLIENTTURN_LOG(...)
    3434#endif
    3535
    36 CNetClientTurnManager::CNetClientTurnManager(CSimulation2& simulation, CNetClient& client, int clientId, IReplayLogger& replay)
     36CNetClientTurnManager::CNetClientTurnManager(CSimulation2& simulation, CNetClientWorker& client, int clientId, IReplayLogger& replay)
    3737    : CTurnManager(simulation, DEFAULT_TURN_LENGTH_MP, clientId, replay), m_NetClient(client)
    3838{
    3939}
  • source/network/NetClientTurnManager.h

     
    2121#include "simulation2/system/TurnManager.h"
    2222#include "NetMessage.h"
    2323
    24 class CNetClient;
     24class CNetClientWorker;
    2525
    2626/**
    2727 * Implementation of CTurnManager for network clients.
     
    3030{
    3131    NONCOPYABLE(CNetClientTurnManager);
    3232public:
    33     CNetClientTurnManager(CSimulation2& simulation, CNetClient& client, int clientId, IReplayLogger& replay);
     33    CNetClientTurnManager(CSimulation2& simulation, CNetClientWorker& client, int clientId, IReplayLogger& replay);
    3434
    3535    void OnSimulationMessage(CSimulationMessage* msg) override;
    3636
     
    4848
    4949    void NotifyFinishedUpdate(u32 turn) override;
    5050
    51     CNetClient& m_NetClient;
     51    CNetClientWorker& m_NetClient;
    5252};
    5353
    5454#endif // INCLUDED_NETCLIENTTURNMANAGER
  • source/network/NetSession.cpp

     
    3232
    3333static const int CHANNEL_COUNT = 1;
    3434
    35 CNetClientSession::CNetClientSession(CNetClient& client) :
     35CNetClientSession::CNetClientSession(CNetClientWorker& client) :
    3636    m_Client(client), m_FileTransferer(this), m_Host(NULL), m_Server(NULL), m_Stats(NULL)
    3737{
    3838}
  • source/network/NetSession.h

     
    3434 */
    3535extern const u32 MAXIMUM_HOST_TIMEOUT;
    3636
    37 class CNetClient;
     37class CNetClientWorker;
    3838class CNetServerWorker;
    3939
    4040class CNetStatsTable;
     
    6767    NONCOPYABLE(CNetClientSession);
    6868
    6969public:
    70     CNetClientSession(CNetClient& client);
     70    CNetClientSession(CNetClientWorker& client);
    7171    ~CNetClientSession();
    7272
    7373    bool Connect(const CStr& server, const u16 port, const bool isLocalClient);
     
    106106    CNetFileTransferer& GetFileTransferer() { return m_FileTransferer; }
    107107
    108108private:
    109     CNetClient& m_Client;
     109    CNetClientWorker& m_Client;
    110110
    111111    CNetFileTransferer m_FileTransferer;
    112112
  • source/ps/GameSetup/GameSetup.cpp

     
    14981498        bool ok = g_NetServer->SetupConnection(PS_DEFAULT_PORT);
    14991499        ENSURE(ok);
    15001500
    1501         g_NetClient = new CNetClient(g_Game, true);
     1501        g_NetClient = new CNetClientWorker(g_Game, true);
    15021502        g_NetClient->SetUserName(userName);
    15031503        g_NetClient->SetupConnection("127.0.0.1", PS_DEFAULT_PORT);
    15041504    }
     
    15061506    {
    15071507        InitPs(true, L"page_loading.xml", &scriptInterface, mpInitData);
    15081508
    1509         g_NetClient = new CNetClient(g_Game, false);
     1509        g_NetClient = new CNetClientWorker(g_Game, false);
    15101510        g_NetClient->SetUserName(userName);
    15111511
    15121512        CStr ip = args.Get("autostart-client");