forked from 0ad/0ad
Allow kicking/banning players from gamesetup and session. Patch by elexis. Fixes #3241.
This was SVN commit r17217.
This commit is contained in:
parent
d3ff090ce7
commit
32da740f14
@ -1,3 +1,9 @@
|
||||
/**
|
||||
* Get a human readable version of the given disconnect reason.
|
||||
*
|
||||
* @param reason {number}
|
||||
* @returns {string}
|
||||
*/
|
||||
function getDisconnectReason(id)
|
||||
{
|
||||
// Must be kept in sync with source/network/NetHost.h
|
||||
@ -8,15 +14,76 @@ function getDisconnectReason(id)
|
||||
case 2: return translate("Incorrect network protocol version");
|
||||
case 3: return translate("Game is loading, please try later");
|
||||
case 4: return translate("Game has already started, no observers allowed");
|
||||
case 5: return translate("You have been kicked");
|
||||
case 6: return translate("You have been banned");
|
||||
default: return sprintf(translate("\\[Invalid value %(id)s]"), { "id": id });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the disconnect reason in a message box.
|
||||
*
|
||||
* @param {number} reason
|
||||
*/
|
||||
function reportDisconnect(reason)
|
||||
{
|
||||
var reasontext = getDisconnectReason(reason);
|
||||
|
||||
messageBox(400, 200,
|
||||
translate("Lost connection to the server.") + "\n\n" + sprintf(translate("Reason: %(reason)s."), { reason: reasontext }),
|
||||
translate("Disconnected"), 2);
|
||||
// Translation: States the reason why the client disconnected from the server.
|
||||
var reasonText = sprintf(translate("Reason: %(reason)s."), { "reason": getDisconnectReason(reason) })
|
||||
messageBox(400, 200, translate("Lost connection to the server.") + "\n\n" + reasonText, translate("Disconnected"), 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get usernames sorted by player slot, observers last.
|
||||
* Requires g_PlayerAssignments.
|
||||
*
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function getUsernameList()
|
||||
{
|
||||
return Object.keys(g_PlayerAssignments).sort((guidA, guidB) => {
|
||||
|
||||
var playerIdA = g_PlayerAssignments[guidA].player;
|
||||
var playerIdB = g_PlayerAssignments[guidB].player;
|
||||
|
||||
// Sort observers last
|
||||
if (playerIdA == -1) return +1;
|
||||
if (playerIdB == -1) return -1;
|
||||
|
||||
// Sort players
|
||||
return playerIdA - playerIdB;
|
||||
|
||||
}).map(guid => g_PlayerAssignments[guid].name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a command locally. Requires addChatMessage.
|
||||
*
|
||||
* @param {string} input
|
||||
* @returns {Boolean} whether a command was executed
|
||||
*/
|
||||
function executeNetworkCommand(input)
|
||||
{
|
||||
if (input.indexOf("/") != 0)
|
||||
return false;
|
||||
|
||||
var command = input.split(" ", 1)[0];
|
||||
var argument = input.substr(command.length + 1);
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case "/list":
|
||||
addChatMessage({ "type": "clientlist", "guid": "local" });
|
||||
return true;
|
||||
|
||||
case "/kick":
|
||||
if (!Engine.KickPlayer(argument, false))
|
||||
addChatMessage({ "type": "system", "text": sprintf(translate("Could not kick %(name)s."), { "name": argument }) });
|
||||
return true;
|
||||
|
||||
case "/ban":
|
||||
if (!Engine.KickPlayer(argument, true))
|
||||
addChatMessage({ "type": "system", "text": sprintf(translate("Could not ban %(name)s."), { "name": argument }) });
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -508,6 +508,14 @@ function handleNetMessage(message)
|
||||
addChatMessage({ "type": "message", "guid": message.guid, "text": message.text });
|
||||
break;
|
||||
|
||||
case "kicked":
|
||||
addChatMessage({ "type": "system", "text": sprintf(translate("%(username)s has been kicked"), { "username": message.username })});
|
||||
break;
|
||||
|
||||
case "banned":
|
||||
addChatMessage({ "type": "system", "text": sprintf(translate("%(username)s has been banned"), { "username": message.username })});
|
||||
break;
|
||||
|
||||
// Singular client to host message
|
||||
case "ready":
|
||||
g_ReadyChanged -= 1;
|
||||
@ -1776,8 +1784,12 @@ function submitChatInput()
|
||||
if (!text.length)
|
||||
return;
|
||||
|
||||
Engine.SendNetworkChat(text);
|
||||
input.caption = "";
|
||||
|
||||
if (executeNetworkCommand(text))
|
||||
return;
|
||||
|
||||
Engine.SendNetworkChat(text);
|
||||
}
|
||||
|
||||
function addChatMessage(msg)
|
||||
@ -1812,6 +1824,14 @@ function addChatMessage(msg)
|
||||
formatted = '[font="sans-bold-13"] ' + sprintf(translate("== %(message)s"), { "message": sprintf(translate("%(username)s has left"), { "username": formattedUsername }) }) + '[/font]';
|
||||
break;
|
||||
|
||||
case "clientlist":
|
||||
formatted = sprintf(translate("Users: %(users)s"), { "users": getUsernameList().join(translate(", ")) });
|
||||
break;
|
||||
|
||||
case "system":
|
||||
formatted = '[font="sans-bold-13"] ' + sprintf(translate("== %(message)s"), { "message": msg.text }) + '[/font]';
|
||||
break;
|
||||
|
||||
case "message":
|
||||
var formattedUsername = '[color="'+ color +'"]' + username + '[/color]';
|
||||
var formattedUsernamePrefix = '[font="sans-bold-13"]' + sprintf(translate("<%(username)s>"), { "username": formattedUsername }) + '[/font]';
|
||||
|
@ -269,7 +269,9 @@ function handleNetMessage(message)
|
||||
break;
|
||||
case "disconnected":
|
||||
g_Disconnected = true;
|
||||
obj.caption = translate("Connection to the server has been lost.") + "\n\n" + translate("The game has ended.");
|
||||
// Translation: States the reason why the client disconnected from the server.
|
||||
let reason = sprintf(translate("Reason: %(reason)s."), { "reason": getDisconnectReason(message.reason) });
|
||||
obj.caption = translate("Connection to the server has been lost.") + "\n" + reason + "\n" + translate("The game has ended.");
|
||||
obj.hidden = false;
|
||||
break;
|
||||
default:
|
||||
@ -325,6 +327,14 @@ function handleNetMessage(message)
|
||||
addChatMessage({ "type": "rejoined", "guid": message.guid });
|
||||
break;
|
||||
|
||||
case "kicked":
|
||||
addChatMessage({ "type": "system", "text": sprintf(translate("%(username)s has been kicked"), { "username": message.username })});
|
||||
break;
|
||||
|
||||
case "banned":
|
||||
addChatMessage({ "type": "system", "text": sprintf(translate("%(username)s has been banned"), { "username": message.username })});
|
||||
break;
|
||||
|
||||
// To prevent errors, ignore these message types that occur during autostart
|
||||
case "gamesetup":
|
||||
case "start":
|
||||
@ -359,6 +369,9 @@ function submitChatInput()
|
||||
if (!text.length)
|
||||
return;
|
||||
|
||||
if (executeNetworkCommand(text))
|
||||
return;
|
||||
|
||||
if (executeCheat(text))
|
||||
return;
|
||||
|
||||
@ -420,6 +433,12 @@ function addChatMessage(msg)
|
||||
case "rejoined":
|
||||
formatted = sprintf(translate("%(player)s has rejoined the game."), { "player": "[color=\"" + playerColor + "\"]" + username + "[/color]" });
|
||||
break;
|
||||
case "clientlist":
|
||||
formatted = sprintf(translate("Users: %(users)s"), { "users": getUsernameList().join(translate(", ")) });
|
||||
break;
|
||||
case "system":
|
||||
formatted = msg.text;
|
||||
break;
|
||||
case "defeat":
|
||||
// In singleplayer, the local player is "You". "You has" is incorrect.
|
||||
if (!g_IsNetworked && msg.player == Engine.GetPlayerID())
|
||||
|
@ -8,6 +8,7 @@
|
||||
<script file="gui/common/functions_utility.js"/>
|
||||
<script file="gui/common/l10n.js"/>
|
||||
<script file="gui/common/music.js"/>
|
||||
<script file="gui/common/network.js"/>
|
||||
<script file="gui/common/settings.js"/>
|
||||
<script file="gui/common/timer.js"/>
|
||||
<script file="gui/common/tooltips.js"/>
|
||||
|
@ -353,6 +353,14 @@ void DisconnectNetworkGame(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
|
||||
SAFE_DELETE(g_Game);
|
||||
}
|
||||
|
||||
bool KickPlayer(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), CStrW playerName, bool ban)
|
||||
{
|
||||
if (!g_NetServer)
|
||||
return false;
|
||||
|
||||
return g_NetServer->KickPlayer(playerName, ban);
|
||||
}
|
||||
|
||||
JS::Value PollNetworkClient(ScriptInterface::CxPrivate* pCxPrivate)
|
||||
{
|
||||
if (!g_NetClient)
|
||||
@ -963,6 +971,7 @@ void GuiScriptingInit(ScriptInterface& scriptInterface)
|
||||
scriptInterface.RegisterFunction<void, std::wstring, &StartNetworkHost>("StartNetworkHost");
|
||||
scriptInterface.RegisterFunction<void, std::wstring, std::string, &StartNetworkJoin>("StartNetworkJoin");
|
||||
scriptInterface.RegisterFunction<void, &DisconnectNetworkGame>("DisconnectNetworkGame");
|
||||
scriptInterface.RegisterFunction<bool, CStrW, bool, &KickPlayer>("KickPlayer");
|
||||
scriptInterface.RegisterFunction<JS::Value, &PollNetworkClient>("PollNetworkClient");
|
||||
scriptInterface.RegisterFunction<void, JS::HandleValue, &SetNetworkGameAttributes>("SetNetworkGameAttributes");
|
||||
scriptInterface.RegisterFunction<void, int, std::string, &AssignNetworkPlayer>("AssignNetworkPlayer");
|
||||
|
@ -93,6 +93,7 @@ CNetClient::CNetClient(CGame* game) :
|
||||
AddTransition(NCS_PREGAME, (uint)NMT_READY, NCS_PREGAME, (void*)&OnReady, context);
|
||||
AddTransition(NCS_PREGAME, (uint)NMT_GAME_SETUP, NCS_PREGAME, (void*)&OnGameSetup, context);
|
||||
AddTransition(NCS_PREGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_PREGAME, (void*)&OnPlayerAssignment, context);
|
||||
AddTransition(NCS_PREGAME, (uint)NMT_KICKED, NCS_PREGAME, (void*)&OnKicked, context);
|
||||
AddTransition(NCS_PREGAME, (uint)NMT_GAME_START, NCS_LOADING, (void*)&OnGameStart, context);
|
||||
AddTransition(NCS_PREGAME, (uint)NMT_JOIN_SYNC_START, NCS_JOIN_SYNCING, (void*)&OnJoinSyncStart, context);
|
||||
|
||||
@ -110,6 +111,7 @@ CNetClient::CNetClient(CGame* game) :
|
||||
AddTransition(NCS_LOADING, (uint)NMT_LOADED_GAME, NCS_INGAME, (void*)&OnLoadedGame, context);
|
||||
|
||||
AddTransition(NCS_INGAME, (uint)NMT_REJOINED, NCS_INGAME, (void*)&OnRejoined, context);
|
||||
AddTransition(NCS_INGAME, (uint)NMT_KICKED, NCS_INGAME, (void*)&OnKicked, context);
|
||||
AddTransition(NCS_INGAME, (uint)NMT_CHAT, NCS_INGAME, (void*)&OnChat, context);
|
||||
AddTransition(NCS_INGAME, (uint)NMT_GAME_SETUP, NCS_INGAME, (void*)&OnGameSetup, context);
|
||||
AddTransition(NCS_INGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_INGAME, (void*)&OnPlayerAssignment, context);
|
||||
@ -607,6 +609,24 @@ bool CNetClient::OnRejoined(void *context, CFsmEvent* event)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CNetClient::OnKicked(void *context, CFsmEvent* event)
|
||||
{
|
||||
ENSURE(event->GetType() == (uint)NMT_KICKED);
|
||||
|
||||
CNetClient* client = (CNetClient*)context;
|
||||
JSContext* cx = client->GetScriptInterface().GetContext();
|
||||
|
||||
CKickedMessage* message = (CKickedMessage*)event->GetParamRef();
|
||||
JS::RootedValue msg(cx);
|
||||
|
||||
client->GetScriptInterface().Eval("({})", &msg);
|
||||
client->GetScriptInterface().SetProperty(msg, "username", message->m_Name);
|
||||
client->GetScriptInterface().SetProperty(msg, "type", message->m_Ban ? std::string("banned") : std::string("kicked"));
|
||||
client->PushGuiMessage(msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CNetClient::OnLoadedGame(void* context, CFsmEvent* event)
|
||||
{
|
||||
ENSURE(event->GetType() == (uint)NMT_LOADED_GAME);
|
||||
|
@ -201,6 +201,7 @@ private:
|
||||
static bool OnJoinSyncStart(void* context, CFsmEvent* event);
|
||||
static bool OnJoinSyncEndCommandBatch(void* context, CFsmEvent* event);
|
||||
static bool OnRejoined(void* context, CFsmEvent* event);
|
||||
static bool OnKicked(void* context, CFsmEvent* event);
|
||||
static bool OnLoadedGame(void* context, CFsmEvent* event);
|
||||
|
||||
/**
|
||||
|
@ -63,7 +63,9 @@ enum NetDisconnectReason
|
||||
NDR_UNEXPECTED_SHUTDOWN,
|
||||
NDR_INCORRECT_PROTOCOL_VERSION,
|
||||
NDR_SERVER_LOADING,
|
||||
NDR_SERVER_ALREADY_IN_GAME
|
||||
NDR_SERVER_ALREADY_IN_GAME,
|
||||
NDR_KICKED,
|
||||
NDR_BANNED
|
||||
};
|
||||
|
||||
class CNetHost
|
||||
|
@ -135,6 +135,10 @@ CNetMessage* CNetMessageFactory::CreateMessage(const void* pData,
|
||||
pNewMessage = new CRejoinedMessage;
|
||||
break;
|
||||
|
||||
case NMT_KICKED:
|
||||
pNewMessage = new CKickedMessage;
|
||||
break;
|
||||
|
||||
case NMT_LOADED_GAME:
|
||||
pNewMessage = new CLoadedGameMessage;
|
||||
break;
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
#define PS_PROTOCOL_MAGIC 0x5073013f // 'P', 's', 0x01, '?'
|
||||
#define PS_PROTOCOL_MAGIC_RESPONSE 0x50630121 // 'P', 'c', 0x01, '!'
|
||||
#define PS_PROTOCOL_VERSION 0x01010007 // Arbitrary protocol
|
||||
#define PS_PROTOCOL_VERSION 0x01010008 // Arbitrary protocol
|
||||
#define PS_DEFAULT_PORT 0x5073 // 'P', 's'
|
||||
|
||||
// Defines the list of message types. The order of the list must not change.
|
||||
@ -58,6 +58,7 @@ enum NetMessageType
|
||||
NMT_JOIN_SYNC_START,
|
||||
|
||||
NMT_REJOINED,
|
||||
NMT_KICKED,
|
||||
|
||||
NMT_LOADED_GAME,
|
||||
NMT_GAME_START,
|
||||
@ -161,6 +162,11 @@ START_NMT_CLASS_(Rejoined, NMT_REJOINED)
|
||||
NMT_FIELD(CStr8, m_GUID)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(Kicked, NMT_KICKED)
|
||||
NMT_FIELD(CStrW, m_Name)
|
||||
NMT_FIELD_INT(m_Ban, u8, 1)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(LoadedGame, NMT_LOADED_GAME)
|
||||
NMT_FIELD_INT(m_CurrentTurn, u32, 4)
|
||||
END_NMT_CLASS()
|
||||
|
@ -121,7 +121,7 @@ CNetServerWorker::CNetServerWorker(int autostartPlayers) :
|
||||
m_AutostartPlayers(autostartPlayers),
|
||||
m_Shutdown(false),
|
||||
m_ScriptInterface(NULL),
|
||||
m_NextHostID(1), m_Host(NULL), m_Stats(NULL)
|
||||
m_NextHostID(1), m_Host(NULL), m_HostGUID(), m_Stats(NULL)
|
||||
{
|
||||
m_State = SERVER_STATE_UNCONNECTED;
|
||||
|
||||
@ -610,6 +610,12 @@ void CNetServerWorker::SetupSession(CNetServerSession* session)
|
||||
|
||||
bool CNetServerWorker::HandleConnect(CNetServerSession* session)
|
||||
{
|
||||
if (std::find(m_BannedIPs.begin(), m_BannedIPs.end(), session->GetIPAddress()) != m_BannedIPs.end())
|
||||
{
|
||||
session->Disconnect(NDR_BANNED);
|
||||
return false;
|
||||
}
|
||||
|
||||
CSrvHandshakeMessage handshake;
|
||||
handshake.m_Magic = PS_PROTOCOL_MAGIC;
|
||||
handshake.m_ProtocolVersion = PS_PROTOCOL_VERSION;
|
||||
@ -621,6 +627,10 @@ void CNetServerWorker::OnUserJoin(CNetServerSession* session)
|
||||
{
|
||||
AddPlayer(session->GetGUID(), session->GetUserName());
|
||||
|
||||
// Host is the first to join
|
||||
if (m_HostGUID.empty())
|
||||
m_HostGUID = session->GetGUID();
|
||||
|
||||
CGameSetupMessage gameSetupMessage(GetScriptInterface());
|
||||
gameSetupMessage.m_Data = m_GameAttributes.get();
|
||||
session->SendMessage(&gameSetupMessage);
|
||||
@ -713,6 +723,40 @@ void CNetServerWorker::ClearAllPlayerReady()
|
||||
SendPlayerAssignments();
|
||||
}
|
||||
|
||||
bool CNetServerWorker::KickPlayer(const CStrW& playerName, const bool ban)
|
||||
{
|
||||
// Find the user with that name
|
||||
std::vector<CNetServerSession*>::iterator it = std::find_if(m_Sessions.begin(), m_Sessions.end(),
|
||||
[&](CNetServerSession* session) { return session->GetUserName() == playerName; });
|
||||
|
||||
// and return if no one or the host has that name
|
||||
if (it == m_Sessions.end() || (*it)->GetGUID() == m_HostGUID)
|
||||
return false;
|
||||
|
||||
if (ban)
|
||||
{
|
||||
// Remember name
|
||||
if (std::find(m_BannedPlayers.begin(), m_BannedPlayers.end(), playerName) == m_BannedPlayers.end())
|
||||
m_BannedPlayers.push_back(playerName);
|
||||
|
||||
// Remember IP address
|
||||
CStr ipAddress = (*it)->GetIPAddress();
|
||||
if (!ipAddress.empty() && std::find(m_BannedIPs.begin(), m_BannedIPs.end(), ipAddress) == m_BannedIPs.end())
|
||||
m_BannedIPs.push_back(ipAddress);
|
||||
}
|
||||
|
||||
// Disconnect that user
|
||||
(*it)->Disconnect(ban ? NDR_BANNED : NDR_KICKED);
|
||||
|
||||
// Send message notifying other clients
|
||||
CKickedMessage kickedMessage;
|
||||
kickedMessage.m_Name = playerName;
|
||||
kickedMessage.m_Ban = ban;
|
||||
Broadcast(&kickedMessage);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CNetServerWorker::AssignPlayer(int playerID, const CStr& guid)
|
||||
{
|
||||
// Remove anyone who's already assigned to this player
|
||||
@ -804,6 +848,13 @@ bool CNetServerWorker::OnAuthenticate(void* context, CFsmEvent* event)
|
||||
CAuthenticateMessage* message = (CAuthenticateMessage*)event->GetParamRef();
|
||||
CStrW username = server.DeduplicatePlayerName(SanitisePlayerName(message->m_Name));
|
||||
|
||||
// Disconnect banned usernames
|
||||
if (std::find(server.m_BannedPlayers.begin(), server.m_BannedPlayers.end(), username) != server.m_BannedPlayers.end())
|
||||
{
|
||||
session->Disconnect(NDR_BANNED);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Optionally allow observers to join after the game has started
|
||||
bool observerLateJoin = false;
|
||||
ScriptInterface& scriptInterface = server.GetScriptInterface();
|
||||
@ -1168,6 +1219,12 @@ bool CNetServer::SetupConnection()
|
||||
return m_Worker->SetupConnection();
|
||||
}
|
||||
|
||||
bool CNetServer::KickPlayer(const CStrW& playerName, const bool ban)
|
||||
{
|
||||
CScopeLock lock(m_Worker->m_WorkerMutex);
|
||||
return m_Worker->KickPlayer(playerName, ban);
|
||||
}
|
||||
|
||||
void CNetServer::AssignPlayer(int playerID, const CStr& guid)
|
||||
{
|
||||
CScopeLock lock(m_Worker->m_WorkerMutex);
|
||||
|
@ -134,7 +134,12 @@ public:
|
||||
* The changes will be asynchronously propagated to all clients.
|
||||
*/
|
||||
void ClearAllPlayerReady();
|
||||
|
||||
|
||||
/**
|
||||
* Disconnects a player from gamesetup or session.
|
||||
*/
|
||||
bool KickPlayer(const CStrW& playerName, const bool ban);
|
||||
|
||||
/**
|
||||
* Call from the GUI to asynchronously notify all clients that they should start loading the game.
|
||||
*/
|
||||
@ -182,6 +187,11 @@ public:
|
||||
*/
|
||||
bool SendMessage(ENetPeer* peer, const CNetMessage* message);
|
||||
|
||||
/**
|
||||
* Disconnects a player from gamesetup or session.
|
||||
*/
|
||||
bool KickPlayer(const CStrW& playerName, const bool ban);
|
||||
|
||||
/**
|
||||
* Send a message to all clients who have completed the full connection process
|
||||
* (i.e. are in the pre-game or in-game states).
|
||||
@ -299,10 +309,15 @@ private:
|
||||
CStrW m_ServerName;
|
||||
CStrW m_WelcomeMessage;
|
||||
|
||||
std::vector<CStr> m_BannedIPs;
|
||||
std::vector<CStrW> m_BannedPlayers;
|
||||
|
||||
u32 m_NextHostID;
|
||||
|
||||
CNetServerTurnManager* m_ServerTurnManager;
|
||||
|
||||
CStr m_HostGUID;
|
||||
|
||||
/**
|
||||
* A copy of all simulation commands received so far, indexed by
|
||||
* turn number, to simplify support for rejoining etc.
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
/* Copyright (C) 2015 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -175,6 +175,15 @@ CNetServerSession::CNetServerSession(CNetServerWorker& server, ENetPeer* peer) :
|
||||
{
|
||||
}
|
||||
|
||||
CStr CNetServerSession::GetIPAddress() const
|
||||
{
|
||||
char ipAddress[256] = "";
|
||||
if (enet_address_get_host_ip(&m_Peer->address, ipAddress, ARRAY_SIZE(ipAddress)) < 0)
|
||||
LOGMESSAGE("Could not get IP address of a client!");
|
||||
|
||||
return ipAddress;
|
||||
}
|
||||
|
||||
void CNetServerSession::Disconnect(u32 reason)
|
||||
{
|
||||
Update((uint)NMT_CONNECTION_LOST, NULL);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
/* Copyright (C) 2015 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -122,6 +122,8 @@ public:
|
||||
u32 GetHostID() const { return m_HostID; }
|
||||
void SetHostID(u32 id) { m_HostID = id; }
|
||||
|
||||
CStr GetIPAddress() const;
|
||||
|
||||
/**
|
||||
* Sends a disconnection notification to the client,
|
||||
* and sends a NMT_CONNECTION_LOST message to the session FSM.
|
||||
|
Loading…
Reference in New Issue
Block a user