Initial work on lobby redesign
This commit is contained in:
parent
4dea283965
commit
3bbec8aa27
@ -25,13 +25,13 @@
|
||||
#include "network/race_config.hpp"
|
||||
#include "network/remote_kart_info.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Online { class OnlineProfile; }
|
||||
class NetworkPlayerProfile;
|
||||
|
||||
|
||||
// ============================================================================
|
||||
/*! \class GameSetup
|
||||
* \brief Used to store the needed data about the players that join a game.
|
||||
|
@ -19,31 +19,6 @@
|
||||
#include "network/network_player_profile.hpp"
|
||||
|
||||
#include "network/stk_host.hpp"
|
||||
#include "online/online_player_profile.hpp"
|
||||
|
||||
/** Constructor.
|
||||
* \param global_player_id A unique number assigned from the server to this
|
||||
* player (though it might not be the index in the peer list).
|
||||
* \param name Name of this player.
|
||||
* \param global_player_id Global id of this player.
|
||||
* \param host_id The id of the host the player is connected from.
|
||||
*/
|
||||
NetworkPlayerProfile::NetworkPlayerProfile(const irr::core::stringw &name,
|
||||
int global_player_id,
|
||||
int host_id )
|
||||
{
|
||||
m_global_player_id = global_player_id;
|
||||
m_host_id = host_id;
|
||||
m_kart_name = "";
|
||||
m_world_kart_id = 0;
|
||||
m_per_player_difficulty = PLAYER_DIFFICULTY_NORMAL;
|
||||
m_player_name = name;
|
||||
} // BetworkPlayerProfile
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
NetworkPlayerProfile::~NetworkPlayerProfile()
|
||||
{
|
||||
} // ~NetworkPlayerProfile
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns true if this player is local, i.e. running on this computer. This
|
||||
* is done by comparing the host id of this player with the host id of this
|
||||
@ -52,4 +27,4 @@ NetworkPlayerProfile::~NetworkPlayerProfile()
|
||||
bool NetworkPlayerProfile::isLocalPlayer() const
|
||||
{
|
||||
return m_host_id == STKHost::get()->getMyHostId();
|
||||
} // isLocalPlayer
|
||||
} // isLocalPlayer
|
||||
|
@ -26,10 +26,11 @@
|
||||
#include "utils/types.hpp"
|
||||
|
||||
#include "irrString.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
namespace Online { class OnlineProfile; }
|
||||
#include <tuple>
|
||||
|
||||
class STKPeer;
|
||||
|
||||
/*! \class NetworkPlayerProfile
|
||||
* \brief Contains the profile of a player.
|
||||
@ -37,31 +38,51 @@ namespace Online { class OnlineProfile; }
|
||||
class NetworkPlayerProfile
|
||||
{
|
||||
private:
|
||||
std::weak_ptr<STKPeer> m_peer;
|
||||
|
||||
/** The name of the player. */
|
||||
irr::core::stringw m_player_name;
|
||||
|
||||
/** Host id of this player. */
|
||||
uint32_t m_host_id;
|
||||
|
||||
float m_default_kart_color;
|
||||
|
||||
uint32_t m_online_id;
|
||||
|
||||
/** Per player difficulty. */
|
||||
PerPlayerDifficulty m_per_player_difficulty;
|
||||
|
||||
/** The selected kart id. */
|
||||
std::string m_kart_name;
|
||||
|
||||
/** The unique id of the player for this race. The number is assigned
|
||||
* by the server (and it might not be the index of this player in the
|
||||
* peer list. */
|
||||
uint8_t m_global_player_id;
|
||||
|
||||
/** Host id of this player. */
|
||||
uint8_t m_host_id;
|
||||
|
||||
/** The selected kart id. */
|
||||
std::string m_kart_name;
|
||||
|
||||
/** The name of the player. */
|
||||
irr::core::stringw m_player_name;
|
||||
|
||||
/** The kart id in the World class (pointer to AbstractKart). */
|
||||
uint8_t m_world_kart_id;
|
||||
|
||||
/** Per player difficulty. */
|
||||
PerPlayerDifficulty m_per_player_difficulty;
|
||||
public:
|
||||
NetworkPlayerProfile(const irr::core::stringw &name,
|
||||
int global_player_id, int host_id);
|
||||
~NetworkPlayerProfile();
|
||||
NetworkPlayerProfile(std::shared_ptr<STKPeer> peer,
|
||||
const irr::core::stringw &name, uint32_t host_id,
|
||||
float default_kart_color, uint32_t online_id,
|
||||
PerPlayerDifficulty per_player_difficulty)
|
||||
{
|
||||
m_peer = peer;
|
||||
m_player_name = name;
|
||||
m_host_id = host_id;
|
||||
m_default_kart_color = default_kart_color;
|
||||
m_online_id = online_id;
|
||||
m_per_player_difficulty = per_player_difficulty;
|
||||
m_global_player_id = 0;
|
||||
m_world_kart_id = 0;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
~NetworkPlayerProfile() {}
|
||||
// ------------------------------------------------------------------------
|
||||
bool isLocalPlayer() const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the global player id of this player. */
|
||||
void setGlobalPlayerId(int player_id) { m_global_player_id = player_id; }
|
||||
@ -93,6 +114,15 @@ public:
|
||||
/** Returns the name of this player. */
|
||||
const irr::core::stringw& getName() const { return m_player_name; }
|
||||
// ------------------------------------------------------------------------
|
||||
float getDefaultKartColor() const { return m_default_kart_color; }
|
||||
// ------------------------------------------------------------------------
|
||||
uint32_t getOnlineID() const { return m_online_id; }
|
||||
// ------------------------------------------------------------------------
|
||||
std::shared_ptr<STKPeer> getPeer() const { return m_peer.lock(); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the minimun info for networking lobby screen. */
|
||||
std::tuple<uint32_t, uint32_t, irr::core::stringw> toTuple() const
|
||||
{ return std::make_tuple(m_host_id, m_online_id, m_player_name); }
|
||||
|
||||
}; // class NetworkPlayerProfile
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "config/player_manager.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "guiengine/message_queue.hpp"
|
||||
#include "modes/world_with_rank.hpp"
|
||||
#include "network/event.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
@ -29,6 +30,7 @@
|
||||
#include "network/race_event_manager.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "network/stk_peer.hpp"
|
||||
#include "online/online_player_profile.hpp"
|
||||
#include "online/online_profile.hpp"
|
||||
#include "states_screens/networking_lobby.hpp"
|
||||
#include "states_screens/network_kart_selection.hpp"
|
||||
@ -201,13 +203,6 @@ void ClientLobby::voteLaps(uint8_t player_id, uint8_t laps,
|
||||
delete request;
|
||||
} // voteLaps
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called when a client selects to exit a server.
|
||||
*/
|
||||
void ClientLobby::leave()
|
||||
{
|
||||
} // leave
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called from the gui when a client clicked on 'continue' on the race result
|
||||
* screen. It notifies the server that this client has exited the screen and
|
||||
@ -239,6 +234,7 @@ bool ClientLobby::notifyEvent(Event* event)
|
||||
case LE_LOAD_WORLD: loadWorld(); break;
|
||||
case LE_RACE_FINISHED: raceFinished(event); break;
|
||||
case LE_EXIT_RESULT: exitResultScreen(event); break;
|
||||
case LE_UPDATE_PLAYER_LIST: updatePlayerList(event); break;
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
@ -261,7 +257,6 @@ bool ClientLobby::notifyEventAsynchronous(Event* event)
|
||||
message_type);
|
||||
switch(message_type)
|
||||
{
|
||||
case LE_NEW_PLAYER_CONNECTED: newPlayer(event); break;
|
||||
case LE_PLAYER_DISCONNECTED : disconnectedPlayer(event); break;
|
||||
case LE_START_RACE: startGame(event); break;
|
||||
case LE_CONNECTION_REFUSED: connectionRefused(event); break;
|
||||
@ -273,6 +268,7 @@ bool ClientLobby::notifyEventAsynchronous(Event* event)
|
||||
case LE_VOTE_TRACK: playerTrackVote(event); break;
|
||||
case LE_VOTE_REVERSE: playerReversedVote(event); break;
|
||||
case LE_VOTE_LAPS: playerLapsVote(event); break;
|
||||
case LE_AUTHORISED: becomingServerOwner(); break;
|
||||
} // switch
|
||||
|
||||
return true;
|
||||
@ -321,20 +317,31 @@ void ClientLobby::update(float dt)
|
||||
break;
|
||||
case LINKED:
|
||||
{
|
||||
core::stringw name;
|
||||
if(PlayerManager::getCurrentOnlineState()==PlayerProfile::OS_SIGNED_IN)
|
||||
name = PlayerManager::getCurrentOnlineUserName();
|
||||
else
|
||||
name = PlayerManager::getCurrentPlayer()->getName();
|
||||
|
||||
std::string name_u8 = StringUtils::wideToUtf8(name);
|
||||
const std::string &password = NetworkConfig::get()->getPassword();
|
||||
NetworkString *ns = getNetworkString(6+1+name_u8.size()
|
||||
+1+password.size());
|
||||
// 4 (size of id), global id
|
||||
ns->addUInt8(LE_CONNECTION_REQUESTED).encodeString(name)
|
||||
.encodeString(NetworkConfig::get()->getPassword());
|
||||
// atm assume only 1 local player (no split screen yet)
|
||||
NetworkString *ns = getNetworkString();
|
||||
ns->addUInt8(LE_CONNECTION_REQUESTED)
|
||||
.encodeString(NetworkConfig::get()->getPassword());
|
||||
|
||||
uint8_t num_player = 1;
|
||||
ns->addUInt8(num_player);
|
||||
for (unsigned i = 0; i < num_player; i++)
|
||||
{
|
||||
core::stringw name;
|
||||
PlayerProfile* player = PlayerManager::getCurrentPlayer();
|
||||
if (PlayerManager::getCurrentOnlineState() ==
|
||||
PlayerProfile::OS_SIGNED_IN)
|
||||
name = PlayerManager::getCurrentOnlineUserName();
|
||||
else
|
||||
name = player->getName();
|
||||
std::string name_u8 = StringUtils::wideToUtf8(name);
|
||||
ns->encodeString(name_u8).addFloat(player->getDefaultKartColor());
|
||||
Online::OnlinePlayerProfile* opp =
|
||||
dynamic_cast<Online::OnlinePlayerProfile*>(player);
|
||||
ns->addUInt32(opp && opp->getProfile() ?
|
||||
opp->getProfile()->getID() : 0);
|
||||
// Assume no handicap player now
|
||||
ns->addUInt8(PLAYER_DIFFICULTY_NORMAL);
|
||||
}
|
||||
auto all_k = kart_properties_manager->getAllAvailableKarts();
|
||||
auto all_t = track_manager->getAllTrackIdentifiers();
|
||||
if (all_k.size() >= 65536)
|
||||
@ -389,49 +396,6 @@ void ClientLobby::update(float dt)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*! \brief Called when a new player is connected to the server
|
||||
* \param event : Event providing the information.
|
||||
*
|
||||
* Format of the data :
|
||||
* Byte 0 1 2
|
||||
* -------------------------------------
|
||||
* Size | 1 | 1 | |
|
||||
* Data | player_id | hostid | player name |
|
||||
* -------------------------------------
|
||||
*/
|
||||
void ClientLobby::newPlayer(Event* event)
|
||||
{
|
||||
if (!checkDataSize(event, 2)) return;
|
||||
const NetworkString &data = event->data();
|
||||
|
||||
uint8_t player_id = data.getUInt8();
|
||||
uint8_t host_id = data.getUInt8();
|
||||
core::stringw name;
|
||||
data.decodeStringW(&name);
|
||||
// FIXME need adjusting when splitscreen is used/
|
||||
if(STKHost::get()->getGameSetup()->isLocalMaster(player_id))
|
||||
{
|
||||
Log::error("ClientLobby",
|
||||
"The server notified me that I'm a new player in the "
|
||||
"room (not normal).");
|
||||
}
|
||||
else if (m_game_setup->getProfile(player_id) == NULL)
|
||||
{
|
||||
Log::verbose("ClientLobby", "New player connected.");
|
||||
NetworkPlayerProfile* profile =
|
||||
new NetworkPlayerProfile(name, player_id, host_id);
|
||||
m_game_setup->addPlayer(profile);
|
||||
NetworkingLobby::getInstance()->addPlayer(profile);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::error("ClientLobby",
|
||||
"One of the player notified in the list is myself.");
|
||||
}
|
||||
} // newPlayer
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*! \brief Called when a new player is disconnected
|
||||
* \param event : Event providing the information.
|
||||
*
|
||||
@ -447,95 +411,67 @@ void ClientLobby::disconnectedPlayer(Event* event)
|
||||
if (!checkDataSize(event, 1)) return;
|
||||
|
||||
NetworkString &data = event->data();
|
||||
while(data.size()>0)
|
||||
unsigned disconnected_player_count = data.getUInt8();
|
||||
for (unsigned i = 0; i < disconnected_player_count; i++)
|
||||
{
|
||||
const NetworkPlayerProfile *profile =
|
||||
m_game_setup->getProfile(data.getUInt8());
|
||||
if (m_game_setup->removePlayer(profile))
|
||||
{
|
||||
Log::info("ClientLobby",
|
||||
"Player %d removed successfully.",
|
||||
profile->getGlobalPlayerId());
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::error("ClientLobby",
|
||||
"The disconnected peer wasn't known.");
|
||||
}
|
||||
} // while
|
||||
core::stringw player_name;
|
||||
data.decodeStringW(&player_name);
|
||||
core::stringw msg = _("%s disconnected.", player_name);
|
||||
// Use the friend icon to avoid an error-like message
|
||||
MessageQueue::add(MessageQueue::MT_FRIEND, msg);
|
||||
}
|
||||
|
||||
} // disconnectedPlayer
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*! \brief Called when the server accepts the connection.
|
||||
* \param event : Event providing the information.
|
||||
*
|
||||
* Format of the data :
|
||||
* Byte 0 1 2 3
|
||||
* ---------------------------------------------------------
|
||||
* Size | 1 | 1 | 1 | |
|
||||
* Data | player_id| hostid | authorised |playernames* |
|
||||
* ---------------------------------------------------------
|
||||
*/
|
||||
void ClientLobby::connectionAccepted(Event* event)
|
||||
{
|
||||
// At least 3 bytes should remain now
|
||||
if(!checkDataSize(event, 3)) return;
|
||||
// At least 4 byte should remain now
|
||||
if (!checkDataSize(event, 4)) return;
|
||||
|
||||
NetworkString &data = event->data();
|
||||
STKPeer* peer = event->getPeer();
|
||||
|
||||
// Accepted
|
||||
// ========
|
||||
Log::info("ClientLobby",
|
||||
"The server accepted the connection.");
|
||||
Log::info("ClientLobby", "The server accepted the connection.");
|
||||
|
||||
// self profile
|
||||
irr::core::stringw name;
|
||||
if (PlayerManager::getCurrentOnlineState() == PlayerProfile::OS_SIGNED_IN)
|
||||
name = PlayerManager::getCurrentOnlineUserName();
|
||||
else
|
||||
name = PlayerManager::getCurrentPlayer()->getName();
|
||||
uint8_t my_player_id = data.getUInt8();
|
||||
uint8_t my_host_id = data.getUInt8();
|
||||
uint8_t authorised = data.getUInt8();
|
||||
// Store this client's authorisation status in the peer information
|
||||
// for the server.
|
||||
event->getPeer()->setAuthorised(authorised!=0);
|
||||
STKHost::get()->setMyHostId(my_host_id);
|
||||
|
||||
NetworkPlayerProfile* profile =
|
||||
new NetworkPlayerProfile(name, my_player_id, my_host_id);
|
||||
STKHost::get()->getGameSetup()->setLocalMaster(my_player_id);
|
||||
STKHost::get()->setMyHostId(data.getUInt32());
|
||||
m_game_setup->setNumLocalPlayers(1);
|
||||
// connection token
|
||||
uint32_t token = data.getToken();
|
||||
peer->setClientServerToken(token);
|
||||
|
||||
// Add all players
|
||||
// ===============
|
||||
while (data.size() > 0)
|
||||
{
|
||||
uint8_t player_id = data.getUInt8();
|
||||
uint8_t host_id = data.getUInt8();
|
||||
irr::core::stringw name;
|
||||
data.decodeStringW(&name);
|
||||
|
||||
NetworkPlayerProfile* profile2 =
|
||||
new NetworkPlayerProfile(name, player_id, host_id);
|
||||
m_game_setup->addPlayer(profile2);
|
||||
// Inform the network lobby of all players so that the GUI can
|
||||
// show all currently connected players.
|
||||
NetworkingLobby::getInstance()->addPlayer(profile2);
|
||||
}
|
||||
|
||||
// Add self after other players so that player order is identical
|
||||
// on server and all clients.
|
||||
m_game_setup->addPlayer(profile);
|
||||
NetworkingLobby::getInstance()->addPlayer(profile);
|
||||
m_state = CONNECTED;
|
||||
if (NetworkConfig::get()->isAutoConnect())
|
||||
} // connectionAccepted
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ClientLobby::updatePlayerList(Event* event)
|
||||
{
|
||||
if (!checkDataSize(event, 1)) return;
|
||||
NetworkString &data = event->data();
|
||||
unsigned player_count = data.getUInt8();
|
||||
NetworkingLobby::getInstance()->cleanPlayers();
|
||||
for (unsigned i = 0; i < player_count; i++)
|
||||
{
|
||||
std::tuple<uint32_t, uint32_t, core::stringw, bool> pl;
|
||||
std::get<0>(pl) = data.getUInt32();
|
||||
std::get<1>(pl) = data.getUInt32();
|
||||
data.decodeStringW(&std::get<2>(pl));
|
||||
std::get<3>(pl) = data.getUInt8() == 1;
|
||||
NetworkingLobby::getInstance()->addPlayer(pl);
|
||||
}
|
||||
} // updatePlayerList
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ClientLobby::becomingServerOwner()
|
||||
{
|
||||
MessageQueue::add(MessageQueue::MT_GENERIC,
|
||||
_("You are now the owner of server."));
|
||||
STKHost::get()->setAuthorisedToControl(true);
|
||||
if (m_state == CONNECTED && NetworkConfig::get()->isAutoConnect())
|
||||
{
|
||||
// Send a message to the server to start
|
||||
NetworkString start(PROTOCOL_LOBBY_ROOM);
|
||||
@ -543,8 +479,7 @@ void ClientLobby::connectionAccepted(Event* event)
|
||||
start.addUInt8(LobbyProtocol::LE_REQUEST_BEGIN);
|
||||
STKHost::get()->sendToServer(&start, true);
|
||||
}
|
||||
|
||||
} // connectionAccepted
|
||||
} // becomingServerOwner
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@ -562,26 +497,31 @@ void ClientLobby::connectionRefused(Event* event)
|
||||
{
|
||||
if (!checkDataSize(event, 1)) return;
|
||||
const NetworkString &data = event->data();
|
||||
|
||||
switch (data.getUInt8()) // the second byte
|
||||
switch ((RejectReason)data.getUInt8()) // the second byte
|
||||
{
|
||||
case 0:
|
||||
Log::info("ClientLobby",
|
||||
"Connection refused : too many players.");
|
||||
case RR_BUSY:
|
||||
STKHost::get()->setErrorMessage(
|
||||
_("Connection refused: Server is busy."));
|
||||
break;
|
||||
case 1:
|
||||
Log::info("ClientLobby", "Connection refused : banned.");
|
||||
case RR_BANNED:
|
||||
STKHost::get()->setErrorMessage(
|
||||
_("Connection refused: You are banned from the server."));
|
||||
break;
|
||||
case 2:
|
||||
Log::info("ClientLobby", "Client busy.");
|
||||
case RR_INCORRECT_PASSWORD:
|
||||
STKHost::get()->setErrorMessage(
|
||||
_("Connection refused: Server password is incorrect."));
|
||||
break;
|
||||
case 3:
|
||||
Log::info("ClientLobby", "Having incompatible karts / tracks.");
|
||||
case RR_INCOMPATIBLE_DATA:
|
||||
STKHost::get()->setErrorMessage(
|
||||
_("Connection refused: Game data is incompatible."));
|
||||
break;
|
||||
default:
|
||||
Log::info("ClientLobby", "Connection refused.");
|
||||
case RR_TOO_MANY_PLAYERS:
|
||||
STKHost::get()->setErrorMessage(
|
||||
_("Connection refused: Server is full."));
|
||||
break;
|
||||
}
|
||||
STKHost::get()->disconnectAllPeers(false/*timeout_waiting*/);
|
||||
STKHost::get()->requestShutdown();
|
||||
} // connectionRefused
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -9,7 +9,6 @@
|
||||
class ClientLobby : public LobbyProtocol
|
||||
{
|
||||
private:
|
||||
void newPlayer(Event* event);
|
||||
void disconnectedPlayer(Event* event);
|
||||
void connectionAccepted(Event* event); //!< Callback function on connection acceptation
|
||||
void connectionRefused(Event* event); //!< Callback function on connection refusal
|
||||
@ -26,6 +25,8 @@ private:
|
||||
void playerTrackVote(Event* event);
|
||||
void playerReversedVote(Event* event);
|
||||
void playerLapsVote(Event* event);
|
||||
void updatePlayerList(Event* event);
|
||||
void becomingServerOwner();
|
||||
|
||||
TransportAddress m_server_address;
|
||||
|
||||
@ -65,7 +66,6 @@ public:
|
||||
void voteLaps(uint8_t player_id, uint8_t laps, uint8_t track_nb = 0);
|
||||
void doneWithResults();
|
||||
void startingRaceNow();
|
||||
void leave();
|
||||
|
||||
const std::set<std::string>& getAvailableKarts() const
|
||||
{ return m_available_karts; }
|
||||
|
@ -42,7 +42,7 @@ public:
|
||||
LE_KART_SELECTION_UPDATE, // inform client about kart selected
|
||||
LE_REQUEST_BEGIN, // begin of kart selection
|
||||
LE_KART_SELECTION_REFUSED, // Client not auth. to start selection
|
||||
LE_NEW_PLAYER_CONNECTED, // inform client about new player
|
||||
LE_UPDATE_PLAYER_LIST, // inform client about player list update
|
||||
LE_KART_SELECTION, // Player selected kart
|
||||
LE_PLAYER_DISCONNECTED, // Client disconnected
|
||||
LE_CLIENT_LOADED_WORLD, // Client finished loading world
|
||||
@ -60,6 +60,18 @@ public:
|
||||
LE_VOTE_TRACK, // vote for a track
|
||||
LE_VOTE_REVERSE, // vote if race in reverse
|
||||
LE_VOTE_LAPS, // vote number of laps
|
||||
LE_CHAT,
|
||||
LE_FINAL_PLAYER_LIST,
|
||||
LE_AUTHORISED
|
||||
};
|
||||
|
||||
enum RejectReason : uint8_t
|
||||
{
|
||||
RR_BUSY = 0,
|
||||
RR_BANNED = 1,
|
||||
RR_INCORRECT_PASSWORD = 2,
|
||||
RR_INCOMPATIBLE_DATA = 3,
|
||||
RR_TOO_MANY_PLAYERS = 4
|
||||
};
|
||||
|
||||
protected:
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "utils/random_generator.hpp"
|
||||
#include "utils/time.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
|
||||
/** This is the central game setup protocol running in the server. It is
|
||||
@ -84,18 +85,9 @@
|
||||
*/
|
||||
ServerLobby::ServerLobby() : LobbyProtocol(NULL)
|
||||
{
|
||||
m_has_created_server_id_file = false;
|
||||
setHandleDisconnections(true);
|
||||
m_state = SET_PUBLIC_ADDRESS;
|
||||
|
||||
// We use maximum 16bit unsigned limit
|
||||
auto all_k = kart_properties_manager->getAllAvailableKarts();
|
||||
auto all_t = track_manager->getAllTrackIdentifiers();
|
||||
if (all_k.size() >= 65536)
|
||||
all_k.resize(65535);
|
||||
if (all_t.size() >= 65536)
|
||||
all_t.resize(65535);
|
||||
m_available_kts.getData().first = { all_k.begin(), all_k.end() };
|
||||
m_available_kts.getData().second = { all_t.begin(), all_t.end() };
|
||||
} // ServerLobby
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -113,6 +105,16 @@ ServerLobby::~ServerLobby()
|
||||
|
||||
void ServerLobby::setup()
|
||||
{
|
||||
// We use maximum 16bit unsigned limit
|
||||
auto all_k = kart_properties_manager->getAllAvailableKarts();
|
||||
auto all_t = track_manager->getAllTrackIdentifiers();
|
||||
if (all_k.size() >= 65536)
|
||||
all_k.resize(65535);
|
||||
if (all_t.size() >= 65536)
|
||||
all_t.resize(65535);
|
||||
m_available_kts.first = { all_k.begin(), all_k.end() };
|
||||
m_available_kts.second = { all_t.begin(), all_t.end() };
|
||||
|
||||
m_server_registered = false;
|
||||
m_game_setup = STKHost::get()->setupNewGame();
|
||||
m_game_setup->setNumLocalPlayers(0); // no local players on a server
|
||||
@ -197,11 +199,12 @@ bool ServerLobby::notifyEventAsynchronous(Event* event)
|
||||
void ServerLobby::createServerIdFile()
|
||||
{
|
||||
const std::string& sid = NetworkConfig::get()->getServerIdFile();
|
||||
if (!sid.empty())
|
||||
if (!sid.empty() && !m_has_created_server_id_file)
|
||||
{
|
||||
std::fstream fs;
|
||||
fs.open(sid, std::ios::out);
|
||||
fs.close();
|
||||
m_has_created_server_id_file = true;
|
||||
}
|
||||
} // createServerIdFile
|
||||
|
||||
@ -265,6 +268,7 @@ void ServerLobby::asynchronousUpdate()
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} // asynchronousUpdate
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -274,6 +278,9 @@ void ServerLobby::asynchronousUpdate()
|
||||
*/
|
||||
void ServerLobby::update(float dt)
|
||||
{
|
||||
// Check if server owner has left
|
||||
updateServerOwner();
|
||||
|
||||
switch (m_state.load())
|
||||
{
|
||||
case SET_PUBLIC_ADDRESS:
|
||||
@ -463,12 +470,6 @@ void ServerLobby::signalRaceStartToClients()
|
||||
void ServerLobby::startSelection(const Event *event)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_connection_mutex);
|
||||
if (NetworkConfig::get()->isWAN())
|
||||
{
|
||||
assert(m_server_registered);
|
||||
unregisterServer();
|
||||
m_server_registered = false;
|
||||
}
|
||||
|
||||
if (m_state != ACCEPTING_CLIENTS)
|
||||
{
|
||||
@ -477,21 +478,28 @@ void ServerLobby::startSelection(const Event *event)
|
||||
m_state.load());
|
||||
return;
|
||||
}
|
||||
if(event && !event->getPeer()->isAuthorised())
|
||||
if (event->getPeerSP() != m_server_owner.lock())
|
||||
{
|
||||
Log::warn("ServerLobby",
|
||||
"Client %lx is not authorised to start selection.",
|
||||
event->getPeer());
|
||||
return;
|
||||
}
|
||||
|
||||
if (NetworkConfig::get()->isWAN())
|
||||
{
|
||||
assert(m_server_registered);
|
||||
unregisterServer();
|
||||
m_server_registered = false;
|
||||
}
|
||||
|
||||
NetworkString *ns = getNetworkString(1);
|
||||
// Start selection - must be synchronous since the receiver pushes
|
||||
// a new screen, which must be donefrom the main thread.
|
||||
ns->setSynchronous(true);
|
||||
ns->addUInt8(LE_START_SELECTION);
|
||||
m_available_kts.lock();
|
||||
const auto& all_k = m_available_kts.getData().first;
|
||||
const auto& all_t = m_available_kts.getData().second;
|
||||
const auto& all_k = m_available_kts.first;
|
||||
const auto& all_t = m_available_kts.second;
|
||||
ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)all_t.size());
|
||||
for (const std::string& kart : all_k)
|
||||
{
|
||||
@ -501,7 +509,6 @@ void ServerLobby::startSelection(const Event *event)
|
||||
{
|
||||
ns->encodeString(track);
|
||||
}
|
||||
m_available_kts.unlock();
|
||||
|
||||
sendMessageToPeersChangingToken(ns, /*reliable*/true);
|
||||
delete ns;
|
||||
@ -625,23 +632,21 @@ void ServerLobby::checkIncomingConnectionRequests()
|
||||
*/
|
||||
void ServerLobby::clientDisconnected(Event* event)
|
||||
{
|
||||
std::vector<NetworkPlayerProfile*> players_on_host =
|
||||
event->getPeer()->getAllPlayerProfiles();
|
||||
std::lock_guard<std::mutex> lock(m_connection_mutex);
|
||||
auto players_on_peer = event->getPeer()->getPlayerProfiles();
|
||||
if (players_on_peer.empty())
|
||||
return;
|
||||
|
||||
NetworkString *msg = getNetworkString(2);
|
||||
NetworkString* msg = getNetworkString(2);
|
||||
msg->addUInt8(LE_PLAYER_DISCONNECTED);
|
||||
|
||||
for(unsigned int i=0; i<players_on_host.size(); i++)
|
||||
msg->addUInt8((uint8_t)players_on_peer.size());
|
||||
for (auto p : players_on_peer)
|
||||
{
|
||||
msg->addUInt8(players_on_host[i]->getGlobalPlayerId());
|
||||
Log::info("ServerLobby", "Player disconnected : id %d",
|
||||
players_on_host[i]->getGlobalPlayerId());
|
||||
m_game_setup->removePlayer(players_on_host[i]);
|
||||
msg->encodeString(p->getName());
|
||||
}
|
||||
|
||||
sendMessageToPeersChangingToken(msg, /*reliable*/true);
|
||||
updatePlayerList();
|
||||
delete msg;
|
||||
|
||||
} // clientDisconnected
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -659,34 +664,62 @@ void ServerLobby::clientDisconnected(Event* event)
|
||||
void ServerLobby::connectionRequested(Event* event)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_connection_mutex);
|
||||
STKPeer* peer = event->getPeer();
|
||||
std::shared_ptr<STKPeer> peer = event->getPeerSP();
|
||||
peer->cleanPlayerProfiles();
|
||||
|
||||
const NetworkString &data = event->data();
|
||||
|
||||
// can we add the player ?
|
||||
if (m_game_setup->getPlayerCount() >= NetworkConfig::get()->getMaxPlayers() ||
|
||||
m_state!=ACCEPTING_CLIENTS )
|
||||
if (m_game_setup->getPlayerCount() >=
|
||||
NetworkConfig::get()->getMaxPlayers() ||
|
||||
m_state != ACCEPTING_CLIENTS)
|
||||
{
|
||||
NetworkString *message = getNetworkString(2);
|
||||
// Len, error code: 2 = busy, 0 = too many players
|
||||
message->addUInt8(LE_CONNECTION_REFUSED)
|
||||
.addUInt8(m_state!=ACCEPTING_CLIENTS ? 2 : 0);
|
||||
.addUInt8(m_state != ACCEPTING_CLIENTS ?
|
||||
RR_BUSY : RR_TOO_MANY_PLAYERS);
|
||||
|
||||
// send only to the peer that made the request
|
||||
// send only to the peer that made the request and disconect it now
|
||||
peer->sendPacket(message);
|
||||
peer->reset();
|
||||
delete message;
|
||||
Log::verbose("ServerLobby", "Player refused");
|
||||
return;
|
||||
}
|
||||
|
||||
// Connection accepted.
|
||||
// ====================
|
||||
std::string name_u8;
|
||||
data.decodeString(&name_u8);
|
||||
core::stringw name = StringUtils::utf8ToWide(name_u8);
|
||||
// Check for password
|
||||
std::string password;
|
||||
data.decodeString(&password);
|
||||
bool is_authorised = (password==NetworkConfig::get()->getPassword());
|
||||
if (password != NetworkConfig::get()->getPassword())
|
||||
{
|
||||
NetworkString *message = getNetworkString(2);
|
||||
message->addUInt8(LE_CONNECTION_REFUSED)
|
||||
.addUInt8(RR_INCORRECT_PASSWORD);
|
||||
|
||||
// send only to the peer that made the request and disconect it now
|
||||
peer->sendPacket(message);
|
||||
peer->reset();
|
||||
delete message;
|
||||
Log::verbose("ServerLobby", "Player refused: incorrect password");
|
||||
return;
|
||||
}
|
||||
|
||||
// Connection accepted.
|
||||
// ====================
|
||||
uint8_t player_count = data.getUInt8();
|
||||
for (unsigned i = 0; i < player_count; i++)
|
||||
{
|
||||
std::string name_u8;
|
||||
data.decodeString(&name_u8);
|
||||
core::stringw name = StringUtils::utf8ToWide(name_u8);
|
||||
float default_kart_color = data.getFloat();
|
||||
uint32_t online_id = data.getUInt32();
|
||||
PerPlayerDifficulty per_player_difficulty =
|
||||
(PerPlayerDifficulty)data.getUInt8();
|
||||
peer->addPlayer(std::make_shared<NetworkPlayerProfile>
|
||||
(peer, name, peer->getHostId(), default_kart_color, online_id,
|
||||
per_player_difficulty));
|
||||
}
|
||||
std::set<std::string> client_karts, client_tracks;
|
||||
const unsigned kart_num = data.getUInt16();
|
||||
const unsigned track_num = data.getUInt16();
|
||||
@ -707,14 +740,14 @@ void ServerLobby::connectionRequested(Event* event)
|
||||
// so that in the end the server has a list of all karts/tracks available
|
||||
// on all clients
|
||||
std::set<std::string> karts_erase, tracks_erase;
|
||||
for (const std::string& server_kart : m_available_kts.getData().first)
|
||||
for (const std::string& server_kart : m_available_kts.first)
|
||||
{
|
||||
if (client_karts.find(server_kart) == client_karts.end())
|
||||
{
|
||||
karts_erase.insert(server_kart);
|
||||
}
|
||||
}
|
||||
for (const std::string& server_track : m_available_kts.getData().second)
|
||||
for (const std::string& server_track : m_available_kts.second)
|
||||
{
|
||||
if (client_tracks.find(server_track) == client_tracks.end())
|
||||
{
|
||||
@ -724,48 +757,27 @@ void ServerLobby::connectionRequested(Event* event)
|
||||
|
||||
// Drop this player if he doesn't have at least 1 kart / track the same
|
||||
// from server
|
||||
if (karts_erase.size() == m_available_kts.getData().first.size() ||
|
||||
tracks_erase.size() == m_available_kts.getData().second.size())
|
||||
if (karts_erase.size() == m_available_kts.first.size() ||
|
||||
tracks_erase.size() == m_available_kts.second.size())
|
||||
{
|
||||
NetworkString *message = getNetworkString(2);
|
||||
message->addUInt8(LE_CONNECTION_REFUSED).addUInt8(3);
|
||||
message->addUInt8(LE_CONNECTION_REFUSED)
|
||||
.addUInt8(RR_INCOMPATIBLE_DATA);
|
||||
peer->sendPacket(message);
|
||||
peer->reset();
|
||||
delete message;
|
||||
Log::verbose("ServerLobby", "Player has incompatible karts / tracks");
|
||||
m_available_kts.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
for (const std::string& kart_erase : karts_erase)
|
||||
{
|
||||
m_available_kts.getData().first.erase(kart_erase);
|
||||
m_available_kts.first.erase(kart_erase);
|
||||
}
|
||||
for (const std::string& track_erase : tracks_erase)
|
||||
{
|
||||
m_available_kts.getData().second.erase(track_erase);
|
||||
m_available_kts.second.erase(track_erase);
|
||||
}
|
||||
m_available_kts.unlock();
|
||||
|
||||
// Get the unique global ID for this player.
|
||||
m_next_player_id.lock();
|
||||
m_next_player_id.getData()++;
|
||||
int new_player_id = m_next_player_id.getData();
|
||||
m_next_player_id.unlock();
|
||||
if(m_game_setup->getLocalMasterID()==0)
|
||||
m_game_setup->setLocalMaster(new_player_id);
|
||||
|
||||
// The host id has already been incremented when the peer
|
||||
// was added, so it is the right id now.
|
||||
int new_host_id = STKHost::get()->getNextHostId();
|
||||
|
||||
// Notify everybody that there is a new player
|
||||
// -------------------------------------------
|
||||
NetworkString *message = getNetworkString(3+1+name_u8.size());
|
||||
// size of id -- id -- size of local id -- local id;
|
||||
message->addUInt8(LE_NEW_PLAYER_CONNECTED).addUInt8(new_player_id)
|
||||
.addUInt8(new_host_id).encodeString(name_u8);
|
||||
STKHost::get()->sendPacketExcept(peer, message);
|
||||
delete message;
|
||||
|
||||
// Now answer to the peer that just connected
|
||||
// ------------------------------------------
|
||||
@ -777,38 +789,83 @@ void ServerLobby::connectionRequested(Event* event)
|
||||
(token_generator.get(RAND_MAX) & 0xff));
|
||||
|
||||
peer->setClientServerToken(token);
|
||||
peer->setAuthorised(is_authorised);
|
||||
peer->setHostId(new_host_id);
|
||||
|
||||
const std::vector<NetworkPlayerProfile*> &players = m_game_setup->getPlayers();
|
||||
// send a message to the one that asked to connect
|
||||
// Estimate 10 as average name length
|
||||
NetworkString *message_ack = getNetworkString(4 + players.size() * (2+10));
|
||||
// connection success -- size of token -- token
|
||||
message_ack->addUInt8(LE_CONNECTION_ACCEPTED).addUInt8(new_player_id)
|
||||
.addUInt8(new_host_id).addUInt8(is_authorised);
|
||||
// Add all players so that this user knows (this new player is only added
|
||||
// to the list of players later, so the new player's info is not included)
|
||||
for (unsigned int i = 0; i < players.size(); i++)
|
||||
{
|
||||
message_ack->addUInt8(players[i]->getGlobalPlayerId())
|
||||
.addUInt8(players[i]->getHostId())
|
||||
.encodeString(players[i]->getName());
|
||||
}
|
||||
NetworkString *message_ack = getNetworkString(4);
|
||||
// connection success -- return the host id of peer
|
||||
message_ack->addUInt8(LE_CONNECTION_ACCEPTED).addUInt32(peer->getHostId());
|
||||
peer->sendPacket(message_ack);
|
||||
delete message_ack;
|
||||
|
||||
NetworkPlayerProfile* profile =
|
||||
new NetworkPlayerProfile(name, new_player_id, new_host_id);
|
||||
m_game_setup->addPlayer(profile);
|
||||
NetworkingLobby::getInstance()->addPlayer(profile);
|
||||
|
||||
updatePlayerList();
|
||||
Log::verbose("ServerLobby", "New player.");
|
||||
|
||||
} // connectionRequested
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ServerLobby::updatePlayerList()
|
||||
{
|
||||
if (m_state.load() != ACCEPTING_CLIENTS)
|
||||
return;
|
||||
auto all_profiles = STKHost::get()->getAllPlayerProfiles();
|
||||
NetworkString* pl = getNetworkString();
|
||||
pl->setSynchronous(true);
|
||||
pl->addUInt8(LE_UPDATE_PLAYER_LIST).addUInt8((uint8_t)all_profiles.size());
|
||||
for (auto profile : all_profiles)
|
||||
{
|
||||
pl->addUInt32(profile->getHostId()).addUInt32(profile->getOnlineID())
|
||||
.encodeString(profile->getName());
|
||||
uint8_t server_owner = 0;
|
||||
if (m_server_owner.lock() == profile->getPeer())
|
||||
server_owner = 1;
|
||||
pl->addUInt8(server_owner);
|
||||
}
|
||||
sendMessageToPeersChangingToken(pl);
|
||||
delete pl;
|
||||
} // updatePlayerList
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ServerLobby::updateServerOwner()
|
||||
{
|
||||
if (m_state.load() < ACCEPTING_CLIENTS ||
|
||||
m_state.load() > RESULT_DISPLAY)
|
||||
return;
|
||||
if (!m_server_owner.expired())
|
||||
return;
|
||||
auto peers = STKHost::get()->getPeers();
|
||||
if (peers.empty())
|
||||
return;
|
||||
std::sort(peers.begin(), peers.end(), [](const std::shared_ptr<STKPeer> a,
|
||||
const std::shared_ptr<STKPeer> b)->bool
|
||||
{
|
||||
return a->getHostId() < b->getHostId();
|
||||
});
|
||||
|
||||
std::shared_ptr<STKPeer> owner;
|
||||
std::lock_guard<std::mutex> lock(m_connection_mutex);
|
||||
// Make sure no one access the weak pointer or adding player to peers
|
||||
for (auto peer: peers)
|
||||
{
|
||||
// Only 127.0.0.1 can be server owner in case of graphics-client-server
|
||||
if (peer->hasPlayerProfiles() &&
|
||||
(NetworkConfig::get()->getServerIdFile().empty() ||
|
||||
peer->getAddress().getIP() == 0x7f000001))
|
||||
{
|
||||
owner = peer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (owner)
|
||||
{
|
||||
NetworkString* ns = getNetworkString();
|
||||
ns->addUInt8(LE_AUTHORISED);
|
||||
owner->sendPacket(ns);
|
||||
delete ns;
|
||||
m_server_owner = owner;
|
||||
updatePlayerList();
|
||||
}
|
||||
} // updateServerOwner
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/*! \brief Called when a player asks to select a kart.
|
||||
* \param event : Event providing the information.
|
||||
*
|
||||
|
@ -6,9 +6,12 @@
|
||||
#include "utils/synchronised.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
|
||||
class STKPeer;
|
||||
|
||||
class ServerLobby : public LobbyProtocol
|
||||
{
|
||||
public:
|
||||
@ -31,10 +34,13 @@ public:
|
||||
private:
|
||||
std::atomic<ServerState> m_state;
|
||||
|
||||
/** Hold the next connected peer for server owner if current one expired
|
||||
* (disconnected). */
|
||||
std::weak_ptr<STKPeer> m_server_owner;
|
||||
|
||||
/** Available karts and tracks for all clients, this will be initialized
|
||||
* with data in server first. */
|
||||
Synchronised<std::pair<std::set<std::string>,
|
||||
std::set<std::string> > > m_available_kts;
|
||||
std::pair<std::set<std::string>, std::set<std::string> > m_available_kts;
|
||||
|
||||
/** Next id to assign to a peer. */
|
||||
Synchronised<int> m_next_player_id;
|
||||
@ -58,6 +64,8 @@ private:
|
||||
|
||||
bool m_selection_enabled;
|
||||
|
||||
bool m_has_created_server_id_file;
|
||||
|
||||
/** It indicates if this server is registered with the stk server. */
|
||||
std::atomic_bool m_server_registered;
|
||||
|
||||
@ -89,6 +97,9 @@ private:
|
||||
void startedRaceOnClient(Event *event);
|
||||
void unregisterServer();
|
||||
void createServerIdFile();
|
||||
void updatePlayerList();
|
||||
void updateServerOwner();
|
||||
|
||||
public:
|
||||
ServerLobby();
|
||||
virtual ~ServerLobby();
|
||||
|
@ -34,9 +34,9 @@ enum SoccerTeam
|
||||
};
|
||||
|
||||
/** Game difficulty per player. */
|
||||
enum PerPlayerDifficulty
|
||||
enum PerPlayerDifficulty : uint8_t
|
||||
{
|
||||
PLAYER_DIFFICULTY_NORMAL,
|
||||
PLAYER_DIFFICULTY_NORMAL = 0,
|
||||
PLAYER_DIFFICULTY_HANDICAP,
|
||||
PLAYER_DIFFICULTY_COUNT
|
||||
};
|
||||
@ -51,7 +51,7 @@ class RemoteKartInfo
|
||||
SoccerTeam m_soccer_team;
|
||||
bool m_network_player;
|
||||
PerPlayerDifficulty m_difficulty;
|
||||
|
||||
float m_default_kart_color;
|
||||
public:
|
||||
RemoteKartInfo(int player_id, const std::string& kart_name,
|
||||
const irr::core::stringw& user_name, int host_id,
|
||||
@ -75,6 +75,7 @@ public:
|
||||
void setGlobalPlayerId(int id) { m_global_player_id = id; }
|
||||
void setSoccerTeam(SoccerTeam team) { m_soccer_team = team; }
|
||||
void setNetworkPlayer(bool value) { m_network_player = value; }
|
||||
void setDefaultKartColor(float value) { m_default_kart_color = value; }
|
||||
void setPerPlayerDifficulty(PerPlayerDifficulty value)
|
||||
{ m_difficulty = value; }
|
||||
int getHostId() const { return m_host_id; }
|
||||
@ -85,6 +86,7 @@ public:
|
||||
const irr::core::stringw& getPlayerName() const { return m_user_name; }
|
||||
SoccerTeam getSoccerTeam() const { return m_soccer_team; }
|
||||
PerPlayerDifficulty getDifficulty() const { return m_difficulty; }
|
||||
float getDefaultKartColor() const { return m_default_kart_color; }
|
||||
|
||||
bool operator<(const RemoteKartInfo& other) const
|
||||
{
|
||||
|
@ -262,7 +262,6 @@ void STKHost::create(std::shared_ptr<Server> server, SeparateProcess* p)
|
||||
*/
|
||||
STKHost::STKHost(std::shared_ptr<Server> server)
|
||||
{
|
||||
m_next_unique_host_id = -1;
|
||||
// Will be overwritten with the correct value once a connection with the
|
||||
// server is made.
|
||||
m_host_id = 0;
|
||||
@ -291,16 +290,14 @@ STKHost::STKHost(std::shared_ptr<Server> server)
|
||||
STKHost::STKHost(const irr::core::stringw &server_name)
|
||||
{
|
||||
init();
|
||||
// The host id will be increased whenever a new peer is added, so the
|
||||
// first client will have host id 1 (host id 0 is the server).
|
||||
m_next_unique_host_id = 0;
|
||||
m_host_id = 0; // indicates a server host.
|
||||
|
||||
ENetAddress addr;
|
||||
addr.host = STKHost::HOST_ANY;
|
||||
addr.port = NetworkConfig::get()->getServerPort();
|
||||
|
||||
m_network = new Network(NetworkConfig::get()->getMaxPlayers(),
|
||||
// Reserver 1 peer to handle full server message
|
||||
m_network = new Network(NetworkConfig::get()->getMaxPlayers() + 1,
|
||||
/*channel_limit*/2,
|
||||
/*max_in_bandwidth*/0,
|
||||
/*max_out_bandwidth*/ 0, &addr,
|
||||
@ -320,6 +317,7 @@ STKHost::STKHost(const irr::core::stringw &server_name)
|
||||
void STKHost::init()
|
||||
{
|
||||
m_shutdown = false;
|
||||
m_authorised = false;
|
||||
m_network = NULL;
|
||||
m_game_setup = NULL;
|
||||
m_exit_timeout.store(std::numeric_limits<double>::max());
|
||||
@ -627,13 +625,14 @@ GameSetup* STKHost::setupNewGame()
|
||||
void STKHost::disconnectAllPeers(bool timeout_waiting)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_peers_mutex);
|
||||
if (!m_peers.empty())
|
||||
if (!m_peers.empty() && timeout_waiting)
|
||||
{
|
||||
for (auto peer : m_peers)
|
||||
peer.second->disconnect();
|
||||
// Wait for at most 2 seconds for disconnect event to be generated
|
||||
if (timeout_waiting)
|
||||
m_exit_timeout.store(StkTime::getRealTime() + 2.0);
|
||||
m_peers.clear();
|
||||
m_exit_timeout.store(StkTime::getRealTime() + 2.0);
|
||||
}
|
||||
m_peers.clear();
|
||||
} // disconnectAllPeers
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -694,23 +693,6 @@ void STKHost::stopListening()
|
||||
m_listening_thread.join();
|
||||
} // stopListening
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns true if this client instance is allowed to control the server.
|
||||
* A client can authorise itself by providing the server's password. It is
|
||||
* then allowed to control the server (e.g. start kart selection).
|
||||
* The information if this client was authorised by the server is actually
|
||||
* stored in the peer (which is the server peer on a client).
|
||||
*/
|
||||
bool STKHost::isAuthorisedToControl() const
|
||||
{
|
||||
assert(NetworkConfig::get()->isClient());
|
||||
// If we are not properly connected (i.e. only enet connection, but not
|
||||
// stk logic), no peer is authorised.
|
||||
if(m_peers.size()==0)
|
||||
return false;
|
||||
return m_peers.begin()->second->isAuthorised();
|
||||
} // isAuthorisedToControl
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** \brief Thread function checking if data is received.
|
||||
* This function tries to get data from network low-level functions as
|
||||
@ -767,6 +749,14 @@ void STKHost::mainLoop()
|
||||
case ECT_DISCONNECT:
|
||||
enet_peer_disconnect(std::get<0>(p), std::get<2>(p));
|
||||
break;
|
||||
case ECT_RESET:
|
||||
// Flush enet before reset (so previous command is send)
|
||||
enet_host_flush(host);
|
||||
enet_peer_reset(std::get<0>(p));
|
||||
// Remove the stk peer of it
|
||||
std::lock_guard<std::mutex> lock(m_peers_mutex);
|
||||
m_peers.erase(std::get<0>(p));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -778,8 +768,8 @@ void STKHost::mainLoop()
|
||||
Event* stk_event = NULL;
|
||||
if (event.type == ENET_EVENT_TYPE_CONNECT)
|
||||
{
|
||||
auto stk_peer =
|
||||
std::make_shared<STKPeer>(event.peer, this);
|
||||
auto stk_peer = std::make_shared<STKPeer>
|
||||
(event.peer, this, m_next_unique_host_id++);
|
||||
std::unique_lock<std::mutex> lock(m_peers_mutex);
|
||||
m_peers[event.peer] = stk_peer;
|
||||
lock.unlock();
|
||||
@ -1026,3 +1016,30 @@ void STKHost::sendToServer(NetworkString *data, bool reliable)
|
||||
assert(NetworkConfig::get()->isClient());
|
||||
m_peers.begin()->second->sendPacket(data, reliable);
|
||||
} // sendToServer
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
std::vector<std::shared_ptr<NetworkPlayerProfile> >
|
||||
STKHost::getAllPlayerProfiles() const
|
||||
{
|
||||
std::vector<std::shared_ptr<NetworkPlayerProfile> > p;
|
||||
std::unique_lock<std::mutex> lock(m_peers_mutex);
|
||||
for (auto peer : m_peers)
|
||||
{
|
||||
auto peer_profile = peer.second->getPlayerProfiles();
|
||||
p.insert(p.end(), peer_profile.begin(), peer_profile.end());
|
||||
}
|
||||
lock.unlock();
|
||||
return p;
|
||||
} // getAllPlayerProfiles
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
std::shared_ptr<STKPeer> STKHost::findPeerByHostId(uint32_t id) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_peers_mutex);
|
||||
auto ret = std::find_if(m_peers.begin(), m_peers.end(),
|
||||
[id](const std::pair<ENetPeer*, std::shared_ptr<STKPeer> >& p)
|
||||
{
|
||||
return p.second->getHostId() == id;
|
||||
});
|
||||
return ret != m_peers.end() ? ret->second : nullptr;
|
||||
} // findPeerByHostId
|
||||
|
@ -50,7 +50,8 @@ class SeparateProcess;
|
||||
enum ENetCommandType : unsigned int
|
||||
{
|
||||
ECT_SEND_PACKET = 0,
|
||||
ECT_DISCONNECT = 1
|
||||
ECT_DISCONNECT = 1,
|
||||
ECT_RESET = 2
|
||||
};
|
||||
|
||||
class STKHost
|
||||
@ -80,7 +81,7 @@ private:
|
||||
std::thread m_network_console;
|
||||
|
||||
/** Make sure the removing or adding a peer is thread-safe. */
|
||||
std::mutex m_peers_mutex;
|
||||
mutable std::mutex m_peers_mutex;
|
||||
|
||||
/** Let (atm enet_peer_send and enet_peer_disconnect) run in the listening
|
||||
* thread. */
|
||||
@ -98,10 +99,10 @@ private:
|
||||
* getPeer()), but not decreased whena host (=peer) disconnects. This
|
||||
* results in a unique host id for each host, even when a host should
|
||||
* disconnect and then reconnect. */
|
||||
int m_next_unique_host_id;
|
||||
uint32_t m_next_unique_host_id = 0;
|
||||
|
||||
/** Host id of this host. */
|
||||
uint8_t m_host_id;
|
||||
uint32_t m_host_id = 0;
|
||||
|
||||
/** Stores data about the online game to play. */
|
||||
GameSetup* m_game_setup;
|
||||
@ -113,6 +114,9 @@ private:
|
||||
* triggers a shutdown of the STKHost (and the Protocolmanager). */
|
||||
std::atomic_bool m_shutdown;
|
||||
|
||||
/** True if this local host is authorised to control a server. */
|
||||
std::atomic_bool m_authorised;
|
||||
|
||||
/** Use as a timeout to waiting a disconnect event when exiting. */
|
||||
std::atomic<double> m_exit_timeout;
|
||||
|
||||
@ -142,7 +146,6 @@ public:
|
||||
* a crash in release mode on windows (see #1529). */
|
||||
static bool m_enable_console;
|
||||
|
||||
|
||||
/** Creates the STKHost. It takes all confifguration parameters from
|
||||
* NetworkConfig. This STKHost can either be a client or a server.
|
||||
*/
|
||||
@ -199,7 +202,21 @@ public:
|
||||
void shutdown();
|
||||
//-------------------------------------------------------------------------
|
||||
void sendPacketToAllPeers(NetworkString *data, bool reliable = true);
|
||||
//-------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns true if this client instance is allowed to control the server.
|
||||
* It will auto transfer ownership if previous server owner disconnected.
|
||||
*/
|
||||
bool isAuthorisedToControl() const { return m_authorised.load(); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets if this local host is authorised to control the server. */
|
||||
void setAuthorisedToControl(bool authorised)
|
||||
{ m_authorised.store(authorised); }
|
||||
// ------------------------------------------------------------------------
|
||||
std::vector<std::shared_ptr<NetworkPlayerProfile> >
|
||||
getAllPlayerProfiles() const;
|
||||
// ------------------------------------------------------------------------
|
||||
std::shared_ptr<STKPeer> findPeerByHostId(uint32_t id) const;
|
||||
// ------------------------------------------------------------------------
|
||||
void sendPacketExcept(STKPeer* peer,
|
||||
NetworkString *data,
|
||||
bool reliable = true);
|
||||
@ -213,8 +230,6 @@ public:
|
||||
std::shared_ptr<STKPeer> getServerPeerForClient() const;
|
||||
std::vector<NetworkPlayerProfile*> getMyPlayerProfiles();
|
||||
void setErrorMessage(const irr::core::stringw &message);
|
||||
bool isAuthorisedToControl() const;
|
||||
//-------------------------------------------------------------------------
|
||||
void addEnetCommand(ENetPeer* peer, ENetPacket* packet, uint32_t i,
|
||||
ENetCommandType ect)
|
||||
{
|
||||
@ -247,7 +262,7 @@ public:
|
||||
} // sendRawPacket
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a copied list of peers. */
|
||||
std::vector<std::shared_ptr<STKPeer> > getPeers()
|
||||
std::vector<std::shared_ptr<STKPeer> > getPeers() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_peers_mutex);
|
||||
std::vector<std::shared_ptr<STKPeer> > peers;
|
||||
@ -266,17 +281,17 @@ public:
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the number of currently connected peers. */
|
||||
unsigned int getPeerCount()
|
||||
unsigned int getPeerCount() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_peers_mutex);
|
||||
return m_peers.size();
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the global host id of this host. */
|
||||
void setMyHostId(uint8_t my_host_id) { m_host_id = my_host_id; }
|
||||
/** Sets the global host id of this host (client use). */
|
||||
void setMyHostId(uint32_t my_host_id) { m_host_id = my_host_id; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the host id of this host. */
|
||||
uint8_t getMyHostId() const { return m_host_id; }
|
||||
uint32_t getMyHostId() const { return m_host_id; }
|
||||
// ------------------------------------------------------------------------
|
||||
void sendToServer(NetworkString *data, bool reliable = true);
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -29,27 +29,24 @@
|
||||
|
||||
/** Constructor for an empty peer.
|
||||
*/
|
||||
STKPeer::STKPeer(ENetPeer *enet_peer, STKHost* host)
|
||||
STKPeer::STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id)
|
||||
: m_peer_address(enet_peer->address), m_host(host)
|
||||
{
|
||||
m_enet_peer = enet_peer;
|
||||
m_is_authorised = false;
|
||||
m_client_server_token = 0;
|
||||
m_host_id = 0;
|
||||
m_host_id = host_id;
|
||||
m_token_set = false;
|
||||
} // STKPeer
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Destructor.
|
||||
*/
|
||||
STKPeer::~STKPeer()
|
||||
void STKPeer::disconnect()
|
||||
{
|
||||
TransportAddress a(m_enet_peer->address);
|
||||
if (m_enet_peer->state != ENET_PEER_STATE_CONNECTED ||
|
||||
a != m_peer_address)
|
||||
return;
|
||||
m_host->addEnetCommand(m_enet_peer, NULL, PDI_NORMAL, ECT_DISCONNECT);
|
||||
} // ~STKPeer
|
||||
} // disconnect
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Kick this peer (used by server).
|
||||
@ -63,6 +60,18 @@ void STKPeer::kick()
|
||||
m_host->addEnetCommand(m_enet_peer, NULL, PDI_KICK, ECT_DISCONNECT);
|
||||
} // kick
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Forcefully disconnects a peer (used by server).
|
||||
*/
|
||||
void STKPeer::reset()
|
||||
{
|
||||
TransportAddress a(m_enet_peer->address);
|
||||
if (m_enet_peer->state != ENET_PEER_STATE_CONNECTED ||
|
||||
a != m_peer_address)
|
||||
return;
|
||||
m_host->addEnetCommand(m_enet_peer, NULL, 0, ECT_RESET);
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Sends a packet to this host.
|
||||
* \param data The data to send.
|
||||
@ -111,14 +120,3 @@ bool STKPeer::isSamePeer(const ENetPeer* peer) const
|
||||
{
|
||||
return peer==m_enet_peer;
|
||||
} // isSamePeer
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns the list of all player profiles connected to this peer. Note that
|
||||
* this function is somewhat expensive (it loops over all network profiles
|
||||
* to find the ones with the same host id as this peer.
|
||||
*/
|
||||
std::vector<NetworkPlayerProfile*> STKPeer::getAllPlayerProfiles()
|
||||
{
|
||||
return m_host->getGameSetup()->getAllPlayersOnHost(getHostId());
|
||||
} // getAllPlayerProfiles
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include <enet/enet.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class NetworkPlayerProfile;
|
||||
@ -62,26 +63,38 @@ protected:
|
||||
/** Host id of this peer. */
|
||||
int m_host_id;
|
||||
|
||||
/** True if this peer is authorised to control a server. */
|
||||
bool m_is_authorised;
|
||||
|
||||
TransportAddress m_peer_address;
|
||||
|
||||
STKHost* m_host;
|
||||
|
||||
std::vector<std::shared_ptr<NetworkPlayerProfile> > m_players;
|
||||
|
||||
public:
|
||||
STKPeer(ENetPeer *enet_peer, STKHost* host);
|
||||
~STKPeer();
|
||||
STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id);
|
||||
~STKPeer() {}
|
||||
// ------------------------------------------------------------------------
|
||||
void sendPacket(NetworkString *data, bool reliable = true);
|
||||
// ------------------------------------------------------------------------
|
||||
void disconnect();
|
||||
// ------------------------------------------------------------------------
|
||||
void kick();
|
||||
// ------------------------------------------------------------------------
|
||||
void reset();
|
||||
// ------------------------------------------------------------------------
|
||||
bool isConnected() const;
|
||||
const TransportAddress& getAddress() const { return m_peer_address; }
|
||||
bool isSamePeer(const STKPeer* peer) const;
|
||||
bool isSamePeer(const ENetPeer* peer) const;
|
||||
std::vector<NetworkPlayerProfile*> getAllPlayerProfiles();
|
||||
// ------------------------------------------------------------------------
|
||||
std::vector<std::shared_ptr<NetworkPlayerProfile> >
|
||||
getPlayerProfiles() const { return m_players; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool hasPlayerProfiles() const { return !m_players.empty(); }
|
||||
// ------------------------------------------------------------------------
|
||||
void cleanPlayerProfiles() { m_players.clear(); }
|
||||
// ------------------------------------------------------------------------
|
||||
void addPlayer(std::shared_ptr<NetworkPlayerProfile> p)
|
||||
{ m_players.push_back(p); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the token for this client. */
|
||||
void setClientServerToken(const uint32_t& token)
|
||||
@ -90,7 +103,11 @@ public:
|
||||
m_token_set = true;
|
||||
} // setClientServerToken
|
||||
// ------------------------------------------------------------------------
|
||||
void unsetClientServerToken() { m_token_set = false; }
|
||||
void unsetClientServerToken()
|
||||
{
|
||||
m_token_set = false;
|
||||
m_client_server_token = 0;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the token of this client. */
|
||||
uint32_t getClientServerToken() const { return m_client_server_token; }
|
||||
@ -98,21 +115,9 @@ public:
|
||||
/** Returns if the token for this client is known. */
|
||||
bool isClientServerTokenSet() const { return m_token_set; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the host if of this peer. */
|
||||
void setHostId(int host_id) { m_host_id = host_id; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the host id of this peer. */
|
||||
int getHostId() const { return m_host_id; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets if this peer is authorised to control the server. */
|
||||
void setAuthorised(bool authorised) { m_is_authorised = authorised; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if this peer is authorised to control the server. The server
|
||||
* uses this to check if a peer is allowed certain commands; and a client
|
||||
* uses this function (in which case this peer is actually the server
|
||||
* peer) to see if this client is allowed certain command (i.e. to
|
||||
* display additional GUI elements). */
|
||||
bool isAuthorised() const { return m_is_authorised; }
|
||||
uint32_t getHostId() const { return m_host_id; }
|
||||
|
||||
}; // STKPeer
|
||||
|
||||
#endif // STK_PEER_HPP
|
||||
|
@ -96,10 +96,6 @@ namespace Online
|
||||
return m_online_state;
|
||||
} // getOnlineState
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
/** Returns a pointer to the profile associated with the current user. */
|
||||
OnlineProfile* getProfile() const { return m_profile; }
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
/** Returns the session token of the signed in user. */
|
||||
const std::string& getToken() const { return m_token; }
|
||||
@ -113,6 +109,9 @@ namespace Online
|
||||
OnlinePlayerProfile(const core::stringw &name, bool is_guest = false);
|
||||
virtual ~OnlinePlayerProfile() {}
|
||||
// ----------------------------------------------------------------
|
||||
/** Returns a pointer to the profile associated with the current user. */
|
||||
OnlineProfile* getProfile() const { return m_profile; }
|
||||
// ----------------------------------------------------------------
|
||||
}; // class OnlinePlayerProfile
|
||||
} // namespace Online
|
||||
#endif // HEADER_CURRENT_ONLINE_USER_HPP
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include "input/input_manager.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_player_profile.hpp"
|
||||
#include "network/protocols/client_lobby.hpp"
|
||||
#include "network/protocols/server_lobby.hpp"
|
||||
#include "network/server.hpp"
|
||||
@ -262,16 +261,25 @@ void NetworkingLobby::onDialogClose()
|
||||
} // onDialogClose()
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkingLobby::addPlayer(NetworkPlayerProfile *profile)
|
||||
void NetworkingLobby::addPlayer(const std::tuple<uint32_t, uint32_t,
|
||||
core::stringw, bool>& p)
|
||||
{
|
||||
// In GUI-less server this function will be called without proper
|
||||
// initialisation
|
||||
if(m_player_list)
|
||||
m_player_list->addItem(StringUtils::toString(profile->getGlobalPlayerId()),
|
||||
profile->getName());
|
||||
if (m_player_list)
|
||||
{
|
||||
const std::string internal_name =
|
||||
StringUtils::toString(std::get<0>(p)) + "_" +
|
||||
StringUtils::toString(std::get<1>(p));
|
||||
m_player_list->addItem(internal_name, std::get<2>(p));
|
||||
if (std::get<3>(p))
|
||||
m_player_list->markItemRed(internal_name, true);
|
||||
}
|
||||
} // addPlayer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkingLobby::removePlayer(NetworkPlayerProfile *profile)
|
||||
void NetworkingLobby::cleanPlayers()
|
||||
{
|
||||
} // removePlayer
|
||||
if (m_player_list)
|
||||
m_player_list->clear();
|
||||
} // cleanPlayers
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "guiengine/screen.hpp"
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
||||
class Server;
|
||||
|
||||
@ -32,8 +33,6 @@ namespace GUIEngine
|
||||
class TextBoxWidget;
|
||||
}
|
||||
|
||||
class NetworkPlayerProfile;
|
||||
|
||||
/**
|
||||
* \brief Handles the main menu
|
||||
* \ingroup states_screens
|
||||
@ -91,8 +90,9 @@ public:
|
||||
/** Used to insert each client chat message (reserved). */
|
||||
void addMoreServerInfo(const core::stringw& info);
|
||||
void setJoinedServer(std::shared_ptr<Server> server);
|
||||
void addPlayer(NetworkPlayerProfile *profile);
|
||||
void removePlayer(NetworkPlayerProfile *profile);
|
||||
void addPlayer(const std::tuple<uint32_t/*host id*/, uint32_t/*online id*/,
|
||||
core::stringw/*player name*/, bool/*is server owner*/>& p);
|
||||
void cleanPlayers();
|
||||
}; // class NetworkingLobby
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user