Ticket #2447: readyv4.patch

File readyv4.patch, 29.8 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// If no one has changed ready status, we have no need to spam the settings changed message.
     38// 2 - Host's initial ready, suppressed settings message, 1 - Will show settings message, <=0 - Suppressed settings message
     39var g_ReadyChanged = 2;
     40
    3441var g_PlayerAssignments = {};
    3542
    3643// Default game setup attributes
     
    97104    {
    98105        cancelButton.tooltip = "Return to the lobby."
    99106    }
    100 
    101107}
    102108
    103109// Called after the map data is loaded and cached
     
    412418        break;
    413419
    414420    case "players":
     421        var resetReady = false;
     422        var newPlayer = "";
    415423        // Find and report all joinings/leavings
    416424        for (var host in message.hosts)
     425        {
    417426            if (! g_PlayerAssignments[host])
     427            {
    418428                addChatMessage({ "type": "connect", "username": message.hosts[host].name });
     429                newPlayer = host;
     430            }
     431        }
    419432
    420433        for (var host in g_PlayerAssignments)
     434        {
    421435            if (! message.hosts[host])
     436            {
    422437                addChatMessage({ "type": "disconnect", "guid": host });
    423 
     438                playersChanged = "leave";
     439                if (g_PlayerAssignments[host] != -1)
     440                    resetReady = true; // Observers shouldn't reset ready.
     441            }
     442        }
     443       
    424444        // Update the player list
    425445        g_PlayerAssignments = message.hosts;
    426446        updatePlayerList();
    427 
     447        if (g_PlayerAssignments[newPlayer])
     448        {
     449            if (g_PlayerAssignments[newPlayer].player != -1)
     450                resetReady = true;
     451        }
     452       
     453        if (resetReady)
     454            resetReadyData(); // Observers shouldn't reset ready.
     455        updateReadyUI();       
    428456        if (g_IsController)
    429457            sendRegisterGameStanza();
    430458        break;
     
    447475        addChatMessage({ "type": "message", "guid": message.guid, "text": message.text });
    448476        break;
    449477
     478    // Singular client to host message
     479    case "ready":
     480        g_ReadyChanged -= 1;
     481        warn(String(g_ReadyChanged));
     482        if (g_ReadyChanged < 1)
     483        {
     484            if (parseInt(message.text) == 1)
     485                addChatMessage({ "type": "ready", "guid": message.guid, "text": "is ready!"});
     486            else
     487                addChatMessage({ "type": "ready", "guid": message.guid, "text": "is not ready."});
     488        }
     489        if (!g_IsController)
     490            break;
     491        g_PlayerAssignments[message.guid].status = (parseInt(message.text) == 1);
     492        Engine.AssignNetworkPlayerStatus(parseInt(message.text), message.guid);
     493        updateReadyUI();
     494        break;
     495
    450496    default:
    451497        error("Unrecognised net message type "+message.type);
    452498    }
     
    705751            if (g_IsNetworked)
    706752                Engine.AssignNetworkPlayer(player, "");
    707753            else
    708                 g_PlayerAssignments = { "local": { "name": "You", "player": 1, "civ": "", "team": -1} };
     754                g_PlayerAssignments = { "local": { "name": "You", "player": 1, "civ": "", "team": -1, "ready": 0} };
    709755        }
    710756    }
    711757
     
    822868    // Reset player assignments on map change
    823869    if (!g_IsNetworked)
    824870    {   // Slot 1
    825         g_PlayerAssignments = { "local": { "name": "You", "player": 1, "civ": "", "team": -1} };
     871        g_PlayerAssignments = { "local": { "name": "You", "player": 1, "civ": "", "team": -1, "ready": 0} };
    826872    }
    827873    else
    828874    {
     
    842888
    843889function launchGame()
    844890{
     891    if (g_IsNetworked && !g_IsReady)
     892    {
     893        for (var guid in g_PlayerAssignments)
     894        {
     895            if (g_PlayerAssignments[guid].name.split(" (")[0] == Engine.ConfigDB_GetValue("user", "playername") && g_PlayerAssignments[guid].player == -1)
     896                break; // Observers don't need to be ready.
     897            else
     898                return; // Host may have changed their own code.
     899        }
     900    }
    845901    if (g_IsNetworked && !g_IsController)
    846902    {
    847903        error("Only host can start game");
     
    11841240        if (i >= numPlayers)
    11851241            continue;
    11861242
    1187         var pName = Engine.GetGUIObjectByName("playerName["+i+"]");
     1243        var pName = Engine.GetGUIObjectByName("playerName["+i+"]"); 
    11881244        var pCiv = Engine.GetGUIObjectByName("playerCiv["+i+"]");
    11891245        var pCivText = Engine.GetGUIObjectByName("playerCivText["+i+"]");
    11901246        var pTeam = Engine.GetGUIObjectByName("playerTeam["+i+"]");
     
    11981254        // Common to all game types
    11991255        var color = iColorToString(getSetting(pData, pDefs, "Colour"));
    12001256        pColor.sprite = "colour:"+color+" 100";
    1201         pName.caption = getSetting(pData, pDefs, "Name");
     1257        pName.caption = getSetting(pData, pDefs, "Name"); 
    12021258
    12031259        var team = getSetting(pData, pDefs, "Team");
    12041260        var civ = getSetting(pData, pDefs, "Civ");
     
    12351291
    12361292    // Game attributes include AI settings, so update the player list
    12371293    updatePlayerList();
     1294
     1295    // We should have everyone confirm that the new settings are acceptable.
     1296    resetReadyData();   
    12381297}
    12391298
    12401299function updateGameAttributes()
     
    14041463                        swapPlayers(guid, playerSlot);
    14051464
    14061465                    Engine.SetNetworkGameAttributes(g_GameAttributes);
     1466                    updateReadyUI();
    14071467                }
    14081468            };
    14091469        }
     
    14851545
    14861546function addChatMessage(msg)
    14871547{
    1488     var username = escapeText(msg.username || g_PlayerAssignments[msg.guid].name);
    1489     var message = escapeText(msg.text);
     1548    var username = "";
     1549    if (msg.username || g_PlayerAssignments[msg.guid])
     1550        username = escapeText(msg.username || g_PlayerAssignments[msg.guid].name);
    14901551
     1552    var message = "";
     1553    if (msg.text)
     1554        message = escapeText(msg.text);
     1555
    14911556    // TODO: Maybe host should have distinct font/color?
    14921557    var color = "white";
    14931558
    1494     if (g_PlayerAssignments[msg.guid] && g_PlayerAssignments[msg.guid].player != -1)
    1495     {   // Valid player who has been assigned - get player colour
    1496         var player = g_PlayerAssignments[msg.guid].player - 1;
    1497         var mapName = g_GameAttributes.map;
    1498         var mapData = loadMapData(mapName);
    1499         var mapSettings = (mapData && mapData.settings ? mapData.settings : {});
    1500         var pData = mapSettings.PlayerData ? mapSettings.PlayerData[player] : {};
    1501         var pDefs = g_DefaultPlayerData ? g_DefaultPlayerData[player] : {};
     1559    if (msg.guid)
     1560    {
     1561        if (g_PlayerAssignments[msg.guid] && g_PlayerAssignments[msg.guid].player != -1)
     1562        {   // Valid player who has been assigned - get player colour
     1563            var player = g_PlayerAssignments[msg.guid].player - 1;
     1564            var mapName = g_GameAttributes.map;
     1565            var mapData = loadMapData(mapName);
     1566            var mapSettings = (mapData && mapData.settings ? mapData.settings : {});
     1567            var pData = mapSettings.PlayerData ? mapSettings.PlayerData[player] : {};
     1568            var pDefs = g_DefaultPlayerData ? g_DefaultPlayerData[player] : {};
    15021569
    1503         color = iColorToString(getSetting(pData, pDefs, "Colour"));
     1570            color = iColorToString(getSetting(pData, pDefs, "Colour"));
     1571        }
    15041572    }
    15051573
    15061574    var formatted;
     
    15181586        formatted = '[font="serif-bold-13"]<[color="'+ color +'"]' + username + '[/color]>[/font] ' + message;
    15191587        break;
    15201588
     1589    case "ready":
     1590        formatted = '[font="serif-bold-13"][color="'+ color +'"]*' + username + " " + message + '[/color][/font]';
     1591        break;
     1592
     1593    case "settings":
     1594        formatted = '[font="serif-bold-13"]*The host has changed the settings.[/font]';
     1595        break;
     1596
    15211597    default:
    15221598        error("Invalid chat message '" + uneval(msg) + "'");
    15231599        return;
     
    15341610    Engine.GetGUIObjectByName("moreOptions").hidden = !Engine.GetGUIObjectByName("moreOptions").hidden;
    15351611}
    15361612
     1613function toggleReady()
     1614{
     1615    g_IsReady = !g_IsReady;
     1616    if (g_IsReady)
     1617    {
     1618        Engine.SendNetworkReady(1);
     1619        Engine.GetGUIObjectByName("startButton").caption = "I'm not ready.";
     1620    }
     1621    else
     1622    {
     1623        Engine.SendNetworkReady(0);
     1624        Engine.GetGUIObjectByName("startButton").caption = "I'm ready!";
     1625    }
     1626}
     1627
     1628function updateReadyUI()
     1629{   
     1630    var allReady = true;
     1631    for (var guid in g_PlayerAssignments)
     1632    {
     1633        var pData = g_GameAttributes.settings.PlayerData ? g_GameAttributes.settings.PlayerData[g_PlayerAssignments[guid].player - 1] : {};
     1634        var pDefs = g_DefaultPlayerData ? g_DefaultPlayerData[g_PlayerAssignments[guid].player - 1] : {};
     1635        // We don't really care whether observers are ready.
     1636        if (g_PlayerAssignments[guid].player == -1)
     1637            return;     
     1638        if (g_PlayerAssignments[guid].status || !g_IsNetworked)
     1639        {
     1640            // Engine.GetGUIObjectByName("playerReadySprite[" + String(g_PlayerAssignments[guid].player - 1) + "]").sprite = "ModernCheckOn";
     1641            Engine.GetGUIObjectByName("playerName[" + String(g_PlayerAssignments[guid].player - 1)+"]").caption = '[color="0 255 0"]' + getSetting(pData, pDefs, "Name") + '[/color]';
     1642        }
     1643        else
     1644        {
     1645            // Engine.GetGUIObjectByName("playerReadySprite[" + String(g_PlayerAssignments[guid].player - 1) + "]").sprite = "ModernCheckOff";
     1646            Engine.GetGUIObjectByName("playerName[" + String(g_PlayerAssignments[guid].player - 1)+"]").caption = getSetting(pData, pDefs, "Name");
     1647            allReady = false;
     1648        }
     1649    }
     1650    // AIs are always ready.
     1651    for (var playerid = 0; playerid < MAX_PLAYERS; playerid++)
     1652    {       
     1653        if (g_GameAttributes.settings.PlayerData[playerid])
     1654        {
     1655            var pData = g_GameAttributes.settings.PlayerData ? g_GameAttributes.settings.PlayerData[playerid] : {};
     1656            var pDefs = g_DefaultPlayerData ? g_DefaultPlayerData[playerid] : {};
     1657            if (g_GameAttributes.settings.PlayerData[playerid].AI != "" || g_GameAttributes.settings.PlayerData[playerid].Name == "Unassigned")
     1658            {
     1659                // Engine.GetGUIObjectByName("playerReadySprite[" + String(playerid) + "]").sprite = "ModernCheckOn";
     1660                Engine.GetGUIObjectByName("playerName[" + String(playerid)+"]").caption = '[color="0 255 0"]' + getSetting(pData, pDefs, "Name") + '[/color]';
     1661            }
     1662        }
     1663    }
     1664
     1665    // The host is not allowed to start until everyone is ready.
     1666    if (g_IsNetworked && g_IsController)
     1667        Engine.GetGUIObjectByName("startGame").enabled = allReady;
     1668}
     1669
     1670function resetReadyData()
     1671{
     1672    if (g_ReadyChanged < 1)
     1673    {
     1674        addChatMessage({ "type": "settings"});
     1675    }
     1676    g_ReadyChanged = 2;
     1677    if (g_IsNetworked && g_IsController)
     1678    {
     1679        Engine.ClearAllPlayerReady();
     1680        g_IsReady = true;
     1681        Engine.SendNetworkReady(1);
     1682    }
     1683    else
     1684        g_IsReady = false;
     1685}
    15371686////////////////////////////////////////////////////////////////////////////////////////////////
    15381687// Basic map filters API
    15391688
  • 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">
    6261                    <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>
     62                    <object name="playerPlacementHeading" type="text" style="ModernLabelText" size="20% 0 50%+35 100%">Player Placement</object>
     63                    <object name="playerCivHeading" type="text" style="ModernLabelText" size="50%+65 0 85%-26 100%">Civilization</object>
    6564                    <object name="civInfoButton"
    6665                        type="button"
    6766                        sprite="iconInfoGold"
    6867                        sprite_over="iconInfoWhite"
    69                         size="82%-8 0 82%+8 16"
     68                        size="67.5%+68 0 67.5%+84 16"
    7069                        tooltip_style="onscreenToolTip"
    7170                        tooltip="View civilization info"
    7271                    >
     
    7574                        ]]></action>
    7675                    </object>
    7776                    <object name="playerTeamHeading" type="text" style="ModernLabelText" size="85%+5 0 100%-5 100%">Team</object>
     77                    <!--<object name="playerReadyHeading" type="text" style="ModernLabelText" size="90%+5 0 100%-5 100%">Ready</object>-->
    7878                </object>
    7979                <object size="1 36 100%-1 100%">
    8080                    <repeat count="8">
    8181                        <object name="playerBox[n]" size="0 0 100% 32" hidden="true">
    8282                            <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"
     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% 2 50%+35 30" tooltip_style="onscreenToolTip" tooltip="Select player."/>
     85                            <object name="playerConfig[n]" type="button" style="StoneButton" size="50%+40 6 50%+60 26"
    8686                                tooltip_style="onscreenToolTip"
    8787                                tooltip="Configure AI settings."
    8888                                font="serif-bold-stroke-12"
    89                             >Settings</object>
     89                            >O</object>
    9090                            <object name="playerCiv[n]" type="dropdown" style="ModernDropDown" size="50%+65 2 85% 30" tooltip_style="onscreenToolTip" tooltip="Select player's civilization."/>
    9191                            <object name="playerCivText[n]" type="text" style="ModernLabelText" size="50%+65 0 85% 30"/>
    9292                            <object name="playerTeam[n]" type="dropdown" style="ModernDropDown" size="85%+5 2 100%-5 30" tooltip_style="onscreenToolTip" tooltip="Select player's team."/>
    9393                            <object name="playerTeamText[n]" type="text" style="ModernLabelText" size="85%+5 0 100%-5 100%"/>
     94                            <!--<object name="playerReadySprite[n]" type="image" sprite="ModernCheckOff" size="95%-16 0 95%+16 32"/> -->
    9495                        </object>
    9596                    </repeat>
    9697                </object>
    9798            </object>
    98             <object size="24 64 100%-460 358" type="image" sprite="CoverFillDark" name="playerAssignmentsPannelCover" hidden="true"/>
     99            <object size="24 64 100%-460 358" type="image" sprite="CoverFillDark" name="playerAssignmentsPanelCover" hidden="true"/>
    99100            <!-- Map selection -->
    100101           
    101102           
     
    112113                <object name="mapSelectionText" type="text" style="ModernLeftLabelText" size="0 64 100% 94"  hidden="true"/>
    113114                <object name="mapSizeText" type="text" style="ModernLeftLabelText" size="0 96 100% 126" hidden="true"/>
    114115            </object>
    115            
     116
    116117            <object name="mapTypeSelection"
    117118                type="dropdown"
    118119                style="ModernDropDown"
     
    159160            </object>
    160161
    161162            <!-- Chat window -->
    162             <object name="chatPanel" size="24 370 100%-440 100%-60" type="image" sprite="ModernDarkBoxGold">
     163            <object name="chatPanel" size="24 370 100%-440 100%-58" type="image" sprite="ModernDarkBoxGold">
    163164                <object name="chatText" size="2 2 100%-2 100%-26" type="text" style="ChatPanel"/>
    164165
    165166                <object name="chatInput" size="4 100%-24 100%-76 100%-4" type="input" style="ModernInput">
     
    179180                textcolor="white"
    180181                sprite="BackgroundTranslucent"
    181182                hidden="true"
    182                 size="100%-700 100%-56 100%-312 100%-24"
     183                size="25 100%-56 100%-445 100%-24"
    183184            >[Tooltip text]</object>
    184185
    185             <!-- Start Button -->
     186            <!-- Start/Ready Button -->
    186187            <object
    187188                name="startGame"
    188189                type="button"
    189190                style="StoneButton"
    190                 size="100%-308 100%-52 100%-168 100%-24"
     191                size="100%-285 100%-52 100%-165 100%-24"
    191192                tooltip_style="onscreenToolTip"
    192193                tooltip="Start a new game with the current settings."
    193194                enabled="false"
    194195            >
    195196                Start game!
    196                 <action on="Press">launchGame();</action>
     197                <action on="Press">
     198                    if (g_IsController)
     199                        launchGame();
     200                    else
     201                        toggleReady();</action>
    197202            </object>
    198203
    199204            <!-- Cancel Button -->
     
    202207                caption="Back"
    203208                type="button"
    204209                style="StoneButton"
    205                 size="100%-164 100%-52 100%-24 100%-24"
     210                size="100%-145 100%-52 100%-25 100%-24"
    206211                tooltip_style="onscreenToolTip"
    207212            >
    208213                <action on="Press">
     
    215220                    ]]>
    216221                </action>
    217222            </object>
    218            
     223
    219224            <!-- Options -->
    220225            <object name="gameOptionsBox" size="100%-425 497 100%-25 525">
    221226                <!-- More Options Button -->
  • source/gui/scripting/ScriptFunctions.cpp

     
    343343    g_NetServer->AssignPlayer(playerID, guid);
    344344}
    345345
     346void AssignNetworkPlayerStatus(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int ready, std::string guid)
     347{
     348    ENSURE(g_NetServer);
     349
     350    g_NetServer->ReadyPlayer(ready, guid);
     351}
     352
     353void ClearAllPlayerReady (ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
     354{
     355    ENSURE(g_NetServer);
     356
     357    g_NetServer->ClearAllPlayerReady();
     358}
     359
    346360void SendNetworkChat(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::wstring message)
    347361{
    348362    ENSURE(g_NetClient);
     
    350364    g_NetClient->SendChatMessage(message);
    351365}
    352366
     367void SendNetworkReady(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int message)
     368{
     369    ENSURE(g_NetClient);
     370
     371    g_NetClient->SendReadyMessage(message);
     372}
     373
    353374std::vector<CScriptValRooted> GetAIs(ScriptInterface::CxPrivate* pCxPrivate)
    354375{
    355376    return ICmpAIManager::GetAIs(*(pCxPrivate->pScriptInterface));
     
    838859    scriptInterface.RegisterFunction<CScriptVal, &PollNetworkClient>("PollNetworkClient");
    839860    scriptInterface.RegisterFunction<void, CScriptVal, &SetNetworkGameAttributes>("SetNetworkGameAttributes");
    840861    scriptInterface.RegisterFunction<void, int, std::string, &AssignNetworkPlayer>("AssignNetworkPlayer");
     862    scriptInterface.RegisterFunction<void, int, std::string, &AssignNetworkPlayerStatus>("AssignNetworkPlayerStatus");
     863    scriptInterface.RegisterFunction<void, &ClearAllPlayerReady>("ClearAllPlayerReady");
    841864    scriptInterface.RegisterFunction<void, std::wstring, &SendNetworkChat>("SendNetworkChat");
     865    scriptInterface.RegisterFunction<void, int, &SendNetworkReady>("SendNetworkReady");
    842866    scriptInterface.RegisterFunction<std::vector<CScriptValRooted>, &GetAIs>("GetAIs");
    843867    scriptInterface.RegisterFunction<CScriptValRooted, &GetEngineInfo>("GetEngineInfo");
    844868
  • 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);
    9091    AddTransition(NCS_PREGAME, (uint)NMT_GAME_SETUP, NCS_PREGAME, (void*)&OnGameSetup, context);
    9192    AddTransition(NCS_PREGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_PREGAME, (void*)&OnPlayerAssignment, context);
    9293    AddTransition(NCS_PREGAME, (uint)NMT_GAME_START, NCS_LOADING, (void*)&OnGameStart, context);
     
    214215        GetScriptInterface().Eval("({})", host);
    215216        GetScriptInterface().SetProperty(host.get(), "name", std::wstring(it->second.m_Name), false);
    216217        GetScriptInterface().SetProperty(host.get(), "player", it->second.m_PlayerID, false);
     218        GetScriptInterface().SetProperty(host.get(), "status", it->second.m_Status, false);
    217219        GetScriptInterface().SetProperty(hosts.get(), it->first.c_str(), host, false);
    218220    }
    219221
     
    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);
     
    453479        assignment.m_Enabled = true;
    454480        assignment.m_Name = message->m_Hosts[i].m_Name;
    455481        assignment.m_PlayerID = message->m_Hosts[i].m_PlayerID;
     482        assignment.m_Status = message->m_Hosts[i].m_Status;
    456483        newPlayerAssignments[message->m_Hosts[i].m_GUID] = assignment;
    457484    }
    458485
  • 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);
    175178    static bool OnGameSetup(void* context, CFsmEvent* event);
    176179    static bool OnPlayerAssignment(void* context, CFsmEvent* event);
    177180    static bool OnInGame(void* context, CFsmEvent* event);
  • source/network/NetHost.h

     
    4646
    4747    /// The player that the given host controls, or -1 if none (observer)
    4848    i32 m_PlayerID;
     49
     50    /// Status - Ready or not: 0 for not ready, 1 for ready
     51    i32 m_Status;
    4952};
    5053
    5154typedef std::map<CStr, PlayerAssignment> PlayerAssignmentMap; // map from GUID -> assignment
  • 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
    178182    case NMT_SIMULATION_COMMAND:
    179183        pNewMessage = new CSimulationMessage(scriptInterface);
  • source/network/NetMessages.h

     
    4646    NMT_AUTHENTICATE,       // Authentication stage
    4747    NMT_AUTHENTICATE_RESULT,
    4848    NMT_CHAT,       // Common chat message
     49    NMT_READY,
    4950    NMT_GAME_SETUP,
    5051    NMT_PLAYER_ASSIGNMENT,
    5152
     
    118119    NMT_FIELD(CStrW, m_Message)
    119120END_NMT_CLASS()
    120121
     122START_NMT_CLASS_(Ready, NMT_READY)
     123    NMT_FIELD(CStr8, m_GUID)
     124    NMT_FIELD_INT(m_Status, u8, 1)
     125END_NMT_CLASS()
     126
    121127START_NMT_CLASS_(PlayerAssignment, NMT_PLAYER_ASSIGNMENT)
    122128    NMT_START_ARRAY(m_Hosts)
    123129        NMT_FIELD(CStr8, m_GUID)
    124130        NMT_FIELD(CStrW, m_Name)
    125131        NMT_FIELD_INT(m_PlayerID, i8, 1)
     132        NMT_FIELD_INT(m_Status, u8, 1)
    126133    NMT_END_ARRAY()
    127134END_NMT_CLASS()
    128135
  • source/network/NetServer.cpp

     
    376376
    377377    std::vector<std::pair<int, CStr> > newAssignPlayer;
    378378    std::vector<bool> newStartGame;
     379    std::vector<std::pair<int, CStr> > newPlayerReady;
     380    std::vector<bool> newPlayerResetReady;
    379381    std::vector<std::string> newGameAttributes;
    380382    std::vector<u32> newTurnLength;
    381383
     
    386388            return false;
    387389
    388390        newStartGame.swap(m_StartGameQueue);
     391        newPlayerReady.swap(m_PlayerReadyQueue);
     392        newPlayerResetReady.swap(m_PlayerResetReadyQueue);
    389393        newAssignPlayer.swap(m_AssignPlayerQueue);
    390394        newGameAttributes.swap(m_GameAttributesQueue);
    391395        newTurnLength.swap(m_TurnLengthQueue);
     
    394398    for (size_t i = 0; i < newAssignPlayer.size(); ++i)
    395399        AssignPlayer(newAssignPlayer[i].first, newAssignPlayer[i].second);
    396400
     401    for (size_t i = 0; i < newPlayerReady.size(); ++i)
     402        ReadyPlayer(newPlayerReady[i].first, newPlayerReady[i].second);
     403
     404    if (!newPlayerResetReady.empty())
     405        ClearAllPlayerReady();
     406
    397407    if (!newGameAttributes.empty())
    398408        UpdateGameAttributes(GetScriptInterface().ParseJSON(newGameAttributes.back()));
    399409
     
    548558
    549559    session->AddTransition(NSS_PREGAME, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context);
    550560    session->AddTransition(NSS_PREGAME, (uint)NMT_CHAT, NSS_PREGAME, (void*)&OnChat, context);
     561    session->AddTransition(NSS_PREGAME, (uint)NMT_READY, NSS_PREGAME, (void*)&OnReady, context);
    551562    session->AddTransition(NSS_PREGAME, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnLoadedGame, context);
    552563
    553564    session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnJoinSyncingLoadedGame, context);
     
    649660    assignment.m_Enabled = true;
    650661    assignment.m_Name = name;
    651662    assignment.m_PlayerID = playerID;
     663    assignment.m_Status = 0;
    652664    m_PlayerAssignments[guid] = assignment;
    653665
    654666    // Send the new assignments to all currently active players
     
    663675    SendPlayerAssignments();
    664676}
    665677
     678void CNetServerWorker::ReadyPlayer(const int ready, const CStr& guid)
     679{
     680    m_PlayerAssignments[guid].m_Status = ready;
     681
     682    SendPlayerAssignments();
     683}
     684
     685void CNetServerWorker::ClearAllPlayerReady()
     686{
     687    for (PlayerAssignmentMap::iterator it = m_PlayerAssignments.begin(); it != m_PlayerAssignments.end(); ++it)
     688    {
     689        it->second.m_Status = 0;
     690    }
     691
     692    SendPlayerAssignments();
     693}
     694
    666695void CNetServerWorker::AssignPlayer(int playerID, const CStr& guid)
    667696{
    668697    // Remove anyone who's already assigned to this player
     
    690719        h.m_GUID = it->first;
    691720        h.m_Name = it->second.m_Name;
    692721        h.m_PlayerID = it->second.m_PlayerID;
     722        h.m_Status = it->second.m_Status;
    693723        message.m_Hosts.push_back(h);
    694724    }
    695725}
     
    860890    return true;
    861891}
    862892
     893bool CNetServerWorker::OnReady(void* context, CFsmEvent* event)
     894{
     895    ENSURE(event->GetType() == (uint)NMT_READY);
     896
     897    CNetServerSession* session = (CNetServerSession*)context;
     898    CNetServerWorker& server = session->GetServer();
     899
     900    CReadyMessage* message = (CReadyMessage*)event->GetParamRef();
     901
     902    message->m_GUID = session->GetGUID();
     903
     904    server.Broadcast(message);
     905
     906    return true;
     907}
     908
    863909bool CNetServerWorker::OnLoadedGame(void* context, CFsmEvent* event)
    864910{
    865911    ENSURE(event->GetType() == (uint)NMT_LOADED_GAME);
     
    10531099    m_Worker->m_AssignPlayerQueue.push_back(std::make_pair(playerID, guid));
    10541100}
    10551101
     1102void CNetServer::ReadyPlayer(int ready, const CStr& guid)
     1103{
     1104    CScopeLock lock(m_Worker->m_WorkerMutex);
     1105    m_Worker->m_PlayerReadyQueue.push_back(std::make_pair(ready, guid));
     1106}
     1107
     1108void CNetServer::ClearAllPlayerReady()
     1109{
     1110    CScopeLock lock(m_Worker->m_WorkerMutex);
     1111    m_Worker->m_PlayerResetReadyQueue.push_back(false);
     1112}
     1113
    10561114void CNetServer::StartGame()
    10571115{
    10581116    CScopeLock lock(m_Worker->m_WorkerMutex);
  • source/network/NetServer.h

     
    122122     * The changes will be asynchronously propagated to all clients.
    123123     */
    124124    void AssignPlayer(int playerID, const CStr& guid);
     125   
     126    /**
     127     * Call from the GUI to update the player readiness.
     128     * The changes will be asynchronously propagated to all clients.
     129     */
     130    void ReadyPlayer(int ready, const CStr& guid);
    125131
    126132    /**
     133     * Call from the GUI to set the all player readiness to 0.
     134     * The changes will be asynchronously propagated to all clients.
     135     */
     136    void ClearAllPlayerReady();
     137   
     138    /**
    127139     * Call from the GUI to asynchronously notify all clients that they should start loading the game.
    128140     */
    129141    void StartGame();
     
    233245
    234246    void AddPlayer(const CStr& guid, const CStrW& name);
    235247    void RemovePlayer(const CStr& guid);
     248    void ReadyPlayer(const int ready, const CStr& guid);
    236249    void SendPlayerAssignments();
     250    void ClearAllPlayerReady();
    237251
    238252    void SetupSession(CNetServerSession* session);
    239253    bool HandleConnect(CNetServerSession* session);
     
    245259    static bool OnAuthenticate(void* context, CFsmEvent* event);
    246260    static bool OnInGame(void* context, CFsmEvent* event);
    247261    static bool OnChat(void* context, CFsmEvent* event);
     262    static bool OnReady(void* context, CFsmEvent* event);
    248263    static bool OnLoadedGame(void* context, CFsmEvent* event);
    249264    static bool OnJoinSyncingLoadedGame(void* context, CFsmEvent* event);
    250265    static bool OnDisconnect(void* context, CFsmEvent* event);
     
    320335    // Queues for messages sent by the game thread:
    321336    std::vector<std::pair<int, CStr> > m_AssignPlayerQueue; // protected by m_WorkerMutex
    322337    std::vector<bool> m_StartGameQueue; // protected by m_WorkerMutex
     338    std::vector<std::pair<int, CStr> > m_PlayerReadyQueue; // protected by m_WorkerMutex
     339    std::vector<bool> m_PlayerResetReadyQueue; // protected by m_WorkerMutex
    323340    std::vector<std::string> m_GameAttributesQueue; // protected by m_WorkerMutex
    324341    std::vector<u32> m_TurnLengthQueue; // protected by m_WorkerMutex
    325342};