Ticket #2447: readyv2.patch

File readyv2.patch, 27.4 KB (added by scythetwirler, 10 years ago)
  • binaries/data/mods/public/gui/common/modern/sprites.xml

     
    296296            size="0 0 22 22"
    297297        />
    298298    </sprite>
     299    <sprite name="ModernCheckOn">
     300        <image  texture="global/modern/checkbox-on.png"
     301            real_texture_placement="0 0 32 32"
     302        />
     303    </sprite>
     304    <sprite name="ModernCheckOff">
     305        <image  texture="global/modern/checkbox-off.png"
     306            real_texture_placement="0 0 32 32"
     307        />
     308    </sprite>
    299309</sprites>
  • binaries/data/mods/public/gui/gamesetup/gamesetup.js

     
    3131// (and therefore shouldn't send further messages to the network)
    3232var g_IsInGuiUpdate;
    3333
     34// Is this user ready
     35var g_IsReady;
     36
     37// Ready data just for the controller
     38var g_ReadyData = [];
     39
    3440var g_PlayerAssignments = {};
    3541
    3642// Default game setup attributes
     
    97103    {
    98104        cancelButton.tooltip = "Return to the lobby."
    99105    }
    100 
     106    if (!g_IsNetworked)     
     107        Engine.GetGUIObjectByName("toggleReady").hidden = true;
    101108}
    102109
    103110// Called after the map data is loaded and cached
     
    384391        // Find and report all joinings/leavings
    385392        for (var host in message.hosts)
    386393            if (! g_PlayerAssignments[host])
     394            {
    387395                addChatMessage({ "type": "connect", "username": message.hosts[host].name });
     396                g_ReadyData[host] = false;
     397            }
    388398
    389399        for (var host in g_PlayerAssignments)
    390400            if (! message.hosts[host])
     401            {
    391402                addChatMessage({ "type": "disconnect", "guid": host });
     403                delete g_ReadyData[host];
     404            }
    392405
    393406        // Update the player list
    394407        g_PlayerAssignments = message.hosts;
     
    416429        addChatMessage({ "type": "message", "guid": message.guid, "text": message.text });
    417430        break;
    418431
     432    // Singular client to host message
     433    case "ready":       
     434        if (!g_IsController)
     435            break;
     436        g_ReadyData[message.guid] = (message.text == 1);
     437        Engine.SetNetworkReadyData(g_ReadyData);
     438        updateReadyUI();
     439        break;
     440
     441    // Complete data sent by host to everyone.
     442    case "readydata":
     443        if (g_IsController)
     444            break;
     445        g_ReadyData = message.data;
     446        updateReadyUI();
     447        break;
     448
    419449    default:
    420450        error("Unrecognised net message type "+message.type);
    421451    }
     
    811841
    812842function launchGame()
    813843{
     844    if (g_IsNetworked && !g_IsReady)
     845    {
     846        for (var guid in g_PlayerAssignments)
     847        {
     848            if (g_PlayerAssignments[guid].name.split(" (")[0] == Engine.ConfigDB_GetValue("user", "playername") && g_PlayerAssignments[guid].player == -1)
     849                break; // Observers don't need to be ready.
     850            else
     851                return; // Host may have changed their own code.
     852        }
     853    }
    814854    if (g_IsNetworked && !g_IsController)
    815855    {
    816856        error("Only host can start game");
     
    11261166        if (i >= numPlayers)
    11271167            continue;
    11281168
    1129         var pName = Engine.GetGUIObjectByName("playerName["+i+"]");
    11301169        var pCiv = Engine.GetGUIObjectByName("playerCiv["+i+"]");
    11311170        var pCivText = Engine.GetGUIObjectByName("playerCivText["+i+"]");
    11321171        var pTeam = Engine.GetGUIObjectByName("playerTeam["+i+"]");
     
    11401179        // Common to all game types
    11411180        var color = iColorToString(getSetting(pData, pDefs, "Colour"));
    11421181        pColor.sprite = "colour:"+color+" 100";
    1143         pName.caption = getSetting(pData, pDefs, "Name");
    11441182
    11451183        var team = getSetting(pData, pDefs, "Team");
    11461184        var civ = getSetting(pData, pDefs, "Civ");
     
    11771215
    11781216    // Game attributes include AI settings, so update the player list
    11791217    updatePlayerList();
     1218
     1219    // We should have everyone confirm that the new settings are acceptable.
     1220    resetReadyData();
    11801221}
    11811222
    11821223function updateGameAttributes()
     
    14761517    Engine.GetGUIObjectByName("moreOptions").hidden = !Engine.GetGUIObjectByName("moreOptions").hidden;
    14771518}
    14781519
     1520function toggleReady()
     1521{
     1522    g_IsReady = !g_IsReady;
     1523    if (g_IsController)
     1524        Engine.SetNetworkReadyData(g_ReadyData);
     1525    if (g_IsReady)
     1526        Engine.SendNetworkReady(1);
     1527    else
     1528        Engine.SendNetworkReady(0);
     1529}
     1530
     1531function updateReadyUI()
     1532{
     1533    var allReady = true;
     1534    for (var guid in g_PlayerAssignments)
     1535    {
     1536        // We don't really care whether observers are ready.
     1537        if (g_PlayerAssignments[guid].player == -1)
     1538            return;
     1539        if (g_ReadyData[guid])
     1540            Engine.GetGUIObjectByName("playerReadySprite[" + String(g_PlayerAssignments[guid].player - 1) + "]").sprite = "ModernCheckOn";
     1541        else if (!g_IsNetworked)
     1542            Engine.GetGUIObjectByName("playerReadySprite[" + String(g_PlayerAssignments[guid].player - 1) + "]").sprite = "ModernCheckOn";
     1543        else
     1544        {
     1545            Engine.GetGUIObjectByName("playerReadySprite[" + String(g_PlayerAssignments[guid].player - 1) + "]").sprite = "ModernCheckOff";
     1546            allReady = false;
     1547        }
     1548    }
     1549    // AIs are always ready.
     1550    for (var playerid = 0; playerid < MAX_PLAYERS; playerid++)
     1551    {
     1552        if (g_GameAttributes.settings.PlayerData[playerid])
     1553        {
     1554            if (g_GameAttributes.settings.PlayerData[playerid].AI != "" || g_GameAttributes.settings.PlayerData[playerid].Name == "Unassigned")
     1555                Engine.GetGUIObjectByName("playerReadySprite[" + String(playerid) + "]").sprite = "ModernCheckOn";
     1556        }
     1557    }
     1558
     1559    // The host is not allowed to start until everyone is ready.
     1560    if (g_IsNetworked && g_IsController)
     1561        Engine.GetGUIObjectByName("startGame").enabled = allReady;
     1562}
     1563
     1564function resetReadyData()
     1565{
     1566    g_IsReady = false;
     1567    for (var guid in g_PlayerAssignments)
     1568    {
     1569        if (g_ReadyData[guid])
     1570        {
     1571            if (!g_IsNetworked)
     1572                g_ReadyData[guid] = true;
     1573            g_ReadyData[guid] = false;
     1574        }
     1575    }
     1576    updateReadyUI();
     1577}
    14791578////////////////////////////////////////////////////////////////////////////////////////////////
    14801579// Basic map filters API
    14811580
  • binaries/data/mods/public/gui/gamesetup/gamesetup.xml

     
    1414        <object style="TitleText" type="text" size="50%-128 4 50%+128 36">
    1515            Match Setup
    1616        </object>
    17    
     17
    1818        <object type="image" style="ModernDialog" size="50%-190 50%-80 50%+190 50%+80" name="loadingWindow">
    1919
    2020            <object type="text" style="TitleText" size="50%-128 0%-16 50%+128 16">
     
    3232            <action on="Tick">
    3333                onTick();
    3434            </action>
    35            
     35
    3636            <!-- Number of Players-->
    3737            <object size="24 26 224 54">
    3838
     
    4040                <object size="0 0 150 28">
    4141                    <object size="0 0 100% 100%" type="text" style="ModernRightLabelText">Number of players:</object>
    4242                </object>
    43                    
     43
    4444                <!-- Number of Players-->
    4545                <object size="150 0 200 28">
    4646                    <object name="numPlayersText" size="0 0 100% 100%" type="text" style="ModernLeftLabelText"/>
     
    5353                        <action on="SelectionChange">selectNumPlayers(this.list_data[this.selected]);</action>
    5454                    </object>
    5555                </object>
     56            </object>
    5657
    57             </object>
    58            
    5958            <!-- Player assignments -->
    6059            <object size="24 59 100%-440 358" type="image" sprite="ModernDarkBoxGold" name="playerAssignmentsPannel">
    6160                <object size="0 6 100% 30">
    62                     <object name="playerNameHeading" type="text" style="ModernLabelText" size="0 0 20% 100%">Player Name</object>
    63                     <object name="playerPlacementHeading" type="text" style="ModernLabelText" size="20%+5 0 50% 100%">Player Placement</object>
    64                     <object name="playerCivHeading" type="text" style="ModernLabelText" size="50%+65 0 85% 100%">Civilization</object>
     61                    <object name="playerPlacementHeading" type="text" style="ModernLabelText" size="5 0 40% 100%">Player Name</object>
     62                    <object name="playerCivHeading" type="text" style="ModernLabelText" size="40%+65 0 75%-26 100%">Civilization</object>
    6563                    <object name="civInfoButton"
    6664                        type="button"
    6765                        sprite="iconInfoGold"
    6866                        sprite_over="iconInfoWhite"
    69                         size="82%-8 0 82%+8 16"
     67                        size="57.5%+68 0 57.5%+84 16"
    7068                        tooltip_style="onscreenToolTip"
    7169                        tooltip="View civilization info"
    7270                    >
     
    7472                            Engine.PushGuiPage("page_civinfo.xml");
    7573                        ]]></action>
    7674                    </object>
    77                     <object name="playerTeamHeading" type="text" style="ModernLabelText" size="85%+5 0 100%-5 100%">Team</object>
     75                    <object name="playerTeamHeading" type="text" style="ModernLabelText" size="75%+5 0 90%-5 100%">Team</object>
     76                    <object name="playerReadyHeading" type="text" style="ModernLabelText" size="90%+5 0 100%-5 100%">Ready</object>
    7877                </object>
    7978                <object size="1 36 100%-1 100%">
    8079                    <repeat count="8">
    8180                        <object name="playerBox[n]" size="0 0 100% 32" hidden="true">
    8281                            <object name="playerColour[n]" type="image" size="0 0 100% 100%"/>
    83                             <object name="playerName[n]" type="text" style="ModernLabelText" size="0 2 20% 30"/>
    84                             <object name="playerAssignment[n]" type="dropdown" style="ModernDropDown" size="20%+5 2 50% 30" tooltip_style="onscreenToolTip" tooltip="Select player."/>
    85                             <object name="playerConfig[n]" type="button" style="StoneButton" size="50%+5 6 50%+60 26"
     82                            <object name="playerAssignment[n]" type="dropdown" style="ModernDropDown" size="5 2 40% 30" tooltip_style="onscreenToolTip" tooltip="Select player."/>
     83                            <object name="playerConfig[n]" type="button" style="StoneButton" size="40%+5 6 40%+60 26"
    8684                                tooltip_style="onscreenToolTip"
    8785                                tooltip="Configure AI settings."
    8886                                font="serif-bold-stroke-12"
    8987                            >Settings</object>
    90                             <object name="playerCiv[n]" type="dropdown" style="ModernDropDown" size="50%+65 2 85% 30" tooltip_style="onscreenToolTip" tooltip="Select player's civilization."/>
    91                             <object name="playerCivText[n]" type="text" style="ModernLabelText" size="50%+65 0 85% 30"/>
    92                             <object name="playerTeam[n]" type="dropdown" style="ModernDropDown" size="85%+5 2 100%-5 30" tooltip_style="onscreenToolTip" tooltip="Select player's team."/>
    93                             <object name="playerTeamText[n]" type="text" style="ModernLabelText" size="85%+5 0 100%-5 100%"/>
     88                            <object name="playerCiv[n]" type="dropdown" style="ModernDropDown" size="40%+65 2 75% 30" tooltip_style="onscreenToolTip" tooltip="Select player's civilization."/>
     89                            <object name="playerCivText[n]" type="text" style="ModernLabelText" size="40%+65 0 75% 30"/>
     90                            <object name="playerTeam[n]" type="dropdown" style="ModernDropDown" size="75%+5 2 90%-5 30" tooltip_style="onscreenToolTip" tooltip="Select player's team."/>
     91                            <object name="playerTeamText[n]" type="text" style="ModernLabelText" size="75%+5 0 90%-5 100%"/>
     92                            <object name="playerReadySprite[n]" type="image" sprite="ModernCheckOff" size="95%-16 0 95%+16 32"/>
    9493                        </object>
    9594                    </repeat>
    9695                </object>
    9796            </object>
    98             <object size="24 64 100%-460 358" type="image" sprite="CoverFillDark" name="playerAssignmentsPannelCover" hidden="true"/>
     97            <object size="24 64 100%-460 358" type="image" sprite="CoverFillDark" name="playerAssignmentsPanelCover" hidden="true"/>
    9998            <!-- Map selection -->
    10099           
    101100           
     
    112111                <object name="mapSelectionText" type="text" style="ModernLeftLabelText" size="0 64 100% 94"  hidden="true"/>
    113112                <object name="mapSizeText" type="text" style="ModernLeftLabelText" size="0 96 100% 126" hidden="true"/>
    114113            </object>
    115            
     114
    116115            <object name="mapTypeSelection"
    117116                type="dropdown"
    118117                style="ModernDropDown"
     
    159158            </object>
    160159
    161160            <!-- Chat window -->
    162             <object name="chatPanel" size="24 370 100%-440 100%-60" type="image" sprite="ModernDarkBoxGold">
     161            <object name="chatPanel" size="24 370 100%-440 100%-58" type="image" sprite="ModernDarkBoxGold">
    163162                <object name="chatText" size="2 2 100%-2 100%-26" type="text" style="ChatPanel"/>
    164163
    165164                <object name="chatInput" size="4 100%-24 100%-76 100%-4" type="input" style="ModernInput">
     
    179178                textcolor="white"
    180179                sprite="BackgroundTranslucent"
    181180                hidden="true"
    182                 size="100%-700 100%-56 100%-312 100%-24"
     181                size="25 100%-56 100%-445 100%-24"
    183182            >[Tooltip text]</object>
    184183
     184            <!-- Ready Button -->
     185            <object
     186                name="toggleReady"
     187                type="button"
     188                style="StoneButton"
     189                hidden="false"
     190                size="100%-425 100%-52 100%-305 100%-24"
     191                tooltip_style="onscreenToolTip"
     192                tooltip="Accept the current settings and state you are ready to play!"
     193                enabled="true"
     194            >
     195                Set/Unset Ready
     196                <action on="Press">toggleReady();</action>
     197            </object>
     198
    185199            <!-- Start Button -->
    186200            <object
    187201                name="startGame"
    188202                type="button"
    189203                style="StoneButton"
    190                 size="100%-308 100%-52 100%-168 100%-24"
     204                size="100%-285 100%-52 100%-165 100%-24"
    191205                tooltip_style="onscreenToolTip"
    192206                tooltip="Start a new game with the current settings."
    193207                enabled="false"
     
    202216                caption="Back"
    203217                type="button"
    204218                style="StoneButton"
    205                 size="100%-164 100%-52 100%-24 100%-24"
     219                size="100%-145 100%-52 100%-25 100%-24"
    206220                tooltip_style="onscreenToolTip"
    207221            >
    208222                <action on="Press">
     
    215229                    ]]>
    216230                </action>
    217231            </object>
    218            
     232
    219233            <!-- Options -->
    220234            <object name="gameOptionsBox" size="100%-425 497 100%-25 525">
    221235                <!-- More Options Button -->
  • source/gui/scripting/ScriptFunctions.cpp

     
    272272
    273273    g_NetServer->UpdateGameAttributes(attribs, *(pCxPrivate->pScriptInterface));
    274274}
     275void SetNetworkReadyData(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal attribs)
     276{
     277    ENSURE(g_NetServer);
    275278
     279    g_NetServer->UpdateReadyData(attribs, *(pCxPrivate->pScriptInterface));
     280}
     281
    276282void StartNetworkHost(ScriptInterface::CxPrivate* pCxPrivate, std::wstring playerName)
    277283{
    278284    ENSURE(!g_NetClient);
     
    350356    g_NetClient->SendChatMessage(message);
    351357}
    352358
     359void SendNetworkReady(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int message)
     360{
     361    ENSURE(g_NetClient);
     362
     363    g_NetClient->SendReadyMessage(message);
     364}
     365
    353366std::vector<CScriptValRooted> GetAIs(ScriptInterface::CxPrivate* pCxPrivate)
    354367{
    355368    return ICmpAIManager::GetAIs(*(pCxPrivate->pScriptInterface));
     
    837850    scriptInterface.RegisterFunction<void, &DisconnectNetworkGame>("DisconnectNetworkGame");
    838851    scriptInterface.RegisterFunction<CScriptVal, &PollNetworkClient>("PollNetworkClient");
    839852    scriptInterface.RegisterFunction<void, CScriptVal, &SetNetworkGameAttributes>("SetNetworkGameAttributes");
     853    scriptInterface.RegisterFunction<void, CScriptVal, &SetNetworkReadyData>("SetNetworkReadyData");
    840854    scriptInterface.RegisterFunction<void, int, std::string, &AssignNetworkPlayer>("AssignNetworkPlayer");
    841855    scriptInterface.RegisterFunction<void, std::wstring, &SendNetworkChat>("SendNetworkChat");
     856    scriptInterface.RegisterFunction<void, int, &SendNetworkReady>("SendNetworkReady");
    842857    scriptInterface.RegisterFunction<std::vector<CScriptValRooted>, &GetAIs>("GetAIs");
    843858    scriptInterface.RegisterFunction<CScriptValRooted, &GetEngineInfo>("GetEngineInfo");
    844859
  • source/network/NetClient.cpp

     
    8787    AddTransition(NCS_INITIAL_GAMESETUP, (uint)NMT_GAME_SETUP, NCS_PREGAME, (void*)&OnGameSetup, context);
    8888
    8989    AddTransition(NCS_PREGAME, (uint)NMT_CHAT, NCS_PREGAME, (void*)&OnChat, context);
     90    AddTransition(NCS_PREGAME, (uint)NMT_READY, NCS_PREGAME, (void*)&OnReady, context);
     91    AddTransition(NCS_PREGAME, (uint)NMT_READY_DATA, NCS_PREGAME, (void*)&OnReadyData, context);
    9092    AddTransition(NCS_PREGAME, (uint)NMT_GAME_SETUP, NCS_PREGAME, (void*)&OnGameSetup, context);
    9193    AddTransition(NCS_PREGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_PREGAME, (void*)&OnPlayerAssignment, context);
    9294    AddTransition(NCS_PREGAME, (uint)NMT_GAME_START, NCS_LOADING, (void*)&OnGameStart, context);
     
    254256    SendMessage(&chat);
    255257}
    256258
     259void CNetClient::SendReadyMessage(const int status)
     260{
     261    CReadyMessage readyStatus;
     262    readyStatus.m_Status = status;
     263    SendMessage(&readyStatus);
     264}
     265
    257266bool CNetClient::HandleMessage(CNetMessage* message)
    258267{
    259268    // Handle non-FSM messages first
     
    419428    return true;
    420429}
    421430
     431bool CNetClient::OnReady(void* context, CFsmEvent* event)
     432{
     433    ENSURE(event->GetType() == (uint)NMT_READY);
     434
     435    CNetClient* client = (CNetClient*)context;
     436
     437    CReadyMessage* message = (CReadyMessage*)event->GetParamRef();
     438
     439    CScriptValRooted msg;
     440    client->GetScriptInterface().Eval("({'type':'ready'})", msg);
     441    client->GetScriptInterface().SetProperty(msg.get(), "guid", std::string(message->m_GUID), false);
     442    client->GetScriptInterface().SetProperty(msg.get(), "text", int (message->m_Status), false);
     443    client->PushGuiMessage(msg);
     444
     445    return true;
     446}
     447
    422448bool CNetClient::OnGameSetup(void* context, CFsmEvent* event)
    423449{
    424450    ENSURE(event->GetType() == (uint)NMT_GAME_SETUP);
     
    437463    return true;
    438464}
    439465
     466bool CNetClient::OnReadyData(void* context, CFsmEvent* event)
     467{
     468    ENSURE(event->GetType() == (uint)NMT_READY_DATA);
     469
     470    CNetClient* client = (CNetClient*)context;
     471
     472    CReadyDataMessage* message = (CReadyDataMessage*)event->GetParamRef();
     473
     474    client->m_ReadyData = message->m_Data;
     475
     476    CScriptValRooted msg;
     477    client->GetScriptInterface().Eval("({'type':'readydata'})", msg);
     478    client->GetScriptInterface().SetProperty(msg.get(), "data", message->m_Data, false);
     479    client->PushGuiMessage(msg);
     480
     481    return true;
     482}
     483
    440484bool CNetClient::OnPlayerAssignment(void* context, CFsmEvent* event)
    441485{
    442486    ENSURE(event->GetType() == (uint)NMT_PLAYER_ASSIGNMENT);
  • source/network/NetClient.h

     
    164164    void LoadFinished();
    165165
    166166    void SendChatMessage(const std::wstring& text);
     167   
     168    void SendReadyMessage(const int status);
    167169
    168170private:
    169171    // Net message / FSM transition handlers
     
    172174    static bool OnHandshakeResponse(void* context, CFsmEvent* event);
    173175    static bool OnAuthenticate(void* context, CFsmEvent* event);
    174176    static bool OnChat(void* context, CFsmEvent* event);
     177    static bool OnReady(void* context, CFsmEvent* event);
     178    static bool OnReadyData(void* context, CFsmEvent* event);
    175179    static bool OnGameSetup(void* context, CFsmEvent* event);
    176180    static bool OnPlayerAssignment(void* context, CFsmEvent* event);
    177181    static bool OnInGame(void* context, CFsmEvent* event);
     
    204208
    205209    /// Latest copy of game setup attributes heard from the server
    206210    CScriptValRooted m_GameAttributes;
     211   
     212    /// Latest copy of ready data heard from the server
     213    CScriptValRooted m_ReadyData;
    207214
    208215    /// Latest copy of player assignments heard from the server
    209216    PlayerAssignmentMap m_PlayerAssignments;
  • source/network/NetMessage.cpp

     
    174174    case NMT_CHAT:
    175175        pNewMessage = new CChatMessage;
    176176        break;
     177   
     178    case NMT_READY:
     179        pNewMessage = new CReadyMessage;
     180        break;
    177181
     182    case NMT_READY_DATA:
     183        pNewMessage = new CReadyDataMessage(scriptInterface);
     184        break;
     185
    178186    case NMT_SIMULATION_COMMAND:
    179187        pNewMessage = new CSimulationMessage(scriptInterface);
    180188        break;
  • source/network/NetMessage.h

     
    147147    ScriptInterface& m_ScriptInterface;
    148148};
    149149
     150/**
     151 * Special message type for updated ready data.
     152 */
     153class CReadyDataMessage : public CNetMessage
     154{
     155    NONCOPYABLE(CReadyDataMessage);
     156public:
     157    CReadyDataMessage(ScriptInterface& scriptInterface);
     158    CReadyDataMessage(ScriptInterface& scriptInterface, jsval data);
     159    virtual u8* Serialize(u8* pBuffer) const;
     160    virtual const u8* Deserialize(const u8* pStart, const u8* pEnd);
     161    virtual size_t GetSerializedLength() const;
     162    virtual CStr ToString() const;
     163
     164    CScriptValRooted m_Data;
     165private:
     166    ScriptInterface& m_ScriptInterface;
     167};
    150168// This time, the classes are created
    151169#include "NetMessages.h"
    152170
  • source/network/NetMessageSim.cpp

     
    219219    stream << "CGameSetupMessage { m_Data: " << source << " }";
    220220    return CStr(stream.str());
    221221}
     222
     223CReadyDataMessage::CReadyDataMessage(ScriptInterface& scriptInterface) :
     224    CNetMessage(NMT_READY_DATA), m_ScriptInterface(scriptInterface)
     225{
     226}
     227
     228CReadyDataMessage::CReadyDataMessage(ScriptInterface& scriptInterface, jsval data) :
     229    CNetMessage(NMT_READY_DATA), m_ScriptInterface(scriptInterface),
     230    m_Data(scriptInterface.GetContext(), data)
     231{
     232}
     233
     234u8* CReadyDataMessage::Serialize(u8* pBuffer) const
     235{
     236    // TODO: ought to handle serialization exceptions
     237
     238    u8* pos = CNetMessage::Serialize(pBuffer);
     239    CBufferBinarySerializer serializer(m_ScriptInterface, pos);
     240    serializer.ScriptVal("command", m_Data);
     241    return serializer.GetBuffer();
     242}
     243
     244const u8* CReadyDataMessage::Deserialize(const u8* pStart, const u8* pEnd)
     245{
     246    // TODO: ought to handle serialization exceptions
     247
     248    const u8* pos = CNetMessage::Deserialize(pStart, pEnd);
     249    std::istringstream stream(std::string(pos, pEnd));
     250    CStdDeserializer deserializer(m_ScriptInterface, stream);
     251    deserializer.ScriptVal("command", m_Data);
     252    return pEnd;
     253}
     254
     255size_t CReadyDataMessage::GetSerializedLength() const
     256{
     257    CLengthBinarySerializer serializer(m_ScriptInterface);
     258    serializer.ScriptVal("command", m_Data);
     259    return CNetMessage::GetSerializedLength() + serializer.GetLength();
     260}
     261
     262CStr CReadyDataMessage::ToString() const
     263{
     264    std::string source = utf8_from_wstring(m_ScriptInterface.ToString(m_Data.get()));
     265
     266    std::stringstream stream;
     267    stream << "CReadyDataMessage { m_Data: " << source << " }";
     268    return CStr(stream.str());
     269}
     270
  • source/network/NetMessages.h

     
    4646    NMT_AUTHENTICATE,       // Authentication stage
    4747    NMT_AUTHENTICATE_RESULT,
    4848    NMT_CHAT,       // Common chat message
     49    NMT_READY,
     50    NMT_READY_DATA,
    4951    NMT_GAME_SETUP,
    5052    NMT_PLAYER_ASSIGNMENT,
    5153
     
    118120    NMT_FIELD(CStrW, m_Message)
    119121END_NMT_CLASS()
    120122
     123START_NMT_CLASS_(Ready, NMT_READY)
     124    NMT_FIELD(CStr8, m_GUID)
     125    NMT_FIELD_INT(m_Status, u8, 1)
     126END_NMT_CLASS()
     127
    121128START_NMT_CLASS_(PlayerAssignment, NMT_PLAYER_ASSIGNMENT)
    122129    NMT_START_ARRAY(m_Hosts)
    123130        NMT_FIELD(CStr8, m_GUID)
  • source/network/NetServer.cpp

     
    548548
    549549    session->AddTransition(NSS_PREGAME, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context);
    550550    session->AddTransition(NSS_PREGAME, (uint)NMT_CHAT, NSS_PREGAME, (void*)&OnChat, context);
     551    session->AddTransition(NSS_PREGAME, (uint)NMT_READY, NSS_PREGAME, (void*)&OnReady, context);
    551552    session->AddTransition(NSS_PREGAME, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnLoadedGame, context);
    552553
    553554    session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnJoinSyncingLoadedGame, context);
     
    578579    CGameSetupMessage gameSetupMessage(GetScriptInterface());
    579580    gameSetupMessage.m_Data = m_GameAttributes;
    580581    session->SendMessage(&gameSetupMessage);
     582   
     583    CReadyDataMessage readyDataMessage(GetScriptInterface());
     584    readyDataMessage.m_Data = m_ReadyData;
     585    session->SendMessage(&readyDataMessage);
    581586
    582587    CPlayerAssignmentMessage assignMessage;
    583588    ConstructPlayerAssignmentMessage(assignMessage);
     
    860865    return true;
    861866}
    862867
     868bool CNetServerWorker::OnReady(void* context, CFsmEvent* event)
     869{
     870    ENSURE(event->GetType() == (uint)NMT_READY);
     871
     872    CNetServerSession* session = (CNetServerSession*)context;
     873    CNetServerWorker& server = session->GetServer();
     874
     875    CReadyMessage* message = (CReadyMessage*)event->GetParamRef();
     876
     877    message->m_GUID = session->GetGUID();
     878
     879    server.Broadcast(message);
     880
     881    return true;
     882}
     883
    863884bool CNetServerWorker::OnLoadedGame(void* context, CFsmEvent* event)
    864885{
    865886    ENSURE(event->GetType() == (uint)NMT_LOADED_GAME);
     
    9821003    Broadcast(&gameSetupMessage);
    9831004}
    9841005
     1006void CNetServerWorker::UpdateReadyData(const CScriptValRooted& attrs)
     1007{
     1008    m_ReadyData = attrs;
     1009
     1010    if (!m_Host)
     1011        return;
     1012
     1013    CReadyDataMessage readyMessage(GetScriptInterface());
     1014    readyMessage.m_Data = m_ReadyData;
     1015    Broadcast(&readyMessage);
     1016}
     1017
    9851018CStrW CNetServerWorker::SanitisePlayerName(const CStrW& original)
    9861019{
    9871020    const size_t MAX_LENGTH = 32;
     
    10691102    m_Worker->m_GameAttributesQueue.push_back(attrsJSON);
    10701103}
    10711104
     1105void CNetServer::UpdateReadyData(const CScriptVal& attrs, ScriptInterface& scriptInterface)
     1106{
     1107    // Pass the attributes as JSON, since that's the easiest safe
     1108    // cross-thread way of passing script data
     1109    std::string attrsJSON = scriptInterface.StringifyJSON(attrs.get(), false);
     1110
     1111    CScopeLock lock(m_Worker->m_WorkerMutex);
     1112    m_Worker->m_ReadyDataQueue.push_back(attrsJSON);
     1113}
     1114
    10721115void CNetServer::SetTurnLength(u32 msecs)
    10731116{
    10741117    CScopeLock lock(m_Worker->m_WorkerMutex);
  • source/network/NetServer.h

     
    137137    void UpdateGameAttributes(const CScriptVal& attrs, ScriptInterface& scriptInterface);
    138138
    139139    /**
     140     * Call from the GUI to update the readiness of players.
     141     * This must be called at least once before starting the game.
     142     * The changes will be asynchronously propagated to all clients.
     143     * @param attrs ready data, in the script context of scriptInterface
     144     */
     145    void UpdateReadyData(const CScriptVal& attrs, ScriptInterface& scriptInterface);
     146
     147    /**
    140148     * Set the turn length to a fixed value.
    141149     * TODO: we should replace this with some adapative lag-dependent computation.
    142150     */
     
    211219    void UpdateGameAttributes(const CScriptValRooted& attrs);
    212220
    213221    /**
     222     * Call from the GUI to update the readiness of players.
     223     * This must be called at least once before starting the game.
     224     * The changes will be propagated to all clients.
     225     * @param attrs ready data, in the script context of GetScriptInterface()
     226     */
     227    void UpdateReadyData(const CScriptValRooted& attrs);
     228
     229    /**
    214230     * Make a player name 'nicer' by limiting the length and removing forbidden characters etc.
    215231     */
    216232    static CStrW SanitisePlayerName(const CStrW& original);
     
    245261    static bool OnAuthenticate(void* context, CFsmEvent* event);
    246262    static bool OnInGame(void* context, CFsmEvent* event);
    247263    static bool OnChat(void* context, CFsmEvent* event);
     264    static bool OnReady(void* context, CFsmEvent* event);
    248265    static bool OnLoadedGame(void* context, CFsmEvent* event);
    249266    static bool OnJoinSyncingLoadedGame(void* context, CFsmEvent* event);
    250267    static bool OnDisconnect(void* context, CFsmEvent* event);
     
    267284    PlayerAssignmentMap m_PlayerAssignments;
    268285
    269286    CScriptValRooted m_GameAttributes;
     287    CScriptValRooted m_ReadyData;
    270288
    271289    int m_AutostartPlayers;
    272290
     
    321339    std::vector<std::pair<int, CStr> > m_AssignPlayerQueue; // protected by m_WorkerMutex
    322340    std::vector<bool> m_StartGameQueue; // protected by m_WorkerMutex
    323341    std::vector<std::string> m_GameAttributesQueue; // protected by m_WorkerMutex
     342    std::vector<std::string> m_ReadyDataQueue; // protected by m_WorkerMutex
    324343    std::vector<u32> m_TurnLengthQueue; // protected by m_WorkerMutex
    325344};
    326345