Ticket #3806: 3806_player_gamesetup_v2.0.patch

File 3806_player_gamesetup_v2.0.patch, 30.8 KB (added by Imarok, 8 years ago)

ChangeSettingMessage only sends changed setting and value, forward ChangeSettingMessage only to host, ignore every AssignPlayerMessage not coming from host, ignore every SetGameAttributesMessage not coming from host

  • binaries/data/mods/public/gui/aiconfig/aiconfig.js

     
    1616    let aiSelection = Engine.GetGUIObjectByName("aiSelection");
    1717    aiSelection.list = g_AIDescriptions.map(ai => ai.data.name);
    1818    aiSelection.selected = g_AIDescriptions.findIndex(ai => ai.id == settings.id);
    19     aiSelection.hidden = !settings.isController;
     19    aiSelection.hidden = !settings.canBeChanged;
    2020
    2121    let aiSelectionText = Engine.GetGUIObjectByName("aiSelectionText");
    2222    aiSelectionText.caption = aiSelection.list[aiSelection.selected];
    23     aiSelectionText.hidden = settings.isController;
     23    aiSelectionText.hidden = settings.canBeChanged;
    2424
    2525    let aiDiff = Engine.GetGUIObjectByName("aiDifficulty");
    2626    aiDiff.list = prepareForDropdown(g_Settings.AIDifficulties).Title;
    2727    aiDiff.selected = settings.difficulty;
    28     aiDiff.hidden = !settings.isController;
     28    aiDiff.hidden = !settings.canBeChanged;
    2929
    3030    let aiDiffText = Engine.GetGUIObjectByName("aiDifficultyText");
    3131    aiDiffText.caption = aiDiff.list[aiDiff.selected];
    32     aiDiffText.hidden = settings.isController;
     32    aiDiffText.hidden = settings.canBeChanged;
    3333}
    3434
    3535function selectAI(idx)
  • binaries/data/mods/public/gui/common/settings.js

     
    3737        "MapTypes": loadMapTypes(),
    3838        "MapSizes": loadSettingValuesFile("map_sizes.json"),
    3939        "PlayerDefaults": loadPlayerDefaults(),
     40        "GuestSettings": loadSettingValuesFile("guest_settings.json"),
    4041        "PopulationCapacities": loadPopulationCapacities(),
    4142        "StartingResources": loadSettingValuesFile("starting_resources.json"),
    4243        "VictoryConditions": loadVictoryConditions()
  • binaries/data/mods/public/gui/gamesetup/gamesetup.js

     
    55const g_GameSpeeds = prepareForDropdown(g_Settings && g_Settings.GameSpeeds.filter(speed => !speed.ReplayOnly));
    66const g_MapSizes = prepareForDropdown(g_Settings && g_Settings.MapSizes);
    77const g_MapTypes = prepareForDropdown(g_Settings && g_Settings.MapTypes);
     8const g_GuestSettings = prepareForDropdown(g_Settings && g_Settings.GuestSettings);
    89const g_PopulationCapacities = prepareForDropdown(g_Settings && g_Settings.PopulationCapacities);
    910const g_StartingResources = prepareForDropdown(g_Settings && g_Settings.StartingResources);
    1011const g_VictoryConditions = prepareForDropdown(g_Settings && g_Settings.VictoryConditions);
     
    270271    initCivNameList();
    271272    initMapTypes();
    272273    initMapFilters();
     274    initDropdowns();
    273275
    274276    if (g_IsController)
    275277    {
     
    277279        g_GameAttributes.matchID = Engine.GetMatchID();
    278280        g_GameAttributes.settings.CheatsEnabled = !g_IsNetworked;
    279281        g_GameAttributes.settings.RatingEnabled = Engine.IsRankedGame() || undefined;
    280 
    281         initMapNameList();
    282         initNumberOfPlayers();
    283         initGameSpeed();
    284         initPopulationCaps();
    285         initStartingResources();
    286         initCeasefire();
    287         initWonderDurations();
    288         initVictoryConditions();
    289         initMapSizes();
    290         initRadioButtons();
    291282    }
    292283    else
    293284        hideControls();
     
    309300    }
    310301}
    311302
     303function initDropdowns()
     304{
     305    initMapNameList();
     306    initNumberOfPlayers();
     307    initGameSpeed();
     308    initGuestSettings();
     309    initPopulationCaps();
     310    initStartingResources();
     311    initCeasefire();
     312    initWonderDurations();
     313    initVictoryConditions();
     314    initMapSizes();
     315    initRadioButtons();
     316}
     317
    312318function initMapTypes()
    313319{
    314320    let mapTypes = Engine.GetGUIObjectByName("mapType");
     
    318324        if (this.selected != -1)
    319325            selectMapType(this.list_data[this.selected]);
    320326    };
    321     if (g_IsController)
    322         mapTypes.selected = g_MapTypes.Default;
     327    mapTypes.selected = g_MapTypes.Default;
    323328}
    324329
    325330function initMapFilters()
     
    331336        if (this.selected != -1)
    332337            selectMapFilter(this.list_data[this.selected]);
    333338    };
    334     if (g_IsController)
    335         mapFilters.selected = 0;
     339    mapFilters.selected = 0;
    336340    g_GameAttributes.mapFilter = "default";
    337341}
    338342
     
    349353        "optionPopulationCap",
    350354        "optionStartingResources",
    351355        "optionCeasefire",
     356        "optionGuestSettings",
    352357        "optionRevealMap",
    353358        "optionExploreMap",
    354359        "optionDisableTreasures",
     
    398403function initGameSpeed()
    399404{
    400405    let gameSpeed = Engine.GetGUIObjectByName("gameSpeed");
    401     gameSpeed.hidden = false;
    402     Engine.GetGUIObjectByName("gameSpeedText").hidden = true;
    403406    gameSpeed.list = g_GameSpeeds.Title;
    404407    gameSpeed.list_data = g_GameSpeeds.Speed;
    405408    gameSpeed.onSelectionChange = function() {
     
    453456    };
    454457}
    455458
     459function initGuestSettings()
     460{
     461    let guestSettings = Engine.GetGUIObjectByName("guestSettings");
     462    guestSettings.list = g_GuestSettings.Title;
     463    guestSettings.list_data = g_GuestSettings.Data;
     464    guestSettings.onSelectionChange = function() {
     465        if (this.selected != -1)
     466            g_GameAttributes.GuestSettings = g_GuestSettings.Data[this.selected];
     467
     468        updateGameAttributes();
     469    };
     470    if (guestSettings.selected == -1)
     471        guestSettings.selected = g_GuestSettings.Default;
     472}
     473
    456474function initVictoryConditions()
    457475{
    458476    let victoryConditions = Engine.GetGUIObjectByName("victoryCondition");
     
    533551function hideControls()
    534552{
    535553    for (let ctrl of ["mapType", "mapFilter", "mapSelection", "victoryCondition", "gameSpeed", "numPlayers"])
    536         hideControl(ctrl, ctrl + "Text");
     554        hideControl(ctrl, ctrl + "Text", canPlayerChange(ctrl));
    537555
    538     // TODO: Shouldn't players be able to choose their own assignment?
    539556    for (let i = 0; i < g_MaxPlayers; ++i)
    540557    {
    541558        Engine.GetGUIObjectByName("playerAssignment["+i+"]").hidden = true;
     
    573590}
    574591
    575592/**
     593 * Returns if the player is allowed to change this setting
     594 */
     595function canPlayerChange(setting, index = -1)
     596{
     597    if (g_GameAttributes.mapType == "scenario" &&
     598         ["victoryCondition", "wonderDuration", "populationCap",
     599         "startingResources", "ceasefire", "revealMap", "exploreMap",
     600         "disableTreasures", "lockTeams", "playerCiv", "playerTeam", "playerColor"].indexOf(setting) >= 0)
     601        return false;
     602
     603    if (g_GameAttributes.mapType != "random" && setting == "numPlayers")
     604        return false;
     605
     606    if (g_IsController)
     607        return true;
     608 
     609     if (setting == "guestSettings")
     610        return false;
     611
     612    if (g_GuestSettings.Data.indexOf(setting) == -1)
     613        return g_GameAttributes.GuestSettings == "all";
     614
     615    if (index >= 0 && g_PlayerAssignments[Engine.GetPlayerGUID()] !== undefined && index != g_PlayerAssignments[Engine.GetPlayerGUID()].player-1)
     616        return g_GameAttributes.GuestSettings == "all";
     617
     618    return g_GuestSettings.Data.indexOf(g_GameAttributes.GuestSettings) >= g_GuestSettings.Data.indexOf(setting);
     619}
     620
     621/**
    576622 * Hide and set some elements depending on whether we play single- or multiplayer.
    577623 */
    578624function initMultiplayerSettings()
     
    579625{
    580626    Engine.GetGUIObjectByName("chatPanel").hidden = !g_IsNetworked;
    581627    Engine.GetGUIObjectByName("optionCheats").hidden = !g_IsNetworked;
     628    Engine.GetGUIObjectByName("optionGuestSettings").hidden = !g_IsNetworked;
    582629    Engine.GetGUIObjectByName("optionRating").hidden = !Engine.HasXmppClient();
    583630
    584631    Engine.GetGUIObjectByName("enableCheats").enabled = !Engine.IsRankedGame();
     
    695742}
    696743
    697744/**
    698  * Called whenever the host changed any setting.
     745 * Called whenever someone changed any setting.
    699746 * @param {Object} message
    700747 */
    701748function handleGamesetupMessage(message)
     
    10461093function selectNumPlayers(num)
    10471094{
    10481095    // Avoid recursion
    1049     if (g_IsInGuiUpdate || !g_IsController || g_GameAttributes.mapType != "random")
     1096    if (g_IsInGuiUpdate || !canPlayerChange("numPlayers") || g_GameAttributes.mapType != "random")
    10501097        return;
    10511098
    10521099    // Unassign players from nonexistent slots
     
    11101157function selectMapType(type)
    11111158{
    11121159    // Avoid recursion
    1113     if (g_IsInGuiUpdate || !g_IsController)
     1160    if (g_IsInGuiUpdate)
    11141161        return;
    11151162
    11161163    if (!g_MapPath[type])
     
    11401187function selectMapFilter(id)
    11411188{
    11421189    // Avoid recursion
    1143     if (g_IsInGuiUpdate || !g_IsController)
     1190    if (g_IsInGuiUpdate)
    11441191        return;
    11451192
    11461193    g_GameAttributes.mapFilter = id;
     
    11531200function selectMap(name)
    11541201{
    11551202    // Avoid recursion
    1156     if (g_IsInGuiUpdate || !g_IsController || !name)
     1203    if (g_IsInGuiUpdate || !name)
    11571204        return;
    11581205
    11591206    // Reset some map specific properties which are not necessarily redefined on each map
     
    12851332
    12861333    if (g_IsNetworked)
    12871334    {
    1288         Engine.SetNetworkGameAttributes(g_GameAttributes);
     1335        Engine.NetworkChangeSettings(g_GameAttributes);
    12891336        Engine.StartNetworkGame();
    12901337    }
    12911338    else
     
    13241371    let mapFilterIdx = g_MapFilters.findIndex(mapFilter => mapFilter.id == (g_GameAttributes.mapFilter || "default"));
    13251372    let mapTypeIdx = g_GameAttributes.mapType !== undefined ? g_MapTypes.Name.indexOf(g_GameAttributes.mapType) : g_MapTypes.Default;
    13261373    let gameSpeedIdx = g_GameAttributes.gameSpeed !== undefined ? g_GameSpeeds.Speed.indexOf(g_GameAttributes.gameSpeed) : g_GameSpeeds.Default;
     1374    let guestSettingsIdx = g_GameAttributes.GuestSettings !== undefined ? g_GuestSettings.Data.indexOf(g_GameAttributes.GuestSettings) : g_GuestSettings.Default;
    13271375
    13281376    // These dropdowns might set the default (as they ignore g_IsInGuiUpdate)
    13291377    let mapSizeIdx = mapSettings.Size !== undefined ? g_MapSizes.Tiles.indexOf(mapSettings.Size) : g_MapSizes.Default;
     
    13341382    let ceasefireIdx = mapSettings.Ceasefire !== undefined ? g_Ceasefire.Duration.indexOf(mapSettings.Ceasefire) : g_Ceasefire.Default;
    13351383    let numPlayers = mapSettings.PlayerData ? mapSettings.PlayerData.length : g_MaxPlayers;
    13361384
    1337     if (g_IsController)
    1338     {
    1339         Engine.GetGUIObjectByName("mapType").selected = mapTypeIdx;
    1340         Engine.GetGUIObjectByName("mapFilter").selected = mapFilterIdx;
    1341         Engine.GetGUIObjectByName("mapSelection").selected = Engine.GetGUIObjectByName("mapSelection").list_data.indexOf(mapName);
    1342         Engine.GetGUIObjectByName("mapSize").selected = mapSizeIdx;
    1343         Engine.GetGUIObjectByName("numPlayers").selected = numPlayers - 1;
    1344         Engine.GetGUIObjectByName("victoryCondition").selected = victoryIdx;
    1345         Engine.GetGUIObjectByName("wonderDuration").selected = wonderDurationIdx;
    1346         Engine.GetGUIObjectByName("populationCap").selected = popIdx;
    1347         Engine.GetGUIObjectByName("gameSpeed").selected = gameSpeedIdx;
    1348         Engine.GetGUIObjectByName("ceasefire").selected = ceasefireIdx;
    1349         Engine.GetGUIObjectByName("startingResources").selected = startingResIdx;
    1350     }
    1351     else
    1352     {
    1353         Engine.GetGUIObjectByName("mapTypeText").caption = g_MapTypes.Title[mapTypeIdx];
    1354         Engine.GetGUIObjectByName("mapFilterText").caption = g_MapFilters[mapFilterIdx].name;
    1355         Engine.GetGUIObjectByName("mapSelectionText").caption = mapName == "random" ? g_RandomMap : translate(getMapDisplayName(mapName));
    1356         initMapNameList();
    1357     }
     1385    Engine.GetGUIObjectByName("mapType").selected = mapTypeIdx;
     1386    Engine.GetGUIObjectByName("mapFilter").selected = mapFilterIdx;
     1387    Engine.GetGUIObjectByName("mapSelection").selected = Engine.GetGUIObjectByName("mapSelection").list_data.indexOf(mapName);
     1388    Engine.GetGUIObjectByName("mapSize").selected = mapSizeIdx;
     1389    Engine.GetGUIObjectByName("numPlayers").selected = numPlayers - 1;
     1390    Engine.GetGUIObjectByName("victoryCondition").selected = victoryIdx;
     1391    Engine.GetGUIObjectByName("wonderDuration").selected = wonderDurationIdx;
     1392    Engine.GetGUIObjectByName("populationCap").selected = popIdx;
     1393    Engine.GetGUIObjectByName("gameSpeed").selected = gameSpeedIdx;
     1394    Engine.GetGUIObjectByName("ceasefire").selected = ceasefireIdx;
     1395    Engine.GetGUIObjectByName("startingResources").selected = startingResIdx;
     1396    Engine.GetGUIObjectByName("guestSettings").selected = guestSettingsIdx;
    13581397
     1398
     1399    initMapNameList();
     1400
    13591401    // Can be visible to both host and clients
    13601402    Engine.GetGUIObjectByName("mapSizeText").caption = g_GameAttributes.mapType == "random" ? g_MapSizes.LongName[mapSizeIdx] : translate("Default");
    13611403    Engine.GetGUIObjectByName("numPlayersText").caption = numPlayers;
    13621404    Engine.GetGUIObjectByName("victoryConditionText").caption = g_VictoryConditions.Title[victoryIdx];
    13631405    Engine.GetGUIObjectByName("wonderDurationText").caption = g_WonderDurations.Title[wonderDurationIdx];
     1406    Engine.GetGUIObjectByName("guestSettingsText").caption = g_GuestSettings.Title[guestSettingsIdx];
    13641407    Engine.GetGUIObjectByName("populationCapText").caption = g_PopulationCapacities.Title[popIdx];
    13651408    Engine.GetGUIObjectByName("startingResourcesText").caption = g_StartingResources.Title[startingResIdx];
    13661409    Engine.GetGUIObjectByName("ceasefireText").caption = g_Ceasefire.Title[ceasefireIdx];
    13671410    Engine.GetGUIObjectByName("gameSpeedText").caption = g_GameSpeeds.Title[gameSpeedIdx];
     1411    Engine.GetGUIObjectByName("mapTypeText").caption = g_MapTypes.Title[mapTypeIdx];
     1412    Engine.GetGUIObjectByName("mapFilterText").caption = g_MapFilters[mapFilterIdx].name;
     1413    Engine.GetGUIObjectByName("mapSelectionText").caption = mapName == "random" ? g_RandomMap : translate(getMapDisplayName(mapName));
    13681414
    13691415    setGUIBoolean("enableCheats", "enableCheatsText", !!mapSettings.CheatsEnabled);
    13701416    setGUIBoolean("disableTreasures", "disableTreasuresText", !!mapSettings.DisableTreasures);
     
    13871433    Engine.GetGUIObjectByName("mapSizeDesc").hidden = !isRandom;
    13881434    Engine.GetGUIObjectByName("mapSize").hidden = !isRandom || !g_IsController;
    13891435    Engine.GetGUIObjectByName("mapSizeText").hidden = !isRandom || g_IsController;
    1390     hideControl("numPlayers", "numPlayersText", isRandom && g_IsController);
    13911436
    1392     let notScenario = g_GameAttributes.mapType != "scenario" && g_IsController ;
    1393 
    13941437    for (let ctrl of ["victoryCondition", "wonderDuration", "populationCap",
    13951438                      "startingResources", "ceasefire", "revealMap",
    1396                       "exploreMap", "disableTreasures", "lockTeams"])
    1397         hideControl(ctrl, ctrl + "Text", notScenario);
     1439                      "exploreMap", "disableTreasures", "lockTeams",
     1440                      "gameSpeed", "guestSettings", "enableCheats",
     1441                      "mapSelection", "numPlayers", "mapType", "mapFilter"])
     1442        hideControl(ctrl, ctrl + "Text", canPlayerChange(ctrl));
    13981443
     1444    let notScenario = g_GameAttributes.mapType != "scenario" && g_IsController ;
     1445
    13991446    setMapDescription();
    14001447
    14011448    for (let i = 0; i < g_MaxPlayers; ++i)
     
    14311478        pCiv.selected = civ ? pCiv.list_data.indexOf(civ) : 0;
    14321479        pTeam.selected = team !== undefined && team >= 0 ? team+1 : 0;
    14331480
    1434         hideControl("playerAssignment["+i+"]", "playerAssignmentText["+i+"]", g_IsController);
    1435         hideControl("playerCiv["+i+"]", "playerCivText["+i+"]", notScenario);
    1436         hideControl("playerTeam["+i+"]", "playerTeamText["+i+"]", notScenario);
     1481        hideControl("playerAssignment["+i+"]", "playerAssignmentText["+i+"]", canPlayerChange("playerAssignment", i));
     1482        hideControl("playerCiv["+i+"]", "playerCivText["+i+"]", canPlayerChange("playerCiv", i));
     1483        hideControl("playerTeam["+i+"]", "playerTeamText["+i+"]", canPlayerChange("playerTeam", i));
    14371484
    14381485        // Allow host to chose player colors on non-scenario maps
    14391486        let pColorPicker = Engine.GetGUIObjectByName("playerColorPicker["+i+"]");
    14401487        let pColorPickerHeading = Engine.GetGUIObjectByName("playerColorHeading");
    1441         let canChangeColors = g_IsController && g_GameAttributes.mapType != "scenario";
    1442         pColorPicker.hidden = !canChangeColors;
    1443         pColorPickerHeading.hidden = !canChangeColors;
    1444         if (canChangeColors)
     1488        pColorPicker.hidden = !canPlayerChange("playerColor", i);
     1489        pColorPickerHeading.hidden = !canPlayerChange("playerColor", i);
     1490        if (canPlayerChange("playerColor", i))
    14451491            pColorPicker.selected = g_PlayerColors.findIndex(col => sameColor(col, color));
    14461492    }
    14471493
     
    15081554 */
    15091555function updateGameAttributes()
    15101556{
    1511     if (g_IsInGuiUpdate || !g_IsController)
     1557    if (g_IsInGuiUpdate)
    15121558        return;
    15131559
    15141560    if (g_IsNetworked)
    15151561    {
    1516         Engine.SetNetworkGameAttributes(g_GameAttributes);
     1562        Engine.NetworkChangeSettings(g_GameAttributes);
    15171563        if (g_LoadingState >= 2)
    15181564            sendRegisterGameStanza();
    15191565    }
     
    15271573
    15281574    Engine.PushGuiPage("page_aiconfig.xml", {
    15291575        "callback": "AIConfigCallback",
    1530         "isController": g_IsController,
     1576        "canBeChanged": canPlayerChange("playerConfig"),
    15311577        "playerSlot": playerSlot,
    15321578        "id": g_GameAttributes.settings.PlayerData[playerSlot].AI,
    15331579        "difficulty": g_GameAttributes.settings.PlayerData[playerSlot].AIDiff
     
    15411587{
    15421588    g_LastViewedAIPlayer = -1;
    15431589
    1544     if (!ai.save || !g_IsController)
     1590    if (!ai.save)
    15451591        return;
    15461592
    15471593    g_GameAttributes.settings.PlayerData[ai.playerSlot].AI = ai.id;
     
    15481594    g_GameAttributes.settings.PlayerData[ai.playerSlot].AIDiff = ai.difficulty;
    15491595
    15501596    if (g_IsNetworked)
    1551         Engine.SetNetworkGameAttributes(g_GameAttributes);
     1597        Engine.NetworkChangeSettings(g_GameAttributes);
    15521598    else
    15531599        updatePlayerList();
    15541600}
     
    16441690        {
    16451691            g_GameAttributes.settings.PlayerData[playerSlot].AI = "";
    16461692            if (g_IsNetworked)
    1647                 Engine.SetNetworkGameAttributes(g_GameAttributes);
     1693                Engine.NetworkChangeSettings(g_GameAttributes);
    16481694        }
    16491695
    16501696        let assignBox = Engine.GetGUIObjectByName("playerAssignment["+i+"]");
     
    16551701            assignBox.selected = selection;
    16561702        assignBoxText.caption = hostNameList[selection];
    16571703
    1658         if (g_IsController)
    1659             assignBox.onselectionchange = function() {
    1660                 if (g_IsInGuiUpdate)
    1661                     return;
     1704        assignBox.onSelectionChange = function() {
     1705            if (g_IsInGuiUpdate)
     1706                return;
    16621707
    1663                 let guid = hostGuidList[this.selected];
    1664                 if (!guid)
    1665                 {
    1666                     if (g_IsNetworked)
    1667                         // Unassign any host from this player slot
    1668                         Engine.AssignNetworkPlayer(playerID, "");
    1669                     // Remove AI from this player slot
    1670                     g_GameAttributes.settings.PlayerData[playerSlot].AI = "";
    1671                 }
    1672                 else if (guid.substr(0, 3) == "ai:")
    1673                 {
    1674                     if (g_IsNetworked)
    1675                         // Unassign any host from this player slot
    1676                         Engine.AssignNetworkPlayer(playerID, "");
    1677                     // Set the AI for this player slot
    1678                     g_GameAttributes.settings.PlayerData[playerSlot].AI = guid.substr(3);
    1679                 }
    1680                 else
    1681                     swapPlayers(guid, playerSlot);
     1708            let guid = hostGuidList[this.selected];
     1709            if (!guid)
     1710            {
     1711                if (g_IsNetworked)
     1712                    // Unassign any host from this player slot
     1713                    Engine.AssignNetworkPlayer(playerID, "");
     1714                // Remove AI from this player slot
     1715                g_GameAttributes.settings.PlayerData[playerSlot].AI = "";
     1716            }
     1717            else if (guid.substr(0, 3) == "ai:")
     1718            {
     1719                if (g_IsNetworked)
     1720                    // Unassign any host from this player slot
     1721                    Engine.AssignNetworkPlayer(playerID, "");
     1722                // Set the AI for this player slot
     1723                g_GameAttributes.settings.PlayerData[playerSlot].AI = guid.substr(3);
     1724            }
     1725            else
     1726                swapPlayers(guid, playerSlot);
    16821727
    1683                 if (g_IsNetworked)
    1684                     Engine.SetNetworkGameAttributes(g_GameAttributes);
    1685                 else
    1686                     updatePlayerList();
    1687                 updateReadyUI();
    1688             };
     1728            if (g_IsNetworked)
     1729                Engine.NetworkChangeSettings(g_GameAttributes);
     1730            else
     1731                updatePlayerList();
     1732            updateReadyUI();
     1733        };
    16891734    }
    16901735
    16911736    g_IsInGuiUpdate = false;
  • binaries/data/mods/public/gui/gamesetup/gamesetup.xml

     
    8080                            <object name="playerAssignment[n]" type="dropdown" style="ModernDropDown" size="22%+37 2 50%+35 30" tooltip_style="onscreenToolTip">
    8181                                <translatableAttribute id="tooltip">Select player.</translatableAttribute>
    8282                            </object>
    83                             <object name="playerAssignmentText[n]" type="text" style="ModernLabelText" size="22%+5 0 50%+35 30"/>
     83                            <object name="playerAssignmentText[n]" type="text" style="ModernLabelText" size="22%+33 0 50%+35 30"/>
    8484                            <object name="playerConfig[n]" type="button" style="StoneButton" size="50%+40 4 50%+64 28"
    8585                                tooltip_style="onscreenToolTip"
    8686                                font="sans-bold-stroke-12"
     
    336336                    </object>
    337337                </object>
    338338
     339                <object name="optionGuestSettings" size="14 188 94% 206">
     340                    <object size="0 0 40% 28" type="text" style="ModernRightLabelText">
     341                        <translatableAttribute id="caption">Guest Settings:</translatableAttribute>
     342                    </object>
     343                    <object name="guestSettingsText" size="40% 0 100% 100%" type="text" style="ModernLeftLabelText"/>
     344                    <object name="guestSettings" size="40%+10 0 100% 28" type="dropdown" style="ModernDropDown" hidden="true" tooltip_style="onscreenToolTip">
     345                        <translatableAttribute id="tooltip">Set which settings can be changed by every player.</translatableAttribute>
     346                    </object>
     347                </object>
     348
    339349                <object name="optionRevealMap" size="14 218 94% 246">
    340350                    <object size="0 0 40% 28" type="text" style="ModernRightLabelText">
    341351                        <translatableAttribute id="caption" comment="Make sure to differentiate between the revealed map and explored map options!">Revealed Map:</translatableAttribute>
  • source/gui/scripting/ScriptFunctions.cpp

     
    332332        LOGERROR("Failed to save game");
    333333}
    334334
    335 void SetNetworkGameAttributes(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue attribs1)
     335void NetworkChangeSetting(ScriptInterface::CxPrivate* pCxPrivate, const std::string& changedSetting, const std::string& value)
    336336{
    337     ENSURE(g_NetServer);
     337    ENSURE(g_NetClient);
     338    g_NetClient->SendChangeSettingMessage(changedSetting, value);
     339}
     340
     341void NetworkSetGameAttributes(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue attribs1)
     342{
     343    ENSURE(g_NetClient);
    338344    //TODO: This is a workaround because we need to pass a MutableHandle to a JSAPI functions somewhere
    339345    // (with no obvious reason).
    340346    JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
     
    341347    JSAutoRequest rq(cx);
    342348    JS::RootedValue attribs(cx, attribs1);
    343349
    344     g_NetServer->UpdateGameAttributes(&attribs, *(pCxPrivate->pScriptInterface));
     350    g_NetClient->SendSetGameAttributesMessage(&attribs, *(pCxPrivate->pScriptInterface));
    345351}
    346352
    347353void StartNetworkHost(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& playerName)
     
    427433
    428434void AssignNetworkPlayer(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int playerID, const std::string& guid)
    429435{
    430     ENSURE(g_NetServer);
     436    ENSURE(g_NetClient);
    431437
    432     g_NetServer->AssignPlayer(playerID, guid);
     438    g_NetClient->SendAssignPlayerMessage(playerID, guid);
    433439}
    434440
    435441void SetNetworkPlayerStatus(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const std::string& guid, int ready)
     
    10481054    scriptInterface.RegisterFunction<std::string, &GetPlayerGUID>("GetPlayerGUID");
    10491055    scriptInterface.RegisterFunction<bool, CStrW, bool, &KickPlayer>("KickPlayer");
    10501056    scriptInterface.RegisterFunction<JS::Value, &PollNetworkClient>("PollNetworkClient");
    1051     scriptInterface.RegisterFunction<void, JS::HandleValue, &SetNetworkGameAttributes>("SetNetworkGameAttributes");
     1057    scriptInterface.RegisterFunction<void, std::string, std::string, &NetworkChangeSetting>("NetworkChangeSetting");
     1058    scriptInterface.RegisterFunction<void, JS::HandleValue, &NetworkSetGameAttributes>("NetworkSetGameAttributes");
    10521059    scriptInterface.RegisterFunction<void, int, std::string, &AssignNetworkPlayer>("AssignNetworkPlayer");
    10531060    scriptInterface.RegisterFunction<void, std::string, int, &SetNetworkPlayerStatus>("SetNetworkPlayerStatus");
    10541061    scriptInterface.RegisterFunction<void, &ClearAllPlayerReady>("ClearAllPlayerReady");
  • source/network/NetClient.cpp

     
    321321    SetCurrState(NCS_UNCONNECTED);
    322322}
    323323
     324void CNetClient::SendChangeSettingMessage(const std::string& changedSetting, const std::string& value)
     325{
     326    CChangeSettingMessage changeSetting;
     327    changeSetting.m_ChangedSetting = changedSetting;
     328    changeSetting.m_NewValue = value;
     329    SendMessage(&changeSetting);
     330}
     331
     332void CNetClient::SendSetGameAttributesMessage(JS::MutableHandleValue attrs, ScriptInterface& scriptInterface)
     333{
     334    // Pass the attributes as JSON, since that's the easiest safe
     335    // cross-thread way of passing script data
     336    std::string attrsJSON = scriptInterface.StringifyJSON(attrs, false);
     337    CSetGameAttributesMessage setGameAttributes;
     338    setGameAttributes.m_GameAttributes = attrsJSON;
     339    SendMessage(&setGameAttributes);
     340}
     341
     342void CNetClient::SendAssignPlayerMessage(const int playerID, const std::string& guid)
     343{
     344    CAssignPlayerMessage assignPlayer;
     345    assignPlayer.m_PlayerID = playerID;
     346    assignPlayer.m_GUIDToAssign = guid;
     347    SendMessage(&assignPlayer);
     348}
     349
    324350void CNetClient::SendChatMessage(const std::wstring& text)
    325351{
    326352    CChatMessage chat;
  • source/network/NetClient.h

     
    187187     */
    188188    void LoadFinished();
    189189
     190    void SendChangeSettingMessage(const std::string& changedSetting, const std::string& value);
     191
     192    void SendSetGameAttributesMessage(JS::MutableHandleValue attrs, ScriptInterface& scriptInterface);
     193
     194    void SendAssignPlayerMessage(const int playerID, const std::string& guid);
     195
    190196    void SendChatMessage(const std::wstring& text);
    191197
    192198    void SendReadyMessage(const int status);
  • source/network/NetMessage.cpp

     
    199199        pNewMessage = new CSimulationMessage(scriptInterface);
    200200        break;
    201201
     202    case NMT_CHANGE_SETTING:
     203        pNewMessage = new CChangeSettingMessage;
     204        break;
     205
     206    case NMT_SET_GAME_ATTRIBUTES:
     207        pNewMessage = new CSetGameAttributesMessage;
     208        break;
     209
     210    case NMT_ASSIGN_PLAYER:
     211        pNewMessage = new CAssignPlayerMessage;
     212        break;
     213
    202214    default:
    203215        LOGERROR("CNetMessageFactory::CreateMessage(): Unknown message type '%d' received", header.GetType());
    204216        break;
  • source/network/NetMessages.h

     
    2828
    2929#define PS_PROTOCOL_MAGIC               0x5073013f      // 'P', 's', 0x01, '?'
    3030#define PS_PROTOCOL_MAGIC_RESPONSE      0x50630121      // 'P', 'c', 0x01, '!'
    31 #define PS_PROTOCOL_VERSION             0x01010012      // Arbitrary protocol
     31#define PS_PROTOCOL_VERSION             0x01010013      // Arbitrary protocol
    3232#define PS_DEFAULT_PORT                 0x5073          // 'P', 's'
    3333
    3434// Defines the list of message types. The order of the list must not change.
     
    6969    NMT_SYNC_CHECK, // OOS-detection hash checking
    7070    NMT_SYNC_ERROR, // OOS-detection error
    7171    NMT_SIMULATION_COMMAND,
     72    NMT_CHANGE_SETTING,
     73    NMT_SET_GAME_ATTRIBUTES,
     74    NMT_ASSIGN_PLAYER,
    7275    NMT_LAST                // Last message in the list
    7376};
    7477
     
    208211    NMT_END_ARRAY()
    209212END_NMT_CLASS()
    210213
     214START_NMT_CLASS_(ChangeSetting, NMT_CHANGE_SETTING)
     215    NMT_FIELD(CStr, m_GUID) // Ignored when client->server, valid when server->client
     216    NMT_FIELD(CStr, m_ChangedSetting)
     217    NMT_FIELD(CStr, m_NewValue)
     218END_NMT_CLASS()
     219
     220START_NMT_CLASS_(SetGameAttributes, NMT_SET_GAME_ATTRIBUTES)
     221    NMT_FIELD(CStr, m_GameAttributes)
     222END_NMT_CLASS()
     223
     224START_NMT_CLASS_(AssignPlayer, NMT_ASSIGN_PLAYER)
     225    NMT_FIELD_INT(m_PlayerID, i8, 1)
     226    NMT_FIELD(CStr, m_GUIDToAssign)
     227END_NMT_CLASS()
     228
    211229END_NMTS()
    212230
    213231#else
  • source/network/NetServer.cpp

     
    649649    session->AddTransition(NSS_PREGAME, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context);
    650650    session->AddTransition(NSS_PREGAME, (uint)NMT_CHAT, NSS_PREGAME, (void*)&OnChat, context);
    651651    session->AddTransition(NSS_PREGAME, (uint)NMT_READY, NSS_PREGAME, (void*)&OnReady, context);
     652    session->AddTransition(NSS_PREGAME, (uint)NMT_CHANGE_SETTING, NSS_PREGAME, (void*)&OnChangeSetting, context);
     653    session->AddTransition(NSS_PREGAME, (uint)NMT_SET_GAME_ATTRIBUTES, NSS_PREGAME, (void*)&OnSetGameAttributes, context);
     654    session->AddTransition(NSS_PREGAME, (uint)NMT_ASSIGN_PLAYER, NSS_PREGAME, (void*)&OnAssignPlayer, context);
    652655    session->AddTransition(NSS_PREGAME, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnLoadedGame, context);
    653656
    654657    session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context);
     
    11061109    return true;
    11071110}
    11081111
     1112bool CNetServerWorker::OnChangeSetting(void* context, CFsmEvent* event)
     1113{
     1114    ENSURE(event->GetType() == (uint)NMT_CHANGE_SETTING);
     1115    CNetServerSession* session = (CNetServerSession*)context;
     1116    CNetServerWorker& server = session->GetServer();
     1117
     1118    CChangeSettingMessage* message = (CChangeSettingMessage*)event->GetParamRef();
     1119    message->m_GUID = session->GetGUID();
     1120    // Forward message to host
     1121    for (CNetServerSession* session : server.m_Sessions)
     1122        if (session->GetCurrState() == NSS_PREGAME && session->GetGUID() == server.m_HostGUID)
     1123            return session->SendMessage(message);
     1124    return false;
     1125}
     1126
     1127bool CNetServerWorker::OnSetGameAttributes(void* context, CFsmEvent* event)
     1128{
     1129    ENSURE(event->GetType() == (uint)NMT_CHANGE_SETTING);
     1130    CNetServerSession* session = (CNetServerSession*)context;
     1131    CNetServerWorker& server = session->GetServer();
     1132
     1133    if (session->GetGUID() != server.m_HostGUID) // Client wasn't allowed to send new attributes
     1134        return false;
     1135
     1136    CSetGameAttributesMessage* message = (CSetGameAttributesMessage*)event->GetParamRef();
     1137    server.m_GameAttributesQueue.push_back(message->m_GameAttributes);
     1138    return true;
     1139}
     1140
     1141bool CNetServerWorker::OnAssignPlayer(void* context, CFsmEvent* event)
     1142{
     1143    ENSURE(event->GetType() == (uint)NMT_ASSIGN_PLAYER);
     1144    CNetServerSession* session = (CNetServerSession*)context;
     1145    CNetServerWorker& server = session->GetServer();
     1146
     1147    if (session->GetGUID() != server.m_HostGUID) // Client wasn't allowed to assign a player
     1148        return false;
     1149
     1150    CAssignPlayerMessage* message = (CAssignPlayerMessage*)event->GetParamRef();
     1151    server.m_AssignPlayerQueue.emplace_back(message->m_PlayerID, message->m_GUIDToAssign);
     1152    return true;
     1153}
     1154
    11091155bool CNetServerWorker::OnLoadedGame(void* context, CFsmEvent* event)
    11101156{
    11111157    ENSURE(event->GetType() == (uint)NMT_LOADED_GAME);
  • source/network/NetServer.h

     
    270270    static bool OnInGame(void* context, CFsmEvent* event);
    271271    static bool OnChat(void* context, CFsmEvent* event);
    272272    static bool OnReady(void* context, CFsmEvent* event);
     273    static bool OnChangeSetting(void* context, CFsmEvent* event);
     274    static bool OnSetGameAttributes(void* context, CFsmEvent* event);
     275    static bool OnAssignPlayer(void* context, CFsmEvent* event);
    273276    static bool OnLoadedGame(void* context, CFsmEvent* event);
    274277    static bool OnJoinSyncingLoadedGame(void* context, CFsmEvent* event);
    275278    static bool OnRejoined(void* context, CFsmEvent* event);