Ticket #2447: readyv5.patch

File readyv5.patch, 35.6 KB (added by scythetwirler, 10 years ago)

Updated with i18n.

  • binaries/data/mods/public/art/textures/ui/global/modern/gear-hover.png

    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
  • binaries/data/mods/public/art/textures/ui/global/modern/gear-press.png

    Property changes on: binaries/data/mods/public/art/textures/ui/global/modern/gear-hover.png
    ___________________________________________________________________
    Added: svn:mime-type
    ## -0,0 +1 ##
    +application/octet-stream
    \ No newline at end of property
    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
  • binaries/data/mods/public/art/textures/ui/global/modern/gear.png

    Property changes on: binaries/data/mods/public/art/textures/ui/global/modern/gear-press.png
    ___________________________________________________________________
    Added: svn:mime-type
    ## -0,0 +1 ##
    +application/octet-stream
    \ No newline at end of property
    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
  • binaries/data/mods/public/gui/common/modern/sprites.xml

    Property changes on: binaries/data/mods/public/art/textures/ui/global/modern/gear.png
    ___________________________________________________________________
    Added: svn:mime-type
    ## -0,0 +1 ##
    +application/octet-stream
    \ No newline at end of property
     
    271271    <sprite name = "ModernDropDownArrow">
    272272        <image texture = "global/modern/dropdown-arrow.png"
    273273            real_texture_placement = "0 0 16 16"
     274            texture_size="0 0 16 16"
     275            size="0 6 16 22"
    274276        />
    275277    </sprite>
    276278    <sprite name = "ModernDropDownArrowHighlight">
    277279        <image texture = "global/modern/dropdown-arrow.png"
    278280            real_texture_placement = "0 0 16 16"
     281            texture_size="0 0 16 16"
     282            size="0 6 16 22"
    279283        />
    280284    </sprite>
    281285    <sprite name="ModernTickOn">
     
    296300            size="0 0 22 22"
    297301        />
    298302    </sprite>
     303    <sprite name="ModernGear">
     304        <image  texture="global/modern/gear.png"
     305            texture_size="0 0 24 24"
     306        />
     307    </sprite>
     308    <sprite name="ModernGearHover">
     309        <image  texture="global/modern/gear-hover.png"
     310            texture_size="0 0 24 24"
     311        />
     312    </sprite>
     313    <sprite name="ModernGearPressed">
     314        <image  texture="global/modern/gear-press.png"
     315            texture_size="0 0 24 24"
     316        />
     317    </sprite>
    299318</sprites>
  • binaries/data/mods/public/gui/common/modern/styles.xml

     
    4646        sprite2_pressed="ModernDropDownArrowHighlight"
    4747
    4848        buffer_zone="8"
    49         dropdown_size="216"
     49        dropdown_size="224"
    5050        sprite_list="colour:12 12 12"
    5151        sprite_selectarea="ModernDarkBoxWhite"
    5252        textcolor_selected="white"
  • 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// There are some duplicate orders on init, we can ignore these [bool].
     38var g_ReadyInit = true;
     39
     40// If no one has changed ready status, we have no need to spam the settings changed message.
     41// 2 - Host's initial ready, suppressed settings message, 1 - Will show settings message, <=0 - Suppressed settings message
     42var g_ReadyChanged = 2;
     43
     44// Has the game started?
     45var g_GameStarted = false;
     46
    3447var g_PlayerAssignments = {};
    3548
    3649// Default game setup attributes
     
    98111    {
    99112        cancelButton.tooltip = translate("Return to the lobby.");
    100113    }
    101 
    102114}
    103115
    104116// Called after the map data is loaded and cached
     
    296308        }
    297309
    298310        Engine.GetGUIObjectByName("numPlayersSelection").hidden = true;
     311        Engine.GetGUIObjectByName("startGame").enabled = true;
    299312    }
    300313
    301314    // Set up multiplayer/singleplayer bits:
     
    414427        break;
    415428
    416429    case "players":
     430        var resetReady = false;
     431        var newPlayer = "";
    417432        // Find and report all joinings/leavings
    418433        for (var host in message.hosts)
     434        {
    419435            if (! g_PlayerAssignments[host])
     436            {
    420437                addChatMessage({ "type": "connect", "username": message.hosts[host].name });
     438                newPlayer = host;
     439            }
     440        }
    421441
    422442        for (var host in g_PlayerAssignments)
     443        {
    423444            if (! message.hosts[host])
     445            {
    424446                addChatMessage({ "type": "disconnect", "guid": host });
     447                if (g_PlayerAssignments[host].player != -1)
     448                    resetReady = true; // Observers shouldn't reset ready.
     449            }
     450        }
    425451
    426452        // Update the player list
    427453        g_PlayerAssignments = message.hosts;
    428454        updatePlayerList();
     455        if (g_PlayerAssignments[newPlayer] && g_PlayerAssignments[newPlayer].player != -1)
     456            resetReady = true;
    429457
     458        if (resetReady)
     459            resetReadyData(); // Observers shouldn't reset ready.
     460        updateReadyUI();
    430461        if (g_IsController)
    431462            sendRegisterGameStanza();
    432463        break;
     
    449480        addChatMessage({ "type": "message", "guid": message.guid, "text": message.text });
    450481        break;
    451482
     483    // Singular client to host message
     484    case "ready":
     485        g_ReadyChanged -= 1;
     486        if (g_ReadyChanged < 1 && g_PlayerAssignments[message.guid].player != -1)
     487            addChatMessage({ "type": "ready", "guid": message.guid, "ready": +message.status == 1 });
     488        if (!g_IsController)
     489            break;
     490        g_PlayerAssignments[message.guid].status = +message.status == 1;
     491        Engine.SetNetworkPlayerStatus(message.guid, +message.status);
     492        updateReadyUI();
     493        break;
     494
    452495    default:
    453496        error("Unrecognised net message type "+message.type);
    454497    }
     
    597640        case "scenario":
    598641        case "skirmish":
    599642            g_MapData[name] = Engine.LoadMapSettings(name);
    600             translateObjectKeys(g_MapData[name], ["Name", "Description"]);
    601643            break;
    602644
    603645        case "random":
    604646            if (name == "random")
    605647                g_MapData[name] = { settings: { "Name": translateWithContext("map", "Random"), "Description": translate("Randomly selects a map from the list") } };
    606648            else
    607             {
    608649                g_MapData[name] = parseJSONData(name+".json");
    609                 translateObjectKeys(g_MapData[name], ["Name", "Description"]);
    610             }
    611650            break;
    612651
    613652        default:
     
    711750            if (g_IsNetworked)
    712751                Engine.AssignNetworkPlayer(player, "");
    713752            else
    714                 g_PlayerAssignments = { "local": { "name": translate("You"), "player": 1, "civ": "", "team": -1} };
     753                g_PlayerAssignments = { "local": { "name": translate("You"), "player": 1, "civ": "", "team": -1, "ready": 0} };
    715754        }
    716755    }
    717756
     
    828867    // Reset player assignments on map change
    829868    if (!g_IsNetworked)
    830869    {   // Slot 1
    831         g_PlayerAssignments = { "local": { "name": translate("You"), "player": 1, "civ": "", "team": -1} };
     870        g_PlayerAssignments = { "local": { "name": translate("You"), "player": 1, "civ": "", "team": -1, "ready": 0} };
    832871    }
    833872    else
    834873    {
     
    861900    if (g_GameAttributes.map == "random")
    862901        selectMap(Engine.GetGUIObjectByName("mapSelection").list_data[Math.floor(Math.random() *
    863902            (Engine.GetGUIObjectByName("mapSelection").list.length - 1)) + 1]);
    864 
     903    g_GameStarted = true;
    865904    g_GameAttributes.settings.mapType = g_GameAttributes.mapType;
    866905    var numPlayers = g_GameAttributes.settings.PlayerData.length;
    867906    // Assign random civilizations to players with that choice
     
    12441283
    12451284    // Game attributes include AI settings, so update the player list
    12461285    updatePlayerList();
     1286
     1287    // We should have everyone confirm that the new settings are acceptable.
     1288    resetReadyData();
    12471289}
    12481290
    12491291function updateGameAttributes()
     
    14131455                        swapPlayers(guid, playerSlot);
    14141456
    14151457                    Engine.SetNetworkGameAttributes(g_GameAttributes);
     1458                    updateReadyUI();
    14161459                }
    14171460            };
    14181461        }
     
    14941537
    14951538function addChatMessage(msg)
    14961539{
    1497     var username = escapeText(msg.username || g_PlayerAssignments[msg.guid].name);
    1498     var message = escapeText(msg.text);
     1540    var username = "";
     1541    if (msg.username)
     1542        username = escapeText(msg.username);
     1543    else if (msg.guid && g_PlayerAssignments[msg.guid])
     1544        username = escapeText(g_PlayerAssignments[msg.guid].name);
    14991545
     1546    var message = "";
     1547    if (msg.text)
     1548        message = escapeText(msg.text);
     1549
    15001550    // TODO: Maybe host should have distinct font/color?
    15011551    var color = "white";
    15021552
    1503     if (g_PlayerAssignments[msg.guid] && g_PlayerAssignments[msg.guid].player != -1)
    1504     {   // Valid player who has been assigned - get player colour
     1553    if (msg.guid && g_PlayerAssignments[msg.guid] && g_PlayerAssignments[msg.guid].player != -1)
     1554    {
     1555        // Valid player who has been assigned - get player colour
    15051556        var player = g_PlayerAssignments[msg.guid].player - 1;
    15061557        var mapName = g_GameAttributes.map;
    15071558        var mapData = loadMapData(mapName);
     
    15161567    switch (msg.type)
    15171568    {
    15181569    case "connect":
    1519         var formattedUsername = '[font="sans-bold-13"][color="'+ color +'"]' + username + '[/color][/font][color="gold"]'
    1520         formatted = '[color="gold"]' + sprintf(translate("%(username)s has joined"), { username: formattedUsername });
     1570        var formattedUsername = '[font="sans-bold-13"][color="'+ color +'"]' + username + '[/color][/font]'
     1571        formatted = '[color="gold"]' + sprintf(translate("%(username)s has joined"), { username: formattedUsername }) + '[/color]';
    15211572        break;
    15221573
    15231574    case "disconnect":
    1524         var formattedUsername = '[font="sans-bold-13"][color="'+ color +'"]' + username + '[/color][/font][color="gold"]'
    1525         formatted = '[color="gold"]' + sprintf(translate("%(username)s has left"), { username: formattedUsername });
     1575        var formattedUsername = '[font="sans-bold-13"][color="'+ color +'"]' + username + '[/color][/font]'
     1576        formatted = '[color="gold"]' + sprintf(translate("%(username)s has left"), { username: formattedUsername }) + '[/color]';
    15261577        break;
    15271578
    15281579    case "message":
     
    15311582        formatted = sprintf(translate("%(username)s %(message)s"), { username: formattedUsernamePrefix, message: message });
    15321583        break;
    15331584
     1585    case "ready":
     1586        var formattedUsername = '[font="sans-bold-13"][color="'+ color +'"]' + username + '[/color][/font]'
     1587        if (msg.ready)
     1588            formatted = '[color="gold"]*' + sprintf(translate("%(username)s is ready!"), { username: formattedUsername }) + '[/color]';
     1589        else
     1590            formatted = '[color="gold"]*' + sprintf(translate("%(username)s is not ready."), { username: formattedUsername }) + '[/color]';
     1591        break;
     1592
     1593    case "settings":
     1594        formatted = '[color="gold"][font="sans-bold-13"]*' + translate('Game settings have been changed.') + '[/font][/color]';
     1595        break;
     1596
    15341597    default:
    15351598        error(sprintf("Invalid chat message '%(message)s'", { message: uneval(msg) }));
    15361599        return;
     
    15471610    Engine.GetGUIObjectByName("moreOptions").hidden = !Engine.GetGUIObjectByName("moreOptions").hidden;
    15481611}
    15491612
     1613function toggleReady()
     1614{
     1615    g_IsReady = !g_IsReady;
     1616    if (g_IsReady)
     1617    {
     1618        Engine.SendNetworkReady(1);
     1619        Engine.GetGUIObjectByName("startGame").caption = translate("I'm not ready.");
     1620        Engine.GetGUIObjectByName("startGame").tooltip = translate("State that you are not ready to play.");
     1621    }
     1622    else
     1623    {
     1624        Engine.SendNetworkReady(0);
     1625        Engine.GetGUIObjectByName("startGame").caption = translate("I'm ready!");
     1626        Engine.GetGUIObjectByName("startGame").tooltip = translate("State that you are ready to play!");
     1627    }
     1628}
     1629
     1630function updateReadyUI()
     1631{   
     1632    var allReady = true;
     1633    for (var guid in g_PlayerAssignments)
     1634    {
     1635        // We don't really care whether observers are ready.
     1636        if (g_PlayerAssignments[guid].player == -1 || !g_GameAttributes.settings.PlayerData[g_PlayerAssignments[guid].player - 1])
     1637            continue;
     1638        var pData = g_GameAttributes.settings.PlayerData ? g_GameAttributes.settings.PlayerData[g_PlayerAssignments[guid].player - 1] : {};
     1639        var pDefs = g_DefaultPlayerData ? g_DefaultPlayerData[g_PlayerAssignments[guid].player - 1] : {};           
     1640        if (g_PlayerAssignments[guid].status || !g_IsNetworked)
     1641            Engine.GetGUIObjectByName("playerName[" + (g_PlayerAssignments[guid].player - 1) + "]").caption = '[color="0 255 0"]' + getSetting(pData, pDefs, "Name") + '[/color]';
     1642        else
     1643        {
     1644            Engine.GetGUIObjectByName("playerName[" + (g_PlayerAssignments[guid].player - 1) + "]").caption = getSetting(pData, pDefs, "Name");
     1645            allReady = false;
     1646        }
     1647    }
     1648    // AIs are always ready.
     1649    for (var playerid = 0; playerid < MAX_PLAYERS; playerid++)
     1650    {       
     1651        if (!g_GameAttributes.settings.PlayerData[playerid])
     1652            continue;
     1653        var pData = g_GameAttributes.settings.PlayerData ? g_GameAttributes.settings.PlayerData[playerid] : {};
     1654        var pDefs = g_DefaultPlayerData ? g_DefaultPlayerData[playerid] : {};
     1655        if (g_GameAttributes.settings.PlayerData[playerid].AI != "" || g_GameAttributes.settings.PlayerData[playerid].Name == "Unassigned")
     1656            Engine.GetGUIObjectByName("playerName[" + playerid + "]").caption = '[color="0 255 0"]' + getSetting(pData, pDefs, "Name") + '[/color]';
     1657    }
     1658    // The host is not allowed to start until everyone is ready.
     1659    if (g_IsNetworked && g_IsController)
     1660        Engine.GetGUIObjectByName("startGame").enabled = allReady;
     1661}
     1662
     1663function resetReadyData()
     1664{
     1665    if (g_GameStarted)
     1666        return;
     1667    if (g_ReadyChanged < 1)
     1668        addChatMessage({ "type": "settings"});
     1669    else if (g_ReadyChanged == 2 && !g_ReadyInit)
     1670        return; // duplicate calls on init
     1671    else
     1672        g_ReadyInit = false;
     1673    g_ReadyChanged = 2;
     1674    if (g_IsNetworked && g_IsController)
     1675    {
     1676        Engine.ClearAllPlayerReady();
     1677        g_IsReady = true;
     1678        Engine.SendNetworkReady(1);
     1679    }
     1680    else
     1681    {
     1682        g_IsReady = false;
     1683        Engine.GetGUIObjectByName("startGame").caption = translate("I'm ready!");
     1684        Engine.GetGUIObjectByName("startGame").tooltip = translate("State that you accept the current settings and are ready to play!");
     1685    }
     1686}
    15501687////////////////////////////////////////////////////////////////////////////////////////////////
    15511688// Basic map filters API
    15521689
  • binaries/data/mods/public/gui/gamesetup/gamesetup.xml

     
    1414        <object style="TitleText" type="text" size="50%-128 4 50%+128 36">
    1515            <translatableAttribute id="caption">Match Setup</translatableAttribute>
    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-->
    37             <object size="24 26 224 54">
     37            <object size="24 26 100%-24 54">
    3838
    3939                <!-- Number of Players-->
    40                 <object size="0 0 150 28">
     40                <object size="0 0 50%-170 28">
    4141                    <object size="0 0 100% 100%" type="text" style="ModernRightLabelText">
    4242                        <translatableAttribute id="caption">Number of players:</translatableAttribute>
    4343                    </object>
    4444                </object>
    45                    
     45
    4646                <!-- Number of Players-->
    47                 <object size="150 0 200 28">
     47                <object size="50%-170 0 50%-120 28">
    4848                    <object name="numPlayersText" size="0 0 100% 100%" type="text" style="ModernLeftLabelText"/>
    4949                        <object name="numPlayersSelection"
    5050                            type="dropdown"
     
    6161            <!-- Player assignments -->
    6262            <object size="24 59 100%-440 358" type="image" sprite="ModernDarkBoxGold" name="playerAssignmentsPannel">
    6363                <object size="0 6 100% 30">
    64                     <object name="playerNameHeading" type="text" style="ModernLabelText" size="0 0 20% 100%">
     64                    <object name="playerNameHeading" type="text" style="ModernLabelText" size="0 0 22% 100%">
    6565                        <translatableAttribute id="caption">Player Name</translatableAttribute>
    6666                    </object>
    67                     <object name="playerPlacementHeading" type="text" style="ModernLabelText" size="20%+5 0 50% 100%">
     67                    <object name="playerPlacementHeading" type="text" style="ModernLabelText" size="22%+5 0 50%+35 100%">
    6868                        <translatableAttribute id="caption">Player Placement</translatableAttribute>
    6969                    </object>
    70                     <object name="playerCivHeading" type="text" style="ModernLabelText" size="50%+65 0 85% 100%">
     70                    <object name="playerCivHeading" type="text" style="ModernLabelText" size="50%+65 0 85%-26 100%">
    7171                        <translatableAttribute id="caption">Civilization</translatableAttribute>
    7272                    </object>
    7373                    <object name="civInfoButton"
    7474                        type="button"
    7575                        sprite="iconInfoGold"
    7676                        sprite_over="iconInfoWhite"
    77                         size="82%-8 0 82%+8 16"
     77                        size="67.5%+68 0 67.5%+84 16"
    7878                        tooltip_style="onscreenToolTip"
    7979                    >
    8080                        <translatableAttribute id="tooltip">View civilization info</translatableAttribute>
     
    9090                    <repeat count="8">
    9191                        <object name="playerBox[n]" size="0 0 100% 32" hidden="true">
    9292                            <object name="playerColour[n]" type="image" size="0 0 100% 100%"/>
    93                             <object name="playerName[n]" type="text" style="ModernLabelText" size="0 2 20% 30"/>
    94                             <object name="playerAssignment[n]" type="dropdown" style="ModernDropDown" size="20%+5 2 50% 30" tooltip_style="onscreenToolTip">
     93                            <object name="playerName[n]" type="text" style="ModernLabelText" size="0 2 22% 30"/>
     94                            <object name="playerAssignment[n]" type="dropdown" style="ModernDropDown" size="22%+5 2 50%+35 30" tooltip_style="onscreenToolTip">
    9595                                <translatableAttribute id="tooltip">Select player.</translatableAttribute>
    9696                            </object>
    97                             <object name="playerConfig[n]" type="button" style="StoneButton" size="50%+5 6 50%+60 26"
     97                            <object name="playerConfig[n]" type="button" style="StoneButton" size="50%+40 4 50%+64 28"
    9898                                tooltip_style="onscreenToolTip"
    9999                                font="sans-bold-stroke-12"
     100                                sprite="ModernGear"
     101                                sprite_over="ModernGearHover"
     102                                sprite_pressed="ModernGearPressed"
    100103                            >
    101                                 <translatableAttribute id="caption">Settings</translatableAttribute>
    102104                                <translatableAttribute id="tooltip">Configure AI settings.</translatableAttribute>
    103105                            </object>
    104                             <object name="playerCiv[n]" type="dropdown" style="ModernDropDown" size="50%+65 2 85% 30" tooltip_style="onscreenToolTip">
     106                            <object name="playerCiv[n]" type="dropdown" style="ModernDropDown" size="50%+69 2 85% 30" tooltip_style="onscreenToolTip">
    105107                                <translatableAttribute id="tooltip">Select player's civilization.</translatableAttribute>
    106108                            </object>
    107109                            <object name="playerCivText[n]" type="text" style="ModernLabelText" size="50%+65 0 85% 30"/>
     
    113115                    </repeat>
    114116                </object>
    115117            </object>
    116             <object size="24 64 100%-460 358" type="image" sprite="CoverFillDark" name="playerAssignmentsPannelCover" hidden="true"/>
     118            <object size="24 64 100%-460 358" type="image" sprite="CoverFillDark" name="playerAssignmentsPanelCover" hidden="true"/>
    117119            <!-- Map selection -->
    118120           
    119121           
     
    138140                <object name="mapSelectionText" type="text" style="ModernLeftLabelText" size="0 64 100% 94"  hidden="true"/>
    139141                <object name="mapSizeText" type="text" style="ModernLeftLabelText" size="0 96 100% 126" hidden="true"/>
    140142            </object>
    141            
     143
    142144            <object name="mapTypeSelection"
    143145                type="dropdown"
    144146                style="ModernDropDown"
     
    169171                </object>
    170172            </object>
    171173           
    172             <object name="mapSize" size="100%-325 459 100%-25 487" type="dropdown" style="ModernDropDown" hidden="true" tooltip_style="onscreenToolTip">
     174            <object name="mapSize" size="100%-315 459 100%-25 487" type="dropdown" style="ModernDropDown" hidden="true" tooltip_style="onscreenToolTip">
    173175                <translatableAttribute id="tooltip">Select map size. (Larger sizes may reduce performance.)</translatableAttribute>
    174176            </object>
    175177           
     
    187189            </object>
    188190
    189191            <!-- Chat window -->
    190             <object name="chatPanel" size="24 370 100%-440 100%-60" type="image" sprite="ModernDarkBoxGold">
     192            <object name="chatPanel" size="24 370 100%-440 100%-58" type="image" sprite="ModernDarkBoxGold">
    191193                <object name="chatText" size="2 2 100%-2 100%-26" type="text" style="ChatPanel"/>
    192194
    193195                <object name="chatInput" size="4 100%-24 100%-76 100%-4" type="input" style="ModernInput">
     
    207209                textcolor="white"
    208210                sprite="BackgroundTranslucent"
    209211                hidden="true"
    210                 size="100%-700 100%-56 100%-312 100%-24"
     212                size="20 100%-56 100%-312 100%-24"
    211213            >
    212214                <translatableAttribute id="caption">[Tooltip text]</translatableAttribute>
    213215            </object>
    214216
    215             <!-- Start Button -->
     217            <!-- Start/Ready Button -->
    216218            <object
    217219                name="startGame"
    218220                type="button"
     
    223225            >
    224226                <translatableAttribute id="caption">Start game!</translatableAttribute>
    225227                <translatableAttribute id="tooltip">Start a new game with the current settings.</translatableAttribute>
    226                 <action on="Press">launchGame();</action>
     228                <action on="Press">
     229                    if (g_IsController)
     230                        launchGame();
     231                    else
     232                        toggleReady();
     233                </action>
    227234            </object>
    228235
    229236            <!-- Cancel Button -->
     
    245252                    ]]>
    246253                </action>
    247254            </object>
    248            
     255
    249256            <!-- Options -->
    250257            <object name="gameOptionsBox" size="100%-425 497 100%-25 525">
    251258                <!-- More Options Button -->
  • source/gui/scripting/ScriptFunctions.cpp

     
    344344    g_NetServer->AssignPlayer(playerID, guid);
    345345}
    346346
     347void SetNetworkPlayerStatus(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::string guid, int ready)
     348{
     349    ENSURE(g_NetServer);
     350
     351    g_NetServer->SetPlayerReady(guid, ready);
     352}
     353
     354void ClearAllPlayerReady (ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
     355{
     356    ENSURE(g_NetServer);
     357
     358    g_NetServer->ClearAllPlayerReady();
     359}
     360
    347361void SendNetworkChat(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::wstring message)
    348362{
    349363    ENSURE(g_NetClient);
     
    351365    g_NetClient->SendChatMessage(message);
    352366}
    353367
     368void SendNetworkReady(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int message)
     369{
     370    ENSURE(g_NetClient);
     371
     372    g_NetClient->SendReadyMessage(message);
     373}
     374
    354375std::vector<CScriptValRooted> GetAIs(ScriptInterface::CxPrivate* pCxPrivate)
    355376{
    356377    return ICmpAIManager::GetAIs(*(pCxPrivate->pScriptInterface));
     
    861882    scriptInterface.RegisterFunction<CScriptVal, &PollNetworkClient>("PollNetworkClient");
    862883    scriptInterface.RegisterFunction<void, CScriptVal, &SetNetworkGameAttributes>("SetNetworkGameAttributes");
    863884    scriptInterface.RegisterFunction<void, int, std::string, &AssignNetworkPlayer>("AssignNetworkPlayer");
     885    scriptInterface.RegisterFunction<void, std::string, int, &SetNetworkPlayerStatus>("SetNetworkPlayerStatus");
     886    scriptInterface.RegisterFunction<void, &ClearAllPlayerReady>("ClearAllPlayerReady");
    864887    scriptInterface.RegisterFunction<void, std::wstring, &SendNetworkChat>("SendNetworkChat");
     888    scriptInterface.RegisterFunction<void, int, &SendNetworkReady>("SendNetworkReady");
    865889    scriptInterface.RegisterFunction<std::vector<CScriptValRooted>, &GetAIs>("GetAIs");
    866890    scriptInterface.RegisterFunction<CScriptValRooted, &GetEngineInfo>("GetEngineInfo");
    867891
  • 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(), "status", 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    u8 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<CStr, int> > 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        SetPlayerReady(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::SetPlayerReady(const CStr& guid, const int ready)
     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        it->second.m_Status = 0;
     689
     690    SendPlayerAssignments();
     691}
     692
    666693void CNetServerWorker::AssignPlayer(int playerID, const CStr& guid)
    667694{
    668695    // Remove anyone who's already assigned to this player
     
    690717        h.m_GUID = it->first;
    691718        h.m_Name = it->second.m_Name;
    692719        h.m_PlayerID = it->second.m_PlayerID;
     720        h.m_Status = it->second.m_Status;
    693721        message.m_Hosts.push_back(h);
    694722    }
    695723}
     
    860888    return true;
    861889}
    862890
     891bool CNetServerWorker::OnReady(void* context, CFsmEvent* event)
     892{
     893    ENSURE(event->GetType() == (uint)NMT_READY);
     894
     895    CNetServerSession* session = (CNetServerSession*)context;
     896    CNetServerWorker& server = session->GetServer();
     897
     898    CReadyMessage* message = (CReadyMessage*)event->GetParamRef();
     899
     900    message->m_GUID = session->GetGUID();
     901
     902    server.Broadcast(message);
     903
     904    return true;
     905}
     906
    863907bool CNetServerWorker::OnLoadedGame(void* context, CFsmEvent* event)
    864908{
    865909    ENSURE(event->GetType() == (uint)NMT_LOADED_GAME);
     
    10531097    m_Worker->m_AssignPlayerQueue.push_back(std::make_pair(playerID, guid));
    10541098}
    10551099
     1100void CNetServer::SetPlayerReady(const CStr& guid, int ready)
     1101{
     1102    CScopeLock lock(m_Worker->m_WorkerMutex);
     1103    m_Worker->m_PlayerReadyQueue.push_back(std::make_pair(guid, ready));
     1104}
     1105
     1106void CNetServer::ClearAllPlayerReady()
     1107{
     1108    CScopeLock lock(m_Worker->m_WorkerMutex);
     1109    m_Worker->m_PlayerResetReadyQueue.push_back(false);
     1110}
     1111
    10561112void CNetServer::StartGame()
    10571113{
    10581114    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 SetPlayerReady(const CStr& guid, int ready);
    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 SetPlayerReady(const CStr& guid, const int ready);
    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<CStr, int> > 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};
  • source/network/fsm.cpp

     
    402402
    403403    // Lookup transition
    404404    CFsmTransition* pTransition = GetTransition( m_CurrState, eventType );
    405     if ( !pTransition ) return false;
     405    if ( !pTransition )
     406        return false;
    406407
    407408    // Setup event parameter
    408409    EventMap::iterator it = m_Events.find( eventType );
     
    413414    }
    414415
    415416    // Valid transition?
    416     if ( !pTransition->ApplyConditions() ) return false;
     417    if ( !pTransition->ApplyConditions() )
     418        return false;
    417419
    418420    // Save the default state transition (actions might call SetNextState
    419421    // to override this)
    420422    SetNextState( pTransition->GetNextState() );
    421423
    422424    // Run transition actions
    423     if ( !pTransition->RunActions() ) return false;
     425    if ( !pTransition->RunActions() )
     426        return false;
    424427
    425428    // Switch state
    426429    SetCurrState( GetNextState() );