Ticket #3241: t3241_kick_v2.patch

File t3241_kick_v2.patch, 25.1 KB (added by elexis, 9 years ago)

Should be finished by now. Most importantly fixes that everyone had the ability to kick.

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

     
    55    {
    66    case 0: return translate("Unknown reason");
    77    case 1: return translate("Unexpected shutdown");
    88    case 2: return translate("Incorrect network protocol version");
    99    case 3: return translate("Game has already started");
     10    case 4: return translate("You have been kicked from the match");
     11    case 5: return translate("You have been banned from the match");
    1012    default: return sprintf(translate("\\[Invalid value %(id)s]"), { id: id });
    1113    }
    1214}
    1315
    1416function reportDisconnect(reason)
  • binaries/data/mods/public/gui/gamesetup/gamesetup.js

     
    17051705
    17061706    var message = "";
    17071707    if ("text" in msg && msg.text)
    17081708        message = escapeText(msg.text);
    17091709
     1710    // Kick / ban players
     1711    if ("text" in msg)
     1712    {
     1713        let split = msg.text.split(/\s/);
     1714        let kick = msg.text.indexOf("/kick") == 0;
     1715        let ban = msg.text.indexOf("/ban") == 0;
     1716        let playerGUID = Engine.GetPlayerGUID();
     1717        if (kick || ban)
     1718        {
     1719            if (!g_IsNetworked || !g_IsController || msg.guid != playerGUID)
     1720                return;
     1721            var trimmed = msg.text.substr(split[0].length + 1);
     1722            var matched = "";
     1723            // Reject names which don't match or are a superset of the intended name.
     1724            for each (let player in g_PlayerAssignments)
     1725                if (trimmed.indexOf(player.name) == 0 && player.name.length > matched.length)
     1726                    matched = player.name;
     1727            // Prevent the host from kicking him/herself
     1728            if (matched.length && matched != g_PlayerAssignments[playerGUID].name)
     1729            {
     1730                // Sending the message takes a while, so we phrase this past tense.
     1731                // The text should be translated for each client individually (see #3304)
     1732                Engine.SendNetworkChat(matched + " has been " + (ban ? "banned" : "kicked") + ".");
     1733                Engine.KickPlayer(matched, ban);
     1734            }
     1735            return;
     1736        }
     1737    }
     1738   
    17101739    // TODO: Maybe host should have distinct font/color?
    17111740    var color = "white";
    17121741
    17131742    if (msg.guid && g_PlayerAssignments[msg.guid] && g_PlayerAssignments[msg.guid].player != -1)
    17141743    {
  • binaries/data/mods/public/gui/session/messages.js

     
    241241            obj.caption = translate("Connection to the server has been authenticated.");
    242242            obj.hidden = false;
    243243            break;
    244244        case "disconnected":
    245245            g_Disconnected = true;
    246             obj.caption = translate("Connection to the server has been lost.") + "\n\n" + translate("The game has ended.");
     246            obj.caption = translate("Connection to the server has been lost.") + "\n" + 
     247                getDisconnectReason(message.reason)
     248            if (!message.reason)
     249                obj.caption += ".\n" + translate("The game has ended.");
    247250            obj.hidden = false;
    248251            break;
    249252        default:
    250253            error("Unrecognised netstatus type '" + message.status + "'");
    251254            break;
     
    325328function submitChatInput()
    326329{
    327330    var input = Engine.GetGUIObjectByName("chatInput");
    328331    var text = input.caption;
    329332    var isCheat = false;
     333
    330334    if (text.length)
    331335    {
     336        // Check cheats
    332337        if (!g_IsObserver && g_Players[Engine.GetPlayerID()].cheatsEnabled)
    333338        {
    334339            for each (var cheat in Object.keys(cheats))
    335340            {
    336341                // Line must start with the cheat.
     
    374379                isCheat = true;
    375380                break;
    376381            }
    377382        }
    378383
    379         // Observers should only send messages to "/all"
    380         if (!isCheat && (!g_IsObserver || text.indexOf("/") == -1 || text.indexOf("/all ") == 0))
     384        if (!isCheat)
    381385        {
    382             if (Engine.GetGUIObjectByName("toggleTeamChat").checked)
    383                 text = "/team " + text;
    384 
    385             if (g_IsNetworked)
    386                 Engine.SendNetworkChat(text);
     386            if (text.trim() == "/list")
     387                addChatMessage({ "type": "clientlist", "guid": "local"});
    387388            else
    388                 addChatMessage({ "type": "message", "guid": "local", "text": text });
     389            {
     390                if (Engine.GetGUIObjectByName("toggleTeamChat").checked)
     391                    text = "/team " + text;
     392   
     393                if (g_IsNetworked)
     394                    Engine.SendNetworkChat(text);
     395                else
     396                    addChatMessage({ "type": "message", "guid": "local", "text": text });
     397            }
    389398        }
    390399        input.caption = ""; // Clear chat input
    391400    }
    392401
    393402    input.blur(); // Remove focus
     
    453462        if (!g_IsNetworked && msg.player == Engine.GetPlayerID())
    454463            formatted = translate("You have been defeated.");
    455464        else
    456465            formatted = sprintf(translate("%(player)s has been defeated."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
    457466        break;
     467    case "clientlist":
     468        var userlist = Object.keys(playerAssignments).sort(function(a,b)
     469        {
     470            var playerA = playerAssignments[a].player;
     471            var playerB = playerAssignments[b].player;
     472            if (playerA == -1 || playerB == -1)
     473                return 1;
     474            else
     475                return playerA - playerB;
     476        }).map(guid => playerAssignments[guid].name).join(",");
     477        formatted = sprintf(translate("Users: %(users)s."), { "users": userlist });
     478        break;
    458479    case "diplomacy":
    459480        var message;
    460481        if (msg.player == Engine.GetPlayerID())
    461482        {
    462483            [username, playerColor] = getUsernameAndColor(msg.player1);
     
    601622}
    602623
    603624// Parses chat messages for commands.
    604625function parseChatCommands(msg, playerAssignments)
    605626{
     627    var ban = false;
    606628    // Only interested in messages that start with '/'.
    607629    if (!msg.text || msg.text[0] != '/')
    608630        return;
    609631
    610632    var sender;
     
    627649        msg.hide = false;
    628650        recurse = true;
    629651        break;
    630652    case "/team":
    631653        // Check if we are in a team.
    632         if (g_Players[Engine.GetPlayerID()] && g_Players[Engine.GetPlayerID()].team != -1)
     654        if (!g_IsObserver && g_Players[Engine.GetPlayerID()] && g_Players[Engine.GetPlayerID()].team != -1)
    633655        {
    634656            if (g_Players[Engine.GetPlayerID()].team != g_Players[sender].team)
    635657                msg.hide = true;
    636658            else
    637659                msg.context = translate("Team");
     
    641663        recurse = true;
    642664        break;
    643665    case "/ally":
    644666    case "/allies":
    645667        // Check if we sent the message, or are the sender's (mutual) ally
    646         if (Engine.GetPlayerID() == sender || (g_Players[sender] && g_Players[sender].isMutualAlly[Engine.GetPlayerID()]))
     668        if (!g_IsObserver && (Engine.GetPlayerID() == sender || (g_Players[sender] && g_Players[sender].isMutualAlly[Engine.GetPlayerID()])))
    647669            msg.context = translate("Ally");
    648670        else
    649671            msg.hide = true;
    650672
    651673        recurse = true;
    652674        break;
    653675    case "/enemy":
    654676    case "/enemies":
    655677        // Check if we sent the message, or are the sender's enemy
    656         if (Engine.GetPlayerID() == sender || (g_Players[sender] && g_Players[sender].isEnemy[Engine.GetPlayerID()]))
     678        if (!g_IsObserver && (Engine.GetPlayerID() == sender || (g_Players[sender] && g_Players[sender].isEnemy[Engine.GetPlayerID()])))
    657679            msg.context = translate("Enemy");
    658680        else
    659681            msg.hide = true;
    660682
    661683        recurse = true;
    662684        break;
    663685    case "/me":
    664686        msg.action = true;
    665687        break;
     688    case "/ban":
     689        ban = true;
     690    case "/kick":
     691        msg.hide = true;
     692        if (!g_IsNetworked || !g_IsController || msg.guid != Engine.GetPlayerGUID())
     693            break;
     694        var trimmed = msg.text.substr(split[0].length + 1);
     695        var matched = "";
     696        var playerGUID = Engine.GetPlayerGUID();
     697        // Reject names which don't match or are a superset of the intended name.
     698        for each (var player in playerAssignments)
     699            if (trimmed.indexOf(player.name) == 0 && player.name.length > matched.length)
     700                matched = player.name;
     701        // Prevent the host from kicking him/herself
     702        if (matched.length && matched != g_PlayerAssignments[playerGUID].name)
     703        {
     704            Engine.KickPlayer(matched, ban);
     705            // Sending the message takes a while, so we phrase this past tense.
     706            // The text should be translated for each client individually (see #3304)
     707            submitChatDirectly(matched + " has been " + (ban ? "banned" : "kicked") + ".");
     708        }
     709        return;
    666710    case "/msg":
    667711        var trimmed = msg.text.substr(split[0].length + 1);
    668712        var matched = "";
    669713
     714        // Don't show private messages from observers to players
     715        if (g_PlayerAssignments[msg.guid].player == -1 && g_PlayerAssignments[Engine.GetPlayerGUID()].player != -1)
     716        {
     717            msg.hide = true;
     718            return;
     719        }
     720       
    670721        // Reject names which don't match or are a superset of the intended name.
    671722        for each (var player in playerAssignments)
    672723            if (trimmed.indexOf(player.name + " ") == 0 && player.name.length > matched.length)
    673724                matched = player.name;
    674725
    675726        // If the local player's name was the longest one matched, show the message.
    676         var playerName = g_Players[Engine.GetPlayerID()].name;
    677         if (matched.length && (matched == playerName || sender == Engine.GetPlayerID()))
     727        // Show the message only for sender and recipient.
     728        if (matched.length && (msg.guid == Engine.GetPlayerGUID() || matched == g_PlayerAssignments[Engine.GetPlayerGUID()].name))
    678729        {
    679730            msg.context = translate("Private");
    680731            msg.text = trimmed.substr(matched.length + 1);
    681732            msg.hide = false; // Might override team message hiding.
    682733            return;
  • binaries/data/mods/public/gui/session/session.xml

     
    55<script file="gui/common/colorFades.js"/>
    66<script file="gui/common/functions_civinfo.js"/>
    77<script file="gui/common/functions_global_object.js"/>
    88<script file="gui/common/functions_utility.js"/>
    99<script file="gui/common/l10n.js"/>
     10<script file="gui/common/network.js"/>
    1011<script file="gui/common/music.js"/>
    1112<script file="gui/common/timer.js"/>
    1213<script file="gui/common/tooltips.js"/>
    1314<!-- load all scripts in this directory -->
    1415<script directory="gui/session/"/>
  • source/gui/scripting/ScriptFunctions.cpp

     
    186186    if (g_Game)
    187187        return g_Game->GetPlayerID();
    188188    return -1;
    189189}
    190190
     191std::string GetPlayerGUID(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
     192{
     193    if (g_NetServer)
     194        return g_NetServer->GetHostGUID();
     195    else if (g_NetClient)
     196        return g_NetClient->GetGUID();
     197    else
     198        return "";
     199}
     200
    191201void SetPlayerID(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int id)
    192202{
    193203    if (g_Game)
    194204        g_Game->SetPlayerID(id);
    195205}
     
    345355    SAFE_DELETE(g_NetServer);
    346356    SAFE_DELETE(g_NetClient);
    347357    SAFE_DELETE(g_Game);
    348358}
    349359
     360void KickPlayer(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::wstring playerName, bool ban)
     361{
     362    if (g_NetServer)
     363        g_NetServer->KickPlayer(playerName, ban);
     364}
     365
    350366JS::Value PollNetworkClient(ScriptInterface::CxPrivate* pCxPrivate)
    351367{
    352368    if (!g_NetClient)
    353369        return JS::UndefinedValue();
    354370
     
    954970    scriptInterface.RegisterFunction<void, JS::HandleValue, int, &StartGame>("StartGame");
    955971    scriptInterface.RegisterFunction<void, &Script_EndGame>("EndGame");
    956972    scriptInterface.RegisterFunction<void, std::wstring, &StartNetworkHost>("StartNetworkHost");
    957973    scriptInterface.RegisterFunction<void, std::wstring, std::string, &StartNetworkJoin>("StartNetworkJoin");
    958974    scriptInterface.RegisterFunction<void, &DisconnectNetworkGame>("DisconnectNetworkGame");
     975    scriptInterface.RegisterFunction<void, std::wstring, bool, &KickPlayer>("KickPlayer");
    959976    scriptInterface.RegisterFunction<JS::Value, &PollNetworkClient>("PollNetworkClient");
    960977    scriptInterface.RegisterFunction<void, JS::HandleValue, &SetNetworkGameAttributes>("SetNetworkGameAttributes");
    961978    scriptInterface.RegisterFunction<void, int, std::string, &AssignNetworkPlayer>("AssignNetworkPlayer");
    962979    scriptInterface.RegisterFunction<void, std::string, int, &SetNetworkPlayerStatus>("SetNetworkPlayerStatus");
    963980    scriptInterface.RegisterFunction<void, &ClearAllPlayerReady>("ClearAllPlayerReady");
     
    977994    scriptInterface.RegisterFunction<void, &QuickLoad>("QuickLoad");
    978995
    979996    // Misc functions
    980997    scriptInterface.RegisterFunction<std::wstring, std::wstring, &SetCursor>("SetCursor");
    981998    scriptInterface.RegisterFunction<int, &GetPlayerID>("GetPlayerID");
     999    scriptInterface.RegisterFunction<std::string, &GetPlayerGUID>("GetPlayerGUID");
    9821000    scriptInterface.RegisterFunction<void, int, &SetPlayerID>("SetPlayerID");
    9831001    scriptInterface.RegisterFunction<void, std::string, &OpenURL>("OpenURL");
    9841002    scriptInterface.RegisterFunction<std::wstring, &GetMatchID>("GetMatchID");
    9851003    scriptInterface.RegisterFunction<void, &RestartInAtlas>("RestartInAtlas");
    9861004    scriptInterface.RegisterFunction<bool, &AtlasIsAvailable>("AtlasIsAvailable");
  • source/network/NetClient.cpp

     
    139139    ENSURE(!m_Session); // must be called before we start the connection
    140140
    141141    m_UserName = username;
    142142}
    143143
     144CStr CNetClient::GetGUID()
     145{
     146    return m_GUID;
     147}
     148
    144149bool CNetClient::SetupConnection(const CStr& server)
    145150{
    146151    CNetClientSession* session = new CNetClientSession(*this);
    147152    bool ok = session->Connect(PS_DEFAULT_PORT, server);
    148153    SetAndOwnSession(session);
  • source/network/NetClient.h

     
    8686     * Set the user's name that will be displayed to all players.
    8787     * This must not be called after the connection setup.
    8888     */
    8989    void SetUserName(const CStrW& username);
    9090
     91    /** Returns the GUID of the client. */
     92    CStr GetGUID();
     93
    9194    /**
    9295     * Set up a connection to the remote networked server.
    9396     * @param server IP address or host name to connect to
    9497     * @return true on success, false on connection failure
    9598     */
  • 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_ALREADY_IN_GAME
     65    NDR_SERVER_ALREADY_IN_GAME,
     66    NDR_KICKED,
     67    NDR_BANNED
    6668};
    6769
    6870class CNetHost
    6971{
    7072public:
  • source/network/NetServer.cpp

     
    127127
    128128    m_ServerTurnManager = NULL;
    129129
    130130    m_ServerName = DEFAULT_SERVER_NAME;
    131131    m_WelcomeMessage = DEFAULT_WELCOME_MESSAGE;
     132    m_HostGUID = std::string("");
    132133}
    133134
    134135CNetServerWorker::~CNetServerWorker()
    135136{
    136137    if (m_State != SERVER_STATE_UNCONNECTED)
     
    604605    session->SetFirstState(NSS_HANDSHAKE);
    605606}
    606607
    607608bool CNetServerWorker::HandleConnect(CNetServerSession* session)
    608609{
     610    CNetServerWorker& server = session->GetServer();
     611
     612    // Disconnect banned IPs
     613    std::string ipAddress = session -> GetIPAddress();
     614    if(std::find(server.m_BannedIPs.begin(), server.m_BannedIPs.end(), ipAddress) != server.m_BannedIPs.end())
     615    {
     616        session->Disconnect(NDR_BANNED);
     617        return false;
     618    }
     619
     620    // Send handshake challenge
    609621    CSrvHandshakeMessage handshake;
    610622    handshake.m_Magic = PS_PROTOCOL_MAGIC;
    611623    handshake.m_ProtocolVersion = PS_PROTOCOL_VERSION;
    612624    handshake.m_SoftwareVersion = PS_PROTOCOL_VERSION;
    613625    return session->SendMessage(&handshake);
     
    615627
    616628void CNetServerWorker::OnUserJoin(CNetServerSession* session)
    617629{
    618630    AddPlayer(session->GetGUID(), session->GetUserName());
    619631
     632    if (m_HostGUID == "")
     633        m_HostGUID = session->GetGUID();
     634
    620635    CGameSetupMessage gameSetupMessage(GetScriptInterface());
    621636    gameSetupMessage.m_Data = m_GameAttributes.get();
    622637    session->SendMessage(&gameSetupMessage);
    623638
    624639    CPlayerAssignmentMessage assignMessage;
     
    630645{
    631646    RemovePlayer(session->GetGUID());
    632647
    633648    if (m_ServerTurnManager && session->GetCurrState() != NSS_JOIN_SYNCING)
    634649        m_ServerTurnManager->UninitialiseClient(session->GetHostID()); // TODO: only for non-observers
    635 
    636     // TODO: ought to switch the player controlled by that client
    637     // back to AI control, or something?
    638650}
    639651
    640652void CNetServerWorker::AddPlayer(const CStr& guid, const CStrW& name)
    641653{
    642654    // Find all player IDs in active use; we mustn't give them to a second player (excluding the unassigned ID: -1)
     
    707719        it->second.m_Status = 0;
    708720
    709721    SendPlayerAssignments();
    710722}
    711723
     724void CNetServerWorker::KickPlayer(const CStrW& playerName, bool ban)
     725{
     726    if (ban)
     727    {
     728        // Add playername to blacklist
     729        if (std::find(m_BannedPlayers.begin(), m_BannedPlayers.end(), playerName) == m_BannedPlayers.end())
     730            m_BannedPlayers.push_back(playerName);
     731
     732        // Add IP address to blacklist
     733        std::string ipAddress = GetPlayerIPAddress(playerName);
     734        if (std::find(m_BannedIPs.begin(), m_BannedIPs.end(), ipAddress) == m_BannedIPs.end())
     735            m_BannedIPs.push_back(ipAddress);
     736    }
     737
     738    // Disconnect everyone with that nick except the host
     739    for (auto session : m_Sessions)
     740    {
     741        if (session->GetUserName() == playerName && session->GetGUID() != m_HostGUID)
     742            session->Disconnect(ban ? NDR_BANNED : NDR_KICKED);
     743    }
     744}
     745
     746std::string CNetServerWorker::GetPlayerIPAddress(const CStrW& playerName)
     747{
     748    std::string ipAddress = "error";
     749    for (auto session : m_Sessions)
     750    {
     751        if (session->GetUserName() == playerName)
     752            return session->GetIPAddress();
     753    }
     754    return ipAddress;
     755}
     756
     757std::string CNetServerWorker::GetHostGUID()
     758{
     759    return m_HostGUID;
     760}
     761
    712762void CNetServerWorker::AssignPlayer(int playerID, const CStr& guid)
    713763{
    714764    // Remove anyone who's already assigned to this player
    715765    for (PlayerAssignmentMap::iterator it = m_PlayerAssignments.begin(); it != m_PlayerAssignments.end(); ++it)
    716766    {
     
    764814    ENSURE(event->GetType() == (uint)NMT_CLIENT_HANDSHAKE);
    765815
    766816    CNetServerSession* session = (CNetServerSession*)context;
    767817    CNetServerWorker& server = session->GetServer();
    768818
     819    // Check protocol version
    769820    CCliHandshakeMessage* message = (CCliHandshakeMessage*)event->GetParamRef();
    770821    if (message->m_ProtocolVersion != PS_PROTOCOL_VERSION)
    771822    {
    772823        session->Disconnect(NDR_INCORRECT_PROTOCOL_VERSION);
    773824        return false;
    774825    }
    775826
     827    // Send handshake response
    776828    CSrvHandshakeResponseMessage handshakeResponse;
    777829    handshakeResponse.m_UseProtocolVersion = PS_PROTOCOL_VERSION;
    778830    handshakeResponse.m_Message = server.m_WelcomeMessage;
    779831    handshakeResponse.m_Flags = 0;
    780832    session->SendMessage(&handshakeResponse);
     
    791843
    792844    CAuthenticateMessage* message = (CAuthenticateMessage*)event->GetParamRef();
    793845
    794846    CStrW username = server.DeduplicatePlayerName(SanitisePlayerName(message->m_Name));
    795847
     848    // Disconnect banned usernames
     849    if(std::find(server.m_BannedPlayers.begin(), server.m_BannedPlayers.end(), username) != server.m_BannedPlayers.end())
     850    {
     851        session->Disconnect(NDR_BANNED);
     852        return true;
     853    }
     854
    796855    bool isRejoining = false;
    797856
    798857    if (server.m_State != SERVER_STATE_PREGAME)
    799858    {
    800859//      isRejoining = true; // uncomment this to test rejoining even if the player wasn't connected previously
     
    11451204{
    11461205    CScopeLock lock(m_Worker->m_WorkerMutex);
    11471206    m_Worker->m_PlayerReadyQueue.push_back(std::make_pair(guid, ready));
    11481207}
    11491208
     1209void CNetServer::KickPlayer(const CStrW& playerName, bool ban)
     1210{
     1211    CScopeLock lock(m_Worker->m_WorkerMutex);
     1212    m_Worker->KickPlayer(playerName, ban);
     1213}
     1214
     1215std::string CNetServer::GetHostGUID()
     1216{
     1217    CScopeLock lock(m_Worker->m_WorkerMutex);
     1218    return m_Worker->GetHostGUID();
     1219}
     1220
    11501221void CNetServer::ClearAllPlayerReady()
    11511222{
    11521223    CScopeLock lock(m_Worker->m_WorkerMutex);
    11531224    m_Worker->m_PlayerResetReadyQueue.push_back(false);
    11541225}
  • source/network/NetServer.h

     
    134134     * The changes will be asynchronously propagated to all clients.
    135135     */
    136136    void ClearAllPlayerReady();
    137137   
    138138    /**
     139     * Disconnects a player from the gamesetup / session.
     140     */
     141    void KickPlayer(const CStrW& playerName, bool ban);
     142
     143    /**
     144     * Returns the GUID of the host.
     145     */
     146    std::string GetHostGUID();
     147
     148    /**
    139149     * Call from the GUI to asynchronously notify all clients that they should start loading the game.
    140150     */
    141151    void StartGame();
    142152
    143153    /**
     
    181191     * Send a message to the given network peer.
    182192     */
    183193    bool SendMessage(ENetPeer* peer, const CNetMessage* message);
    184194
    185195    /**
     196     * Disconnected a player from the match / gamesetup and optionally prevents him/her from rejoining.
     197     */
     198    void KickPlayer(const CStrW& playerName, bool ban);
     199
     200    /**
    186201     * Send a message to all clients who have completed the full connection process
    187202     * (i.e. are in the pre-game or in-game states).
    188203     */
    189204    bool Broadcast(const CNetMessage* message);
    190205
     206    /**
     207     * Returns the IP address of the given connected player.
     208     */
     209    std::string GetPlayerIPAddress(const CStrW& playerName);
     210
    191211private:
    192212    friend class CNetServer;
    193213    friend class CNetFileReceiveTask_ServerRejoin;
    194214
    195215    CNetServerWorker(int autostartPlayers);
     
    244264    void SetTurnLength(u32 msecs);
    245265
    246266    void AddPlayer(const CStr& guid, const CStrW& name);
    247267    void RemovePlayer(const CStr& guid);
    248268    void SetPlayerReady(const CStr& guid, const int ready);
     269    std::string GetHostGUID();
    249270    void SendPlayerAssignments();
    250271    void ClearAllPlayerReady();
    251272
    252273    void SetupSession(CNetServerSession* session);
    253274    bool HandleConnect(CNetServerSession* session);
     
    269290
    270291    void ConstructPlayerAssignmentMessage(CPlayerAssignmentMessage& message);
    271292
    272293    void HandleMessageReceive(const CNetMessage* message, CNetServerSession* session);
    273294
    274 
    275295    /**
    276296     * Internal script context for (de)serializing script messages,
    277297     * and for storing game attributes.
    278298     * (TODO: we shouldn't bother deserializing (except for debug printing of messages),
    279299     * we should just forward messages blindly and efficiently.)
     
    285305    /**
    286306     * Stores the most current game attributes.
    287307     */
    288308    DefPersistentRooted<JS::Value> m_GameAttributes;
    289309
     310    std::vector<std::string> m_BannedIPs;
     311    std::vector<std::wstring> m_BannedPlayers;
     312
    290313    int m_AutostartPlayers;
    291314
    292315    ENetHost* m_Host;
    293316    std::vector<CNetServerSession*> m_Sessions;
    294317
     
    301324
    302325    u32 m_NextHostID;
    303326
    304327    CNetServerTurnManager* m_ServerTurnManager;
    305328
     329    std::string m_HostGUID;
     330
    306331    /**
    307332     * A copy of all simulation commands received so far, indexed by
    308333     * turn number, to simplify support for rejoining etc.
    309334     * TODO: verify this doesn't use too much RAM.
    310335     */
  • source/network/NetSession.cpp

     
    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
     
    173173CNetServerSession::CNetServerSession(CNetServerWorker& server, ENetPeer* peer) :
    174174    m_Server(server), m_FileTransferer(this), m_Peer(peer)
    175175{
    176176}
    177177
     178std::string CNetServerSession::GetIPAddress()
     179{
     180    char ipAddress[256] = "(error)";
     181    enet_address_get_host_ip(&(m_Peer->address), ipAddress, ARRAY_SIZE(ipAddress));
     182    return std::string(ipAddress);
     183}
     184
    178185void CNetServerSession::Disconnect(u32 reason)
    179186{
    180187    Update((uint)NMT_CONNECTION_LOST, NULL);
    181188
    182189    enet_peer_disconnect(m_Peer, reason);
  • source/network/NetSession.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
     
    121121
    122122    u32 GetHostID() const { return m_HostID; }
    123123    void SetHostID(u32 id) { m_HostID = id; }
    124124
    125125    /**
     126     * Returns the IP address of the client.
     127     */
     128    std::string GetIPAddress();
     129
     130    /**
    126131     * Sends a disconnection notification to the client,
    127132     * and sends a NMT_CONNECTION_LOST message to the session FSM.
    128133     * The server will receive a disconnection notification after a while.
    129134     * The server will not receive any further messages sent via this session.
    130135     */
  • source/ps/GameSetup/GameSetup.cpp

     
    680680}
    681681
    682682
    683683void EndGame()
    684684{
     685    //TODO: The server should send a message telling the clients that the host quit on purpose
    685686    SAFE_DELETE(g_NetClient);
    686687    SAFE_DELETE(g_NetServer);
    687688    SAFE_DELETE(g_Game);
    688689
    689690    ISoundManager::CloseGame();