Don't hardcode the "0ad" resource into lobby XMPP & hosting
XMPP JID has a concept of 'resources', which can be used to differentiate multiple clients of the same account. We currently hardcode this 'resource' to '0ad' in two places: - The 0 A.D. client always uses '0ad' - The network code expects a host resource to be '0ad' when connecting. As noted in 0fd8aa2a77#31215, it is less effort to store the JI D directly. This patch does that. It also makes 0 A.D. use a different resource each time. Note that resources ought not contain particular information, as the XMPP server is free to clobber it. I keep '0ad-' here for debug purposes. This allows: - multiple 0 A.D. instances to log on the lobby at the same time (not massively useful, but good for debugging sometimes) - hosting a game with a custom resource, which will potentially make it easier to have dedi cated servers on one account. Note that hosting multiple games on one account is currently not supported and will have weird behaviour on the lobbybots side. They should be upgraded independently of this. Refs #3556 Differential Revision: https://code.wildfiregames.com/D3500 This was SVN commit r25407.
This commit is contained in:
parent
88810524b3
commit
e94faf7827
@ -90,6 +90,7 @@ class LobbyGameRegistrationController
|
||||
let stanza = {
|
||||
"name": this.serverName,
|
||||
"hostUsername": Engine.LobbyGetNick(),
|
||||
"hostJID": "", // Overwritten by C++, placeholder.
|
||||
"mapName": g_GameSettings.map.map,
|
||||
// TODO: if the map name was always up-to-date we wouldn't need the mapcache here.
|
||||
"niceMapName": this.mapCache.getTranslatableMapName(g_GameSettings.map.type, g_GameSettings.map.map),
|
||||
|
@ -112,7 +112,7 @@ function confirmSetup()
|
||||
let joinServer = Engine.GetGUIObjectByName("joinServer").caption;
|
||||
let joinPort = Engine.GetGUIObjectByName("joinPort").caption;
|
||||
|
||||
if (startJoin(joinPlayerName, joinServer, getValidPort(joinPort), false, ""))
|
||||
if (startJoin(joinPlayerName, joinServer, getValidPort(joinPort)))
|
||||
switchSetupPage("pageConnecting");
|
||||
}
|
||||
else if (!Engine.GetGUIObjectByName("pageHost").hidden)
|
||||
@ -365,7 +365,7 @@ function startHost(playername, servername, port, password)
|
||||
|
||||
try
|
||||
{
|
||||
Engine.StartNetworkHost(playername + (g_UserRating ? " (" + g_UserRating + ")" : ""), port, playername, useSTUN, password);
|
||||
Engine.StartNetworkHost(playername + (g_UserRating ? " (" + g_UserRating + ")" : ""), port, useSTUN, password);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
@ -388,13 +388,13 @@ function startHost(playername, servername, port, password)
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects via STUN if the hostJID is given.
|
||||
* Connect via direct IP (used by the 'simple' MP screen)
|
||||
*/
|
||||
function startJoin(playername, ip, port, useSTUN, hostJID)
|
||||
function startJoin(playername, ip, port)
|
||||
{
|
||||
try
|
||||
{
|
||||
Engine.StartNetworkJoin(playername + (g_UserRating ? " (" + g_UserRating + ")" : ""), ip, port, useSTUN, hostJID);
|
||||
Engine.StartNetworkJoin(playername, ip, port);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
@ -409,18 +409,20 @@ function startJoin(playername, ip, port, useSTUN, hostJID)
|
||||
|
||||
startConnectionStatus("client");
|
||||
|
||||
// Future-proofing: there could be an XMPP client even if we join a game directly.
|
||||
if (Engine.HasXmppClient())
|
||||
Engine.LobbySetPlayerPresence("playing");
|
||||
else
|
||||
{
|
||||
// Only save the player name and host address if they're valid and we're not in the lobby
|
||||
Engine.ConfigDB_CreateAndWriteValueToFile("user", "playername.multiplayer", playername, "config/user.cfg");
|
||||
Engine.ConfigDB_CreateAndWriteValueToFile("user", "multiplayerserver", ip, "config/user.cfg");
|
||||
Engine.ConfigDB_CreateAndWriteValueToFile("user", "multiplayerjoining.port", port, "config/user.cfg");
|
||||
}
|
||||
|
||||
// Only save the player name and host address if they're valid.
|
||||
Engine.ConfigDB_CreateAndWriteValueToFile("user", "playername.multiplayer", playername, "config/user.cfg");
|
||||
Engine.ConfigDB_CreateAndWriteValueToFile("user", "multiplayerserver", ip, "config/user.cfg");
|
||||
Engine.ConfigDB_CreateAndWriteValueToFile("user", "multiplayerjoining.port", port, "config/user.cfg");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect via the lobby.
|
||||
*/
|
||||
function startJoinFromLobby(playername, hostJID, password)
|
||||
{
|
||||
if (!Engine.HasXmppClient())
|
||||
|
@ -73,7 +73,7 @@ class JoinButton
|
||||
"name": g_Nickname,
|
||||
"rating": this.getRejoinRating(stanza),
|
||||
"hasPassword": !!stanza.hasPassword,
|
||||
"hostJID": stanza.hostUsername + "@" + Engine.ConfigDB_GetValue("user", "lobby.server") + "/0ad"
|
||||
"hostJID": stanza.hostJID
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -282,6 +282,7 @@ Game.prototype.StanzaKeys = [
|
||||
"name",
|
||||
"hasPassword",
|
||||
"hostUsername",
|
||||
"hostJID",
|
||||
"state",
|
||||
"nbp",
|
||||
"maxnbp",
|
||||
|
@ -98,13 +98,13 @@ class GameList
|
||||
let newGames = {};
|
||||
for (let stanza of gameListData)
|
||||
{
|
||||
let game = this.games[stanza.hostUsername] || undefined;
|
||||
let game = this.games[stanza.hostJID] || undefined;
|
||||
let exists = !!game;
|
||||
if (!exists)
|
||||
game = new Game(this.mapCache);
|
||||
|
||||
game.update(stanza, selectedColumn);
|
||||
newGames[stanza.hostUsername] = game;
|
||||
newGames[stanza.hostJID] = game;
|
||||
}
|
||||
this.games = newGames;
|
||||
Engine.ProfileStop();
|
||||
@ -160,7 +160,7 @@ class GameList
|
||||
this.list_maxnbp[i] = displayData.playerCount;
|
||||
this.list_gameRating[i] = game.gameRating;
|
||||
this.list[i] = "";
|
||||
if (selectedGame && game.stanza.hostUsername == selectedGame.stanza.hostUsername && game.stanza.name == selectedGame.stanza.name)
|
||||
if (selectedGame && game.stanza.hostJID == selectedGame.stanza.hostJID && game.stanza.name == selectedGame.stanza.name)
|
||||
selectedGameIndex = i;
|
||||
});
|
||||
Engine.ProfileStop();
|
||||
|
@ -44,7 +44,8 @@ public:
|
||||
virtual void SendIqChangeStateGame(const std::string& nbp, const std::string& players) = 0;
|
||||
virtual void SendIqLobbyAuth(const std::string& to, const std::string& token) = 0;
|
||||
virtual void SetNick(const std::string& nick) = 0;
|
||||
virtual std::string GetNick() = 0;
|
||||
virtual std::string GetNick() const = 0;
|
||||
virtual std::string GetJID() const = 0;
|
||||
virtual void kick(const std::string& nick, const std::string& reason) = 0;
|
||||
virtual void ban(const std::string& nick, const std::string& reason) = 0;
|
||||
virtual void SetPresence(const std::string& presence) = 0;
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "network/StunClient.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/ConfigDB.h"
|
||||
#include "ps/GUID.h"
|
||||
#include "ps/Pyrogenesis.h"
|
||||
#include "scriptinterface/ScriptExtraHeaders.h" // StructuredClone
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
@ -109,7 +110,8 @@ XmppClient::XmppClient(const ScriptInterface* scriptInterface, const std::string
|
||||
|
||||
m_xpartamuppId = sXpartamupp + "@" + m_server + "/CC";
|
||||
m_echelonId = sEchelon + "@" + m_server + "/CC";
|
||||
glooxwrapper::JID clientJid(sUsername + "@" + m_server + "/0ad");
|
||||
// Generate a unique, unpredictable resource to allow multiple 0 A.D. instances to connect to the lobby.
|
||||
glooxwrapper::JID clientJid(sUsername + "@" + m_server + "/0ad-" + ps_generate_guid());
|
||||
glooxwrapper::JID roomJid(m_room + "@conference." + m_server + "/" + sNick);
|
||||
|
||||
// If we are connecting, use the full jid and a password
|
||||
@ -425,7 +427,7 @@ void XmppClient::SendIqRegisterGame(const ScriptInterface& scriptInterface, JS::
|
||||
glooxwrapper::JID xpartamuppJid(m_xpartamuppId);
|
||||
|
||||
// Setup some base stanza attributes
|
||||
GameListQuery* g = new GameListQuery();
|
||||
std::unique_ptr<GameListQuery> g = std::make_unique<GameListQuery>();
|
||||
g->m_Command = "register";
|
||||
glooxwrapper::Tag* game = glooxwrapper::Tag::allocate("game");
|
||||
|
||||
@ -434,17 +436,27 @@ void XmppClient::SendIqRegisterGame(const ScriptInterface& scriptInterface, JS::
|
||||
scriptInterface.EnumeratePropertyNames(data, true, properties);
|
||||
for (const std::string& p : properties)
|
||||
{
|
||||
std::wstring value;
|
||||
scriptInterface.GetProperty(data, p.c_str(), value);
|
||||
game->addAttribute(p, utf8_from_wstring(value));
|
||||
std::string value;
|
||||
if (!scriptInterface.GetProperty(data, p.c_str(), value))
|
||||
{
|
||||
LOGERROR("Could not parse attribute '%s' as string.", p);
|
||||
return;
|
||||
}
|
||||
game->addAttribute(p, value);
|
||||
}
|
||||
|
||||
// Overwrite some attributes to make it slightly less trivial to do bad things,
|
||||
// and explicit some invariants.
|
||||
|
||||
// The JID must point to ourself.
|
||||
game->addAttribute("hostJID", GetJID());
|
||||
|
||||
// Push the stanza onto the IQ
|
||||
g->m_GameList.emplace_back(game);
|
||||
|
||||
// Send IQ
|
||||
glooxwrapper::IQ iq(gloox::IQ::Set, xpartamuppJid, m_client->getID());
|
||||
iq.addExtension(g);
|
||||
iq.addExtension(g.release());
|
||||
DbgXMPP("SendIqRegisterGame [" << tag_xml(iq) << "]");
|
||||
m_client->send(iq);
|
||||
}
|
||||
@ -504,7 +516,7 @@ void XmppClient::SendIqLobbyAuth(const std::string& to, const std::string& token
|
||||
LobbyAuth* auth = new LobbyAuth();
|
||||
auth->m_Token = token;
|
||||
|
||||
glooxwrapper::JID clientJid(to + "@" + m_server + "/0ad");
|
||||
glooxwrapper::JID clientJid(to);
|
||||
glooxwrapper::IQ iq(gloox::IQ::Set, clientJid, m_client->getID());
|
||||
iq.addExtension(auth);
|
||||
DbgXMPP("SendIqLobbyAuth [" << tag_xml(iq) << "]");
|
||||
@ -595,7 +607,7 @@ JS::Value XmppClient::GUIGetGameList(const ScriptInterface& scriptInterface)
|
||||
ScriptInterface::CreateArray(rq, &ret);
|
||||
int j = 0;
|
||||
|
||||
const char* stats[] = { "name", "hostUsername", "state", "hasPassword",
|
||||
const char* stats[] = { "name", "hostUsername", "hostJID", "state", "hasPassword",
|
||||
"nbp", "maxnbp", "players", "mapName", "niceMapName", "mapSize", "mapType",
|
||||
"victoryConditions", "startTime", "mods" };
|
||||
|
||||
@ -850,7 +862,7 @@ bool XmppClient::handleIq(const glooxwrapper::IQ& iq)
|
||||
}
|
||||
|
||||
if (!m_connectionDataIqId.empty() && m_connectionDataIqId.compare(iq.id().to_string()) != 0) {
|
||||
LOGWARNING("XmppClient: Received connection data with invalid id");
|
||||
LOGMESSAGE("XmppClient: Received connection data with invalid id");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -943,7 +955,7 @@ bool XmppClient::handleIq(const glooxwrapper::IQ& iq)
|
||||
if (g_NetServer)
|
||||
g_NetServer->OnLobbyAuth(iq.from().username(), lobbyAuth->m_Token.to_string());
|
||||
else
|
||||
LOGERROR("Received lobby authentication request, but not hosting currently!");
|
||||
LOGMESSAGE("Received lobby authentication request, but not hosting currently!");
|
||||
}
|
||||
}
|
||||
else if (iq.subtype() == gloox::IQ::Get)
|
||||
@ -1164,11 +1176,16 @@ void XmppClient::SetNick(const std::string& nick)
|
||||
/**
|
||||
* Get current nickname.
|
||||
*/
|
||||
std::string XmppClient::GetNick()
|
||||
std::string XmppClient::GetNick() const
|
||||
{
|
||||
return m_mucRoom->nick().to_string();
|
||||
}
|
||||
|
||||
std::string XmppClient::GetJID() const
|
||||
{
|
||||
return m_client->getJID().to_string();
|
||||
}
|
||||
|
||||
/**
|
||||
* Kick a player from the current room.
|
||||
*
|
||||
|
@ -91,7 +91,8 @@ public:
|
||||
void SendIqChangeStateGame(const std::string& nbp, const std::string& players);
|
||||
void SendIqLobbyAuth(const std::string& to, const std::string& token);
|
||||
void SetNick(const std::string& nick);
|
||||
std::string GetNick();
|
||||
std::string GetNick() const;
|
||||
std::string GetJID() const;
|
||||
void kick(const std::string& nick, const std::string& reason);
|
||||
void ban(const std::string& nick, const std::string& reason);
|
||||
void SetPresence(const std::string& presence);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -354,6 +354,11 @@ const glooxwrapper::string glooxwrapper::Client::getID() const
|
||||
return m_Wrapped->getID();
|
||||
}
|
||||
|
||||
const glooxwrapper::string glooxwrapper::Client::getJID() const
|
||||
{
|
||||
return m_Wrapped->jid().full();
|
||||
}
|
||||
|
||||
void glooxwrapper::Client::send(const IQ& iq)
|
||||
{
|
||||
m_Wrapped->send(iq.getWrapped());
|
||||
|
@ -414,6 +414,7 @@ namespace glooxwrapper
|
||||
bool connect(bool block = true);
|
||||
gloox::ConnectionError recv(int timeout = -1);
|
||||
const string getID() const;
|
||||
const string getJID() const;
|
||||
void send(const IQ& iq);
|
||||
|
||||
void setTls(gloox::TLSPolicy tls);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -218,6 +218,7 @@ void RegisterScriptFunctions(const ScriptRequest& rq)
|
||||
REGISTER_XMPP(SetPresence, "LobbySetPlayerPresence");
|
||||
REGISTER_XMPP(SetNick, "LobbySetNick");
|
||||
REGISTER_XMPP(GetNick, "LobbyGetNick");
|
||||
REGISTER_XMPP(GetJID, "LobbyGetJID");
|
||||
REGISTER_XMPP(kick, "LobbyKick");
|
||||
REGISTER_XMPP(ban, "LobbyBan");
|
||||
REGISTER_XMPP(GetPresence, "LobbyGetPlayerPresence");
|
||||
|
@ -176,9 +176,9 @@ void CNetClient::SetUserName(const CStrW& username)
|
||||
m_UserName = username;
|
||||
}
|
||||
|
||||
void CNetClient::SetHostingPlayerName(const CStr& hostingPlayerName)
|
||||
void CNetClient::SetHostJID(const CStr& jid)
|
||||
{
|
||||
m_HostingPlayerName = hostingPlayerName;
|
||||
m_HostJID = jid;
|
||||
}
|
||||
|
||||
void CNetClient::SetGamePassword(const CStr& hashedPassword)
|
||||
@ -632,8 +632,8 @@ bool CNetClient::OnHandshakeResponse(void* context, CFsmEvent* event)
|
||||
|
||||
if (message->m_Flags & PS_NETWORK_FLAG_REQUIRE_LOBBYAUTH)
|
||||
{
|
||||
if (g_XmppClient && !client->m_HostingPlayerName.empty())
|
||||
g_XmppClient->SendIqLobbyAuth(client->m_HostingPlayerName, client->m_GUID);
|
||||
if (g_XmppClient && !client->m_HostJID.empty())
|
||||
g_XmppClient->SendIqLobbyAuth(client->m_HostJID, client->m_GUID);
|
||||
else
|
||||
{
|
||||
client->PushGuiMessage(
|
||||
|
@ -92,10 +92,10 @@ public:
|
||||
void SetUserName(const CStrW& username);
|
||||
|
||||
/**
|
||||
* Set the name of the hosting player.
|
||||
* Store the JID of the host.
|
||||
* This is needed for the secure lobby authentication.
|
||||
*/
|
||||
void SetHostingPlayerName(const CStr& hostingPlayerName);
|
||||
void SetHostJID(const CStr& jid);
|
||||
|
||||
void SetControllerSecret(const std::string& secret);
|
||||
|
||||
@ -295,7 +295,8 @@ private:
|
||||
|
||||
CGame *m_Game;
|
||||
CStrW m_UserName;
|
||||
CStr m_HostingPlayerName;
|
||||
|
||||
CStr m_HostJID;
|
||||
CStr m_ServerAddress;
|
||||
u16 m_ServerPort;
|
||||
bool m_UseSTUN;
|
||||
|
@ -87,7 +87,8 @@ CStr HashPassword(const CStr& password)
|
||||
return CStr(Hexify(encrypted, DIGESTSIZE)).UpperCase();
|
||||
}
|
||||
|
||||
void StartNetworkHost(const ScriptRequest& rq, const CStrW& playerName, const u16 serverPort, const CStr& hostLobbyName, bool useSTUN, const CStr& password)
|
||||
|
||||
void StartNetworkHost(const ScriptRequest& rq, const CStrW& playerName, const u16 serverPort, bool useSTUN, const CStr& password)
|
||||
{
|
||||
ENSURE(!g_NetClient);
|
||||
ENSURE(!g_NetServer);
|
||||
@ -138,7 +139,8 @@ void StartNetworkHost(const ScriptRequest& rq, const CStrW& playerName, const u1
|
||||
g_Game = new CGame(true);
|
||||
g_NetClient = new CNetClient(g_Game);
|
||||
g_NetClient->SetUserName(playerName);
|
||||
g_NetClient->SetHostingPlayerName(hostLobbyName);
|
||||
if (hasLobby)
|
||||
g_NetClient->SetHostJID(g_XmppClient->GetJID());
|
||||
g_NetClient->SetGamePassword(hashedPass);
|
||||
g_NetClient->SetupServerData("127.0.0.1", serverPort, false);
|
||||
g_NetClient->SetControllerSecret(secret);
|
||||
@ -151,7 +153,7 @@ void StartNetworkHost(const ScriptRequest& rq, const CStrW& playerName, const u1
|
||||
}
|
||||
}
|
||||
|
||||
void StartNetworkJoin(const ScriptRequest& rq, const CStrW& playerName, const CStr& serverAddress, u16 serverPort, bool useSTUN, const CStr& hostJID)
|
||||
void StartNetworkJoin(const ScriptRequest& rq, const CStrW& playerName, const CStr& serverAddress, u16 serverPort)
|
||||
{
|
||||
ENSURE(!g_NetClient);
|
||||
ENSURE(!g_NetServer);
|
||||
@ -160,8 +162,7 @@ void StartNetworkJoin(const ScriptRequest& rq, const CStrW& playerName, const CS
|
||||
g_Game = new CGame(true);
|
||||
g_NetClient = new CNetClient(g_Game);
|
||||
g_NetClient->SetUserName(playerName);
|
||||
g_NetClient->SetHostingPlayerName(hostJID.substr(0, hostJID.find("@")));
|
||||
g_NetClient->SetupServerData(serverAddress, serverPort, useSTUN);
|
||||
g_NetClient->SetupServerData(serverAddress, serverPort, false);
|
||||
|
||||
if (!g_NetClient->SetupConnection(nullptr))
|
||||
{
|
||||
@ -187,7 +188,7 @@ void StartNetworkJoinLobby(const CStrW& playerName, const CStr& hostJID, const C
|
||||
g_Game = new CGame(true);
|
||||
g_NetClient = new CNetClient(g_Game);
|
||||
g_NetClient->SetUserName(playerName);
|
||||
g_NetClient->SetHostingPlayerName(hostJID.substr(0, hostJID.find("@")));
|
||||
g_NetClient->SetHostJID(hostJID);
|
||||
g_NetClient->SetGamePassword(hashedPass);
|
||||
g_XmppClient->SendIqGetConnectionData(hostJID, hashedPass.c_str());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user