Ticket #3242: t3242_observer_late_join_v2.4.patch

File t3242_observer_late_join_v2.4.patch, 11.0 KB (added by elexis, 9 years ago)

That what Itms said.

  • binaries/data/mods/public/gui/common/network.js

     
    44    switch (id)
    55    {
    66    case 0: return translate("Unknown reason");
    77    case 1: return translate("Unexpected shutdown");
    88    case 2: return translate("Incorrect network protocol version");
    9     case 3: return translate("Game has already started");
     9    case 3: return translate("Game is loading, please try later");
     10    case 4: return translate("Game has already started, no observers allowed");
    1011    default: return sprintf(translate("\\[Invalid value %(id)s]"), { id: id });
    1112    }
    1213}
    1314
    1415function reportDisconnect(reason)
  • binaries/data/mods/public/gui/gamesetup/gamesetup.js

     
    152152    var mapFilters = Engine.GetGUIObjectByName("mapFilterSelection");
    153153    mapFilters.list = getFilterNames();
    154154    mapFilters.list_data = getFilterIds();
    155155    g_GameAttributes.mapFilter = "default";
    156156
     157    // For singleplayer reduce the size of more options dialog by three options (cheats, rated game, observer late join = 90px)
     158    if (!g_IsNetworked)
     159    {
     160        Engine.GetGUIObjectByName("moreOptions").size = "50%-200 50%-195 50%+200 50%+160";
     161        Engine.GetGUIObjectByName("hideMoreOptions").size = "50%-70 310 50%+70 336";
     162    }
     163    // For non-lobby multiplayergames reduce the size of the dialog by one option (rated game, 30px)
     164    else if (g_IsNetworked && !Engine.HasXmppClient())
     165    {
     166        Engine.GetGUIObjectByName("moreOptions").size = "50%-200 50%-195 50%+200 50%+220";
     167        Engine.GetGUIObjectByName("hideMoreOptions").size = "50%-70 370 50%+70 396";
     168        Engine.GetGUIObjectByName("optionObserverLateJoin").size = "14 338 94% 366";
     169    }
     170
    157171    // Setup controls for host only
    158172    if (g_IsController)
    159173    {
    160174        mapTypes.selected = 0;
    161175        mapFilters.selected = 0;
     
    253267        Engine.GetGUIObjectByName("exploreMap").onPress = function() {
    254268            g_GameAttributes.settings.ExploreMap = this.checked;
    255269            updateGameAttributes();
    256270        };
    257271
     272        Engine.GetGUIObjectByName("observerLateJoin").onPress = function() {
     273            g_GameAttributes.settings.ObserverLateJoin = this.checked;
     274            updateGameAttributes();
     275        };
     276
    258277        Engine.GetGUIObjectByName("disableTreasures").onPress = function() {
    259278            g_GameAttributes.settings.DisableTreasures = this.checked;
    260279            updateGameAttributes();
    261280        };
    262281
     
    314333    }
    315334    else
    316335    {
    317336        Engine.GetGUIObjectByName("optionCheats").hidden = false;
    318337        Engine.GetGUIObjectByName("enableCheats").checked = false;
     338        Engine.GetGUIObjectByName("optionObserverLateJoin").hidden = false;
    319339        g_GameAttributes.settings.CheatsEnabled = false;
    320340        // Setup ranked option if we are connected to the lobby.
    321341        if (Engine.HasXmppClient())
    322342        {
    323343            Engine.GetGUIObjectByName("optionRating").hidden = false;
     
    329349        }
    330350        if (g_IsController)
    331351        {
    332352            Engine.GetGUIObjectByName("enableCheatsText").hidden = true;
    333353            Engine.GetGUIObjectByName("enableCheats").hidden = false;
     354            Engine.GetGUIObjectByName("observerLateJoinText").hidden = true;
     355            Engine.GetGUIObjectByName("observerLateJoin").hidden = false;
     356
    334357            if (Engine.HasXmppClient())
    335358            {
    336359                Engine.GetGUIObjectByName("enableRatingText").hidden = true;
    337360                Engine.GetGUIObjectByName("enableRating").hidden = false;
    338361            }
     
    11861209    var enableCheats = Engine.GetGUIObjectByName("enableCheats");
    11871210    var enableRating = Engine.GetGUIObjectByName("enableRating");
    11881211    var populationCap = Engine.GetGUIObjectByName("populationCap");
    11891212    var startingResources = Engine.GetGUIObjectByName("startingResources");
    11901213    var ceasefire = Engine.GetGUIObjectByName("ceasefire");
     1214    var observerLateJoin = Engine.GetGUIObjectByName("observerLateJoin");
    11911215
    11921216    var numPlayersText= Engine.GetGUIObjectByName("numPlayersText");
    11931217    var mapSizeDesc = Engine.GetGUIObjectByName("mapSizeDesc");
    11941218    var mapSizeText = Engine.GetGUIObjectByName("mapSizeText");
     1219    var observerLateJoinText = Engine.GetGUIObjectByName("observerLateJoinText");
    11951220    var revealMapText = Engine.GetGUIObjectByName("revealMapText");
    11961221    var exploreMapText = Engine.GetGUIObjectByName("exploreMapText");
    11971222    var disableTreasuresText = Engine.GetGUIObjectByName("disableTreasuresText");
    11981223    var victoryConditionText = Engine.GetGUIObjectByName("victoryConditionText");
    11991224    var lockTeamsText = Engine.GetGUIObjectByName("lockTeamsText");
     
    12201245        enableCheats.enabled = !enableRating.checked;
    12211246        lockTeams.enabled = !enableRating.checked;
    12221247    }
    12231248    else
    12241249        enableRatingText.caption = "Unknown";
     1250
     1251    observerLateJoin.checked = g_GameAttributes.settings.ObserverLateJoin;
     1252    observerLateJoinText.caption = observerLateJoin.checked ? translate("Yes") : translate("No");
     1253
    12251254    gameSpeedText.caption = g_GameSpeeds.names[speedIdx];
    12261255    gameSpeedBox.selected = speedIdx;
    12271256    populationCap.selected = (mapSettings.PopulationCap !== undefined && POPULATION_CAP_DATA.indexOf(mapSettings.PopulationCap) != -1 ? POPULATION_CAP_DATA.indexOf(mapSettings.PopulationCap) : POPULATION_CAP_DEFAULTIDX);
    12281257    populationCapText.caption = POPULATION_CAP[populationCap.selected];
    12291258    startingResources.selected = (mapSettings.StartingResources !== undefined && STARTING_RESOURCES_DATA.indexOf(mapSettings.StartingResources) != -1 ? STARTING_RESOURCES_DATA.indexOf(mapSettings.StartingResources) : STARTING_RESOURCES_DEFAULTIDX);
  • binaries/data/mods/public/gui/gamesetup/gamesetup.xml

     
    268268            <!-- End Options -->
    269269            </object>
    270270
    271271            <!-- More Options -->
    272272            <object hidden="true" name="moreOptionsFade" type="image" z="60" sprite="ModernFade"/>
    273             <object name="moreOptions" type="image" sprite="ModernDialog" size="50%-200 50%-195 50%+200 50%+220" z="70" hidden="true">
     273            <object name="moreOptions" type="image" sprite="ModernDialog" size="50%-200 50%-195 50%+200 50%+250" z="70" hidden="true">
    274274                <object style="ModernLabelText" type="text" size="50%-128 -18 50%+128 14">
    275275                    <translatableAttribute id="caption">More Options</translatableAttribute>
    276276                </object>
    277277
    278278                <object size="14 38 94% 66">
     
    383383                    <object name="enableRating" size="40%+10 5 40%+30 100%-5" type="checkbox" style="ModernTickBox" hidden="true" tooltip_style="onscreenToolTip">
    384384                        <translatableAttribute id="tooltip">Toggle if this game will be rated for the leaderboard.</translatableAttribute>
    385385                    </object>
    386386                </object>
    387387
     388                <object name="optionObserverLateJoin" size="14 368 94% 396" hidden="true">
     389                    <object size="0 0 40% 28" type="text" hidden="false" style="ModernRightLabelText">
     390                        <translatableAttribute id="caption">Observer Join:</translatableAttribute>
     391                    </object>
     392                    <object name="observerLateJoinText" size="40% 0 100% 28" type="text" style="ModernLeftLabelText"/>
     393                    <object name="observerLateJoin" size="40%+10 5 40%+30 100%-5" type="checkbox" style="ModernTickBox" hidden="true" tooltip_style="onscreenToolTip">
     394                        <translatableAttribute id="tooltip">Allow observers to join after the game started.</translatableAttribute>
     395                    </object>
     396                </object>
     397
    388398                <!-- Hide More Options Button -->
    389399                <object
    390400                    name="hideMoreOptions"
    391401                    type="button"
    392402                    style="StoneButton"
    393                     size="50%-70 370 50%+70 396"
     403                    size="50%-70 400 50%+70 426"
    394404                    tooltip_style="onscreenToolTip"
    395405                    hotkey="cancel"
    396406                >
    397407                    <translatableAttribute id="caption">OK</translatableAttribute>
    398408                    <translatableAttribute id="tooltip">Close more game options window</translatableAttribute>
  • source/network/NetHost.h

     
    1 /* Copyright (C) 2011 Wildfire Games.
     1/* Copyright (C) 2015 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
    55 * it under the terms of the GNU General Public License as published by
    66 * the Free Software Foundation, either version 2 of the License, or
     
    6060enum NetDisconnectReason
    6161{
    6262    NDR_UNKNOWN = 0,
    6363    NDR_UNEXPECTED_SHUTDOWN,
    6464    NDR_INCORRECT_PROTOCOL_VERSION,
     65    NDR_SERVER_LOADING,
    6566    NDR_SERVER_ALREADY_IN_GAME
    6667};
    6768
    6869class CNetHost
    6970{
  • source/network/NetServer.cpp

     
    787787    ENSURE(event->GetType() == (uint)NMT_AUTHENTICATE);
    788788
    789789    CNetServerSession* session = (CNetServerSession*)context;
    790790    CNetServerWorker& server = session->GetServer();
    791791
    792     CAuthenticateMessage* message = (CAuthenticateMessage*)event->GetParamRef();
     792    // Prohibit joins while the game is loading
     793    if (server.m_State == SERVER_STATE_LOADING)
     794    {
     795        LOGMESSAGE("Refused connection while the game is loading");
     796        session->Disconnect(NDR_SERVER_LOADING);
     797        return true;
     798    }
    793799
     800    CAuthenticateMessage* message = (CAuthenticateMessage*)event->GetParamRef();
    794801    CStrW username = server.DeduplicatePlayerName(SanitisePlayerName(message->m_Name));
    795802
    796     bool isRejoining = false;
     803    // Optionally allow observers to join after the game has started
     804    bool observerLateJoin = false;
     805    ScriptInterface& scriptInterface = server.GetScriptInterface();
     806    JSContext* cx = scriptInterface.GetContext();
     807    JSAutoRequest rq(cx);
     808    JS::RootedValue settings(cx);
     809    scriptInterface.GetProperty(server.m_GameAttributes.get(), "settings", &settings);
     810    if (scriptInterface.HasProperty(settings, "ObserverLateJoin"))
     811        scriptInterface.GetProperty(settings, "ObserverLateJoin", observerLateJoin);
    797812
     813    // If the game has already started, only allow rejoins
     814    bool isRejoining = false;
    798815    if (server.m_State != SERVER_STATE_PREGAME)
    799816    {
    800 //      isRejoining = true; // uncomment this to test rejoining even if the player wasn't connected previously
    801 
    802817        // Search for an old disconnected player of the same name
    803818        // (TODO: if GUIDs were stable, we should use them instead)
    804         for (PlayerAssignmentMap::iterator it = server.m_PlayerAssignments.begin(); it != server.m_PlayerAssignments.end(); ++it)
    805         {
    806             if (!it->second.m_Enabled && it->second.m_Name == username)
    807             {
    808                 isRejoining = true;
    809                 break;
    810             }
    811         }
     819        isRejoining =
     820                observerLateJoin ||
     821                std::find_if(
     822                    server.m_PlayerAssignments.begin(), server.m_PlayerAssignments.end(),
     823                    [&username] (const std::pair<CStr, PlayerAssignment>& pair)
     824                    { return pair.second.m_Enabled && pair.second.m_Name == username; })
     825                != server.m_PlayerAssignments.end();
    812826
    813827        // Players who weren't already in the game are not allowed to join now that it's started
    814828        if (!isRejoining)
    815829        {
    816830            LOGMESSAGE("Refused connection after game start from not-previously-known user \"%s\"", utf8_from_wstring(username));