Ticket #3241: t3241_kick_v4.3.patch

File t3241_kick_v4.3.patch, 25.6 KB (added by elexis, 9 years ago)

Removed for-each-loop. Removed optional braces. Fixed "if(". CStr instead of std::string. Initialized string in ctor. Fat arrow for sorting. Removed local variable ipAddress. Some empty lines. empty() instead of == "".

  • 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

     
    17001700
    17011701    var message = "";
    17021702    if ("text" in msg && msg.text)
    17031703        message = escapeText(msg.text);
    17041704
     1705    // Kick / ban players
     1706    if ("text" in msg)
     1707    {
     1708        let split = msg.text.split(/\s/);
     1709        let kick = msg.text.indexOf("/kick") == 0;
     1710        let ban = msg.text.indexOf("/ban") == 0;
     1711        let playerGUID = Engine.GetPlayerGUID();
     1712        if (kick || ban)
     1713        {
     1714            if (!g_IsNetworked || !g_IsController || msg.guid != playerGUID)
     1715                return;
     1716            let trimmed = msg.text.substr(split[0].length + 1);
     1717            let matched = "";
     1718
     1719            // Reject names which don't match or are a superset of the intended name.
     1720            for (let guid in g_PlayerAssignments)
     1721            {
     1722                let name = g_PlayerAssignments[guid].name;
     1723                if (trimmed.indexOf(name) == 0 && name.length > matched.length)
     1724                    matched = name;
     1725            }
     1726
     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
    17051739    // TODO: Maybe host should have distinct font/color?
    17061740    var color = "white";
    17071741
    17081742    if (msg.guid && g_PlayerAssignments[msg.guid] && g_PlayerAssignments[msg.guid].player != -1)
    17091743    {
  • 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) + "\n" + translate("The game has ended.");
    247248            obj.hidden = false;
    248249            break;
    249250        default:
    250251            error("Unrecognised netstatus type '" + message.status + "'");
    251252            break;
     
    325326function submitChatInput()
    326327{
    327328    var input = Engine.GetGUIObjectByName("chatInput");
    328329    var text = input.caption;
    329330    var isCheat = false;
     331
    330332    if (text.length)
    331333    {
     334        // Check cheats
    332335        if (!g_IsObserver && g_Players[Engine.GetPlayerID()].cheatsEnabled)
    333336        {
    334337            for each (var cheat in Object.keys(cheats))
    335338            {
    336339                // Line must start with the cheat.
     
    374377                isCheat = true;
    375378                break;
    376379            }
    377380        }
    378381
    379         // Observers should only send messages to "/all"
    380         if (!isCheat && (!g_IsObserver || text.indexOf("/") == -1 || text.indexOf("/all ") == 0))
     382        if (!isCheat)
    381383        {
    382             if (Engine.GetGUIObjectByName("toggleTeamChat").checked)
    383                 text = "/team " + text;
    384 
    385             if (g_IsNetworked)
    386                 Engine.SendNetworkChat(text);
     384            if (text.trim() == "/list")
     385                addChatMessage({ "type": "clientlist", "guid": "local"});
    387386            else
    388                 addChatMessage({ "type": "message", "guid": "local", "text": text });
     387            {
     388                if (Engine.GetGUIObjectByName("toggleTeamChat").checked)
     389                    text = "/team " + text;
     390
     391                if (g_IsNetworked)
     392                    Engine.SendNetworkChat(text);
     393                else
     394                    addChatMessage({ "type": "message", "guid": "local", "text": text });
     395            }
    389396        }
    390397        input.caption = ""; // Clear chat input
    391398    }
    392399
    393400    input.blur(); // Remove focus
     
    453460        if (!g_IsNetworked && msg.player == Engine.GetPlayerID())
    454461            formatted = translate("You have been defeated.");
    455462        else
    456463            formatted = sprintf(translate("%(player)s has been defeated."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
    457464        break;
     465    case "clientlist":
     466        let userlist = Object.keys(playerAssignments).sort((a,b) =>
     467        {
     468            let playerA = playerAssignments[a].player;
     469            let playerB = playerAssignments[b].player;
     470            if (playerA == -1 || playerB == -1)
     471                return 1;
     472            else
     473                return playerA - playerB;
     474        }).map(guid => playerAssignments[guid].name).join(",");
     475        formatted = sprintf(translate("Users: %(users)s."), { "users": userlist });
     476        break;
    458477    case "diplomacy":
    459478        var message;
    460479        if (msg.player == Engine.GetPlayerID())
    461480        {
    462481            [username, playerColor] = getUsernameAndColor(msg.player1);
     
    601620}
    602621
    603622// Parses chat messages for commands.
    604623function parseChatCommands(msg, playerAssignments)
    605624{
     625    let ban = false;
    606626    // Only interested in messages that start with '/'.
    607627    if (!msg.text || msg.text[0] != '/')
    608628        return;
    609629
    610     var sender;
     630    let playerGUID = Engine.GetPlayerGUID();
     631    let sender;
    611632    if (playerAssignments[msg.guid])
    612633        sender = playerAssignments[msg.guid].player;
    613634    else
    614635        sender = msg.player;
    615636
    616637    // TODO: It would be nice to display multiple different contexts.
    617638    // It should be made clear that only players matching the union of those receive the message.
    618639    var recurse = false;
    619640    var split = msg.text.split(/\s/);
    620 
     641    let trimmed, matched;
    621642    // Parse commands embedded in the message.
    622643    switch (split[0])
    623644    {
    624645    case "/all":
    625646        // Resets values that 'team' or 'enemy' may have set.
     
    627648        msg.hide = false;
    628649        recurse = true;
    629650        break;
    630651    case "/team":
    631652        // Check if we are in a team.
    632         if (g_Players[Engine.GetPlayerID()] && g_Players[Engine.GetPlayerID()].team != -1)
     653        if (!g_IsObserver && g_Players[Engine.GetPlayerID()] && g_Players[Engine.GetPlayerID()].team != -1)
    633654        {
    634655            if (g_Players[Engine.GetPlayerID()].team != g_Players[sender].team)
    635656                msg.hide = true;
    636657            else
    637658                msg.context = translate("Team");
     
    641662        recurse = true;
    642663        break;
    643664    case "/ally":
    644665    case "/allies":
    645666        // 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()]))
     667        if (!g_IsObserver && (Engine.GetPlayerID() == sender || (g_Players[sender] && g_Players[sender].isMutualAlly[Engine.GetPlayerID()])))
    647668            msg.context = translate("Ally");
    648669        else
    649670            msg.hide = true;
    650671
    651672        recurse = true;
    652673        break;
    653674    case "/enemy":
    654675    case "/enemies":
    655676        // 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()]))
     677        if (!g_IsObserver && (Engine.GetPlayerID() == sender || (g_Players[sender] && g_Players[sender].isEnemy[Engine.GetPlayerID()])))
    657678            msg.context = translate("Enemy");
    658679        else
    659680            msg.hide = true;
    660681
    661682        recurse = true;
    662683        break;
    663684    case "/me":
    664685        msg.action = true;
    665686        break;
     687    case "/ban":
     688        ban = true; // handle in the "kick" case
     689    case "/kick":
     690        msg.hide = true;
     691        if (!g_IsNetworked || !g_IsController || msg.guid != playerGUID)
     692            break;
     693        trimmed = msg.text.substr(split[0].length + 1);
     694        matched = "";
     695
     696        // Reject names which don't match or are a superset of the intended name.
     697        for (let guid in playerAssignments)
     698        {
     699            let name = playerAssignments[guid].name;
     700            if (trimmed.indexOf(name) == 0 && name.length > matched.length)
     701                matched = name;
     702        }
     703
     704        // Prevent the host from kicking him/herself
     705        if (matched.length && matched != g_PlayerAssignments[playerGUID].name)
     706        {
     707            Engine.KickPlayer(matched, ban);
     708            // TODO: The text should be translated for each client individually (see #3304)
     709            submitChatDirectly(matched + " has been " + (ban ? "banned" : "kicked") + ".");
     710        }
     711        return;
    666712    case "/msg":
    667         var trimmed = msg.text.substr(split[0].length + 1);
    668         var matched = "";
     713        trimmed = msg.text.substr(split[0].length + 1);
     714        matched = "";
     715
     716        // Don't show private messages from observers to players
     717        if (g_PlayerAssignments[msg.guid].player == -1 && g_PlayerAssignments[playerGUID].player != -1)
     718        {
     719            msg.hide = true;
     720            return;
     721        }
    669722
    670723        // Reject names which don't match or are a superset of the intended name.
    671724        for each (var player in playerAssignments)
    672725            if (trimmed.indexOf(player.name + " ") == 0 && player.name.length > matched.length)
    673726                matched = player.name;
    674727
    675728        // 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()))
     729        // Show the message only for sender and recipient.
     730        if (matched.length && (msg.guid == playerGUID || matched == g_PlayerAssignments[playerGUID].name))
    678731        {
    679732            msg.context = translate("Private");
    680733            msg.text = trimmed.substr(matched.length + 1);
    681734            msg.hide = false; // Might override team message hiding.
    682735            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
     191CStr 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), CStrW 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, CStrW, 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<CStr, &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

     
    119119
    120120CNetServerWorker::CNetServerWorker(int autostartPlayers) :
    121121    m_AutostartPlayers(autostartPlayers),
    122122    m_Shutdown(false),
    123123    m_ScriptInterface(NULL),
    124     m_NextHostID(1), m_Host(NULL), m_Stats(NULL)
     124    m_NextHostID(1), m_Host(NULL), m_HostGUID(""), m_Stats(NULL)
    125125{
    126126    m_State = SERVER_STATE_UNCONNECTED;
    127127
    128128    m_ServerTurnManager = NULL;
    129129
     
    604604    session->SetFirstState(NSS_HANDSHAKE);
    605605}
    606606
    607607bool CNetServerWorker::HandleConnect(CNetServerSession* session)
    608608{
     609    CNetServerWorker& server = session->GetServer();
     610
     611    // Disconnect banned IPs
     612    CStr ipAddress = session -> GetIPAddress();
     613    if (std::find(server.m_BannedIPs.begin(), server.m_BannedIPs.end(), ipAddress) != server.m_BannedIPs.end())
     614    {
     615        session->Disconnect(NDR_BANNED);
     616        return false;
     617    }
     618
     619    // Send handshake challenge
    609620    CSrvHandshakeMessage handshake;
    610621    handshake.m_Magic = PS_PROTOCOL_MAGIC;
    611622    handshake.m_ProtocolVersion = PS_PROTOCOL_VERSION;
    612623    handshake.m_SoftwareVersion = PS_PROTOCOL_VERSION;
    613624    return session->SendMessage(&handshake);
     
    615626
    616627void CNetServerWorker::OnUserJoin(CNetServerSession* session)
    617628{
    618629    AddPlayer(session->GetGUID(), session->GetUserName());
    619630
     631    if (m_HostGUID.empty())
     632        m_HostGUID = session->GetGUID();
     633
    620634    CGameSetupMessage gameSetupMessage(GetScriptInterface());
    621635    gameSetupMessage.m_Data = m_GameAttributes.get();
    622636    session->SendMessage(&gameSetupMessage);
    623637
    624638    CPlayerAssignmentMessage assignMessage;
     
    630644{
    631645    RemovePlayer(session->GetGUID());
    632646
    633647    if (m_ServerTurnManager && session->GetCurrState() != NSS_JOIN_SYNCING)
    634648        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?
    638649}
    639650
    640651void CNetServerWorker::AddPlayer(const CStr& guid, const CStrW& name)
    641652{
    642653    // Find all player IDs in active use; we mustn't give them to a second player (excluding the unassigned ID: -1)
     
    707718        it->second.m_Status = 0;
    708719
    709720    SendPlayerAssignments();
    710721}
    711722
     723void CNetServerWorker::KickPlayer(const CStrW& playerName, bool ban)
     724{
     725    if (ban)
     726    {
     727        // Add playername to blacklist
     728        if (std::find(m_BannedPlayers.begin(), m_BannedPlayers.end(), playerName) == m_BannedPlayers.end())
     729            m_BannedPlayers.push_back(playerName);
     730
     731        // Add IP address to blacklist
     732        CStr ipAddress = GetPlayerIPAddress(playerName);
     733        if (std::find(m_BannedIPs.begin(), m_BannedIPs.end(), ipAddress) == m_BannedIPs.end())
     734            m_BannedIPs.push_back(ipAddress);
     735    }
     736
     737    // Disconnect everyone with that nick except the host
     738    for (CNetServerSession* session : m_Sessions)
     739    {
     740        if (session->GetUserName() == playerName && session->GetGUID() != m_HostGUID)
     741            session->Disconnect(ban ? NDR_BANNED : NDR_KICKED);
     742    }
     743}
     744
     745CStr CNetServerWorker::GetPlayerIPAddress(const CStrW& playerName)
     746{
     747    for (CNetServerSession* session : m_Sessions)
     748        if (session->GetUserName() == playerName)
     749            return session->GetIPAddress();
     750    return "(error)";
     751}
     752
     753CStr CNetServerWorker::GetHostGUID()
     754{
     755    return m_HostGUID;
     756}
     757
    712758void CNetServerWorker::AssignPlayer(int playerID, const CStr& guid)
    713759{
    714760    // Remove anyone who's already assigned to this player
    715761    for (PlayerAssignmentMap::iterator it = m_PlayerAssignments.begin(); it != m_PlayerAssignments.end(); ++it)
    716762    {
     
    764810    ENSURE(event->GetType() == (uint)NMT_CLIENT_HANDSHAKE);
    765811
    766812    CNetServerSession* session = (CNetServerSession*)context;
    767813    CNetServerWorker& server = session->GetServer();
    768814
     815    // Check protocol version
    769816    CCliHandshakeMessage* message = (CCliHandshakeMessage*)event->GetParamRef();
    770817    if (message->m_ProtocolVersion != PS_PROTOCOL_VERSION)
    771818    {
    772819        session->Disconnect(NDR_INCORRECT_PROTOCOL_VERSION);
    773820        return false;
    774821    }
    775822
     823    // Send handshake response
    776824    CSrvHandshakeResponseMessage handshakeResponse;
    777825    handshakeResponse.m_UseProtocolVersion = PS_PROTOCOL_VERSION;
    778826    handshakeResponse.m_Message = server.m_WelcomeMessage;
    779827    handshakeResponse.m_Flags = 0;
    780828    session->SendMessage(&handshakeResponse);
     
    791839
    792840    CAuthenticateMessage* message = (CAuthenticateMessage*)event->GetParamRef();
    793841
    794842    CStrW username = server.DeduplicatePlayerName(SanitisePlayerName(message->m_Name));
    795843
     844    // Disconnect banned usernames
     845    if (std::find(server.m_BannedPlayers.begin(), server.m_BannedPlayers.end(), username) != server.m_BannedPlayers.end())
     846    {
     847        session->Disconnect(NDR_BANNED);
     848        return true;
     849    }
     850
    796851    bool isRejoining = false;
    797852
    798853    if (server.m_State != SERVER_STATE_PREGAME)
    799854    {
    800855//      isRejoining = true; // uncomment this to test rejoining even if the player wasn't connected previously
     
    11451200{
    11461201    CScopeLock lock(m_Worker->m_WorkerMutex);
    11471202    m_Worker->m_PlayerReadyQueue.push_back(std::make_pair(guid, ready));
    11481203}
    11491204
     1205void CNetServer::KickPlayer(const CStrW& playerName, bool ban)
     1206{
     1207    CScopeLock lock(m_Worker->m_WorkerMutex);
     1208    m_Worker->KickPlayer(playerName, ban);
     1209}
     1210
     1211CStr CNetServer::GetHostGUID()
     1212{
     1213    CScopeLock lock(m_Worker->m_WorkerMutex);
     1214    return m_Worker->GetHostGUID();
     1215}
     1216
    11501217void CNetServer::ClearAllPlayerReady()
    11511218{
    11521219    CScopeLock lock(m_Worker->m_WorkerMutex);
    11531220    m_Worker->m_PlayerResetReadyQueue.push_back(false);
    11541221}
  • source/network/NetServer.h

     
    120120     * The given GUID will be (re)assigned to the given player ID.
    121121     * Any player currently using that ID will be unassigned.
    122122     * The changes will be asynchronously propagated to all clients.
    123123     */
    124124    void AssignPlayer(int playerID, const CStr& guid);
    125    
     125
    126126    /**
    127127     * Call from the GUI to update the player readiness.
    128128     * The changes will be asynchronously propagated to all clients.
    129129     */
    130130    void SetPlayerReady(const CStr& guid, int ready);
     
    132132    /**
    133133     * Call from the GUI to set the all player readiness to 0.
    134134     * The changes will be asynchronously propagated to all clients.
    135135     */
    136136    void ClearAllPlayerReady();
    137    
     137
     138    /**
     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    CStr GetHostGUID();
     147
    138148    /**
    139149     * Call from the GUI to asynchronously notify all clients that they should start loading the game.
    140150     */
    141151    void StartGame();
    142152
     
    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    CStr 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    CStr 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<CStr> m_BannedIPs;
     311    std::vector<CStrW> 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    CStr 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
     178CStr CNetServerSession::GetIPAddress()
     179{
     180    char ipAddress[256] = "(error)";
     181    enet_address_get_host_ip(&(m_Peer->address), ipAddress, ARRAY_SIZE(ipAddress));
     182    return CStr(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    CStr 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     */