Add support for joining server with ongoing game
This commit is contained in:
parent
8a579d9542
commit
2199679ac2
@ -48,14 +48,20 @@ void GameSetup::update(bool remove_disconnected_players)
|
||||
{
|
||||
return npp.expired();
|
||||
}), m_players.end());
|
||||
m_connected_players_count.store((uint32_t)m_players.size());
|
||||
return;
|
||||
}
|
||||
if (!World::getWorld() ||
|
||||
World::getWorld()->getPhase() < WorldStatus::MUSIC_PHASE)
|
||||
{
|
||||
m_connected_players_count.store((uint32_t)m_players.size());
|
||||
return;
|
||||
}
|
||||
lock.unlock();
|
||||
if (!World::getWorld() ||
|
||||
World::getWorld()->getPhase() < WorldStatus::MUSIC_PHASE)
|
||||
return;
|
||||
|
||||
int red_count = 0;
|
||||
int blue_count = 0;
|
||||
unsigned total = 0;
|
||||
for (uint8_t i = 0; i < (uint8_t)m_players.size(); i++)
|
||||
{
|
||||
bool disconnected = m_players[i].expired();
|
||||
@ -67,7 +73,10 @@ void GameSetup::update(bool remove_disconnected_players)
|
||||
blue_count++;
|
||||
|
||||
if (!disconnected)
|
||||
{
|
||||
total++;
|
||||
continue;
|
||||
}
|
||||
AbstractKart* k = World::getWorld()->getKart(i);
|
||||
if (!k->isEliminated())
|
||||
{
|
||||
@ -82,6 +91,8 @@ void GameSetup::update(bool remove_disconnected_players)
|
||||
STKHost::get()->sendPacketToAllPeers(&p, true);
|
||||
}
|
||||
}
|
||||
m_connected_players_count.store(total);
|
||||
|
||||
if (m_players.size() != 1 && World::getWorld()->hasTeam() &&
|
||||
(red_count == 0 || blue_count == 0))
|
||||
World::getWorld()->setUnfairTeam(true);
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "network/remote_kart_info.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@ -58,10 +59,13 @@ private:
|
||||
|
||||
float m_battle_time_limit;
|
||||
|
||||
std::atomic<uint32_t> m_connected_players_count;
|
||||
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
GameSetup()
|
||||
{
|
||||
m_connected_players_count.store(0);
|
||||
m_extra_server_info = -1;
|
||||
reset();
|
||||
}
|
||||
@ -99,11 +103,7 @@ public:
|
||||
} // getConnectedPlayers
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the number of connected players. */
|
||||
unsigned getPlayerCount()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_players_mutex);
|
||||
return (unsigned)m_players.size();
|
||||
}
|
||||
unsigned getPlayerCount() { return m_connected_players_count.load(); }
|
||||
// ------------------------------------------------------------------------
|
||||
void setRace(const std::string& track, unsigned laps, bool reverse)
|
||||
{
|
||||
|
@ -111,9 +111,9 @@ void Protocol::requestTerminate()
|
||||
} // requestTerminate
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sends a message to all peers, encrypt the message if needed.
|
||||
* The message is composed of a 1-byte message (usually the message type)
|
||||
* followed by the actual message.
|
||||
/** Sends a message to all validated peers in game, encrypt the message if
|
||||
* needed. The message is composed of a 1-byte message (usually the message
|
||||
* type) followed by the actual message.
|
||||
* \param message The actual message content.
|
||||
*/
|
||||
void Protocol::sendMessageToPeers(NetworkString *message, bool reliable)
|
||||
@ -121,6 +121,18 @@ void Protocol::sendMessageToPeers(NetworkString *message, bool reliable)
|
||||
STKHost::get()->sendPacketToAllPeers(message, reliable);
|
||||
} // sendMessageToPeers
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sends a message to all validated peers in server, encrypt the message if
|
||||
* needed. The message is composed of a 1-byte message (usually the message
|
||||
* type) followed by the actual message.
|
||||
* \param message The actual message content.
|
||||
*/
|
||||
void Protocol::sendMessageToPeersInServer(NetworkString* message,
|
||||
bool reliable)
|
||||
{
|
||||
STKHost::get()->sendPacketToAllPeersInServer(message, reliable);
|
||||
} // sendMessageToPeersInServer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sends a message from a client to the server.
|
||||
*/
|
||||
|
@ -126,6 +126,8 @@ public:
|
||||
NetworkString* getNetworkString(size_t capacity = 16);
|
||||
bool checkDataSize(Event* event, unsigned int minimum_size);
|
||||
void sendMessageToPeers(NetworkString *message, bool reliable = true);
|
||||
void sendMessageToPeersInServer(NetworkString *message,
|
||||
bool reliable = true);
|
||||
void sendToServer(NetworkString *message, bool reliable = true);
|
||||
void requestStart();
|
||||
void requestPause();
|
||||
|
@ -72,6 +72,7 @@ engine.
|
||||
ClientLobby::ClientLobby(const TransportAddress& a, std::shared_ptr<Server> s)
|
||||
: LobbyProtocol(NULL)
|
||||
{
|
||||
m_waiting_for_game.store(false);
|
||||
m_state.store(NONE);
|
||||
m_server_address = a;
|
||||
m_server = s;
|
||||
@ -626,6 +627,16 @@ void ClientLobby::updatePlayerList(Event* event)
|
||||
{
|
||||
if (!checkDataSize(event, 1)) return;
|
||||
NetworkString& data = event->data();
|
||||
bool waiting = data.getUInt8() == 1;
|
||||
if (m_waiting_for_game.load() && !waiting)
|
||||
{
|
||||
// The waiting game finished
|
||||
NetworkingLobby::getInstance()
|
||||
->addMoreServerInfo(L"--------------------");
|
||||
SFXManager::get()->quickSound("wee");
|
||||
}
|
||||
|
||||
m_waiting_for_game.store(waiting);
|
||||
unsigned player_count = data.getUInt8();
|
||||
std::vector<std::tuple<uint32_t, uint32_t, uint32_t, core::stringw,
|
||||
int, KartTeam> > players;
|
||||
@ -637,9 +648,13 @@ void ClientLobby::updatePlayerList(Event* event)
|
||||
std::get<1>(pl) = data.getUInt32();
|
||||
std::get<2>(pl) = data.getUInt8();
|
||||
data.decodeStringW(&std::get<3>(pl));
|
||||
bool is_peer_waiting_for_game = data.getUInt8() == 1;
|
||||
bool is_peer_server_owner = data.getUInt8() == 1;
|
||||
// icon to be used, see NetworkingLobby::loadedFromFile
|
||||
std::get<4>(pl) = data.getUInt8() == 1 /*if server owner*/ ? 0 :
|
||||
std::get<4>(pl) = is_peer_server_owner ? 0 :
|
||||
std::get<1>(pl) != 0 /*if online account*/ ? 1 : 2;
|
||||
if (waiting && !is_peer_waiting_for_game)
|
||||
std::get<4>(pl) = 3;
|
||||
PerPlayerDifficulty d = (PerPlayerDifficulty)data.getUInt8();
|
||||
if (d == PLAYER_DIFFICULTY_HANDICAP)
|
||||
std::get<3>(pl) = _("%s (handicapped)", std::get<3>(pl));
|
||||
|
@ -71,6 +71,8 @@ private:
|
||||
EXITING
|
||||
};
|
||||
|
||||
std::atomic_bool m_waiting_for_game;
|
||||
|
||||
/** The state of the finite state machine. */
|
||||
std::atomic<ClientState> m_state;
|
||||
|
||||
@ -100,13 +102,13 @@ public:
|
||||
virtual void finishedLoadingWorld() OVERRIDE;
|
||||
virtual void setup() OVERRIDE;
|
||||
virtual void update(int ticks) OVERRIDE;
|
||||
virtual bool waitingForPlayers() const OVERRIDE
|
||||
{ return m_state.load() == CONNECTED; }
|
||||
virtual void asynchronousUpdate() OVERRIDE {}
|
||||
virtual bool allPlayersReady() const OVERRIDE
|
||||
{ return m_state.load() >= RACING; }
|
||||
bool waitingForServerRespond() const
|
||||
{ return m_state.load() == REQUESTING_CONNECTION; }
|
||||
bool isLobbyReady() const { return m_state.load() == CONNECTED; }
|
||||
bool isWaitingForGame() const { return m_waiting_for_game.load(); }
|
||||
virtual bool isRacing() const OVERRIDE { return m_state.load() == RACING; }
|
||||
|
||||
};
|
||||
|
@ -125,7 +125,6 @@ public:
|
||||
virtual void update(int ticks) = 0;
|
||||
virtual void finishedLoadingWorld() = 0;
|
||||
virtual void loadWorld();
|
||||
virtual bool waitingForPlayers() const = 0;
|
||||
virtual bool allPlayersReady() const = 0;
|
||||
virtual bool isRacing() const = 0;
|
||||
GameSetup* getGameSetup() const { return m_game_setup; }
|
||||
|
@ -61,12 +61,12 @@
|
||||
node [shape=ellipse,style=filled,color=lightgrey];
|
||||
|
||||
"Server Constructor" -> "INIT_WAN" [label="If WAN game"]
|
||||
"Server Constructor" -> "ACCEPTING_CLIENTS" [label="If LAN game"]
|
||||
"Server Constructor" -> "WAITING_FOR_START_GAME" [label="If LAN game"]
|
||||
"INIT_WAN" -> "GETTING_PUBLIC_ADDRESS" [label="GetPublicAddress protocol callback"]
|
||||
"GETTING_PUBLIC_ADDRESS" -> "ACCEPTING_CLIENTS" [label="Register server"]
|
||||
"ACCEPTING_CLIENTS" -> "connectionRequested" [label="Client connection request"]
|
||||
"connectionRequested" -> "ACCEPTING_CLIENTS"
|
||||
"ACCEPTING_CLIENTS" -> "SELECTING" [label="Start race from authorised client"]
|
||||
"GETTING_PUBLIC_ADDRESS" -> "WAITING_FOR_START_GAME" [label="Register server"]
|
||||
"WAITING_FOR_START_GAME" -> "connectionRequested" [label="Client connection request"]
|
||||
"connectionRequested" -> "WAITING_FOR_START_GAME"
|
||||
"WAITING_FOR_START_GAME" -> "SELECTING" [label="Start race from authorised client"]
|
||||
"SELECTING" -> "SELECTING" [label="Client selects kart, #laps, ..."]
|
||||
"SELECTING" -> "playerTrackVote" [label="Client selected track"]
|
||||
"playerTrackVote" -> "SELECTING" [label="Not all clients have selected"]
|
||||
@ -90,7 +90,9 @@
|
||||
*/
|
||||
ServerLobby::ServerLobby() : LobbyProtocol(NULL)
|
||||
{
|
||||
m_waiting_players_counts.store(0);
|
||||
m_server_owner_id.store(-1);
|
||||
m_registered_for_once_only = false;
|
||||
m_has_created_server_id_file = false;
|
||||
setHandleDisconnections(true);
|
||||
m_state = SET_PUBLIC_ADDRESS;
|
||||
@ -253,7 +255,19 @@ void ServerLobby::handleChat(Event* event)
|
||||
NetworkString* chat = getNetworkString();
|
||||
chat->setSynchronous(true);
|
||||
chat->addUInt8(LE_CHAT).encodeString16(message);
|
||||
sendMessageToPeers(chat, /*reliable*/true);
|
||||
// After game is started, only send to waiting player
|
||||
const bool game_started = m_state.load() != WAITING_FOR_START_GAME;
|
||||
STKHost::get()->sendPacketToAllPeersWith([game_started]
|
||||
(STKPeer* p)
|
||||
{
|
||||
if (!p->isValidated())
|
||||
return false;
|
||||
if (!game_started)
|
||||
return true;
|
||||
if (!p->isWaitingForGame() && game_started)
|
||||
return false;
|
||||
return true;
|
||||
}, chat);
|
||||
delete chat;
|
||||
}
|
||||
} // handleChat
|
||||
@ -341,6 +355,17 @@ void ServerLobby::asynchronousUpdate()
|
||||
// Check if server owner has left
|
||||
updateServerOwner();
|
||||
|
||||
if (allowJoinedPlayersWaiting() || (m_game_setup->isGrandPrix() &&
|
||||
m_state.load() == WAITING_FOR_START_GAME))
|
||||
{
|
||||
updateWaitingPlayers();
|
||||
clearDisconnectedRankedPlayer();
|
||||
// Only poll the STK server if this is a WAN server.
|
||||
if (NetworkConfig::get()->isWAN())
|
||||
checkIncomingConnectionRequests();
|
||||
handlePendingConnection();
|
||||
}
|
||||
|
||||
switch (m_state.load())
|
||||
{
|
||||
case SET_PUBLIC_ADDRESS:
|
||||
@ -349,7 +374,7 @@ void ServerLobby::asynchronousUpdate()
|
||||
// STK server, so we can directly go to the accepting clients state.
|
||||
if (NetworkConfig::get()->isLAN())
|
||||
{
|
||||
m_state = ACCEPTING_CLIENTS;
|
||||
m_state = WAITING_FOR_START_GAME;
|
||||
STKHost::get()->startListening();
|
||||
createServerIdFile();
|
||||
return;
|
||||
@ -369,9 +394,9 @@ void ServerLobby::asynchronousUpdate()
|
||||
}
|
||||
case REGISTER_SELF_ADDRESS:
|
||||
{
|
||||
if (m_game_setup->isGrandPrixStarted())
|
||||
if (m_game_setup->isGrandPrixStarted() || m_registered_for_once_only)
|
||||
{
|
||||
m_state = ACCEPTING_CLIENTS;
|
||||
m_state = WAITING_FOR_START_GAME;
|
||||
break;
|
||||
}
|
||||
// Register this server with the STK server. This will block
|
||||
@ -379,7 +404,9 @@ void ServerLobby::asynchronousUpdate()
|
||||
// to react to any requests before the server is registered.
|
||||
if (registerServer())
|
||||
{
|
||||
m_state = ACCEPTING_CLIENTS;
|
||||
if (allowJoinedPlayersWaiting())
|
||||
m_registered_for_once_only = true;
|
||||
m_state = WAITING_FOR_START_GAME;
|
||||
createServerIdFile();
|
||||
}
|
||||
else
|
||||
@ -388,12 +415,12 @@ void ServerLobby::asynchronousUpdate()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACCEPTING_CLIENTS:
|
||||
case WAITING_FOR_START_GAME:
|
||||
{
|
||||
if (NetworkConfig::get()->isOwnerLess())
|
||||
{
|
||||
auto players = m_game_setup->getPlayers();
|
||||
if (((float)players.size() >=
|
||||
float player_size = (float)m_game_setup->getPlayerCount();
|
||||
if ((player_size >=
|
||||
(float)NetworkConfig::get()->getMaxPlayers() *
|
||||
UserConfigParams::m_start_game_threshold ||
|
||||
m_game_setup->isGrandPrixStarted()) &&
|
||||
@ -403,7 +430,7 @@ void ServerLobby::asynchronousUpdate()
|
||||
(int64_t)
|
||||
(UserConfigParams::m_start_game_counter * 1000.0f));
|
||||
}
|
||||
else if ((float)players.size() <
|
||||
else if (player_size <
|
||||
(float)NetworkConfig::get()->getMaxPlayers() *
|
||||
UserConfigParams::m_start_game_threshold &&
|
||||
!m_game_setup->isGrandPrixStarted())
|
||||
@ -416,11 +443,6 @@ void ServerLobby::asynchronousUpdate()
|
||||
return;
|
||||
}
|
||||
}
|
||||
clearDisconnectedRankedPlayer();
|
||||
// Only poll the STK server if this is a WAN server.
|
||||
if (NetworkConfig::get()->isWAN())
|
||||
checkIncomingConnectionRequests();
|
||||
handlePendingConnection();
|
||||
break;
|
||||
}
|
||||
case ERROR_LEAVE:
|
||||
@ -538,14 +560,12 @@ void ServerLobby::update(int ticks)
|
||||
RaceResultGUI::getInstance()->backToLobby();
|
||||
std::lock_guard<std::mutex> lock(m_connection_mutex);
|
||||
m_game_setup->stopGrandPrix();
|
||||
m_state = NetworkConfig::get()->isLAN() ?
|
||||
ACCEPTING_CLIENTS : REGISTER_SELF_ADDRESS;
|
||||
setup();
|
||||
resetServer();
|
||||
}
|
||||
|
||||
if ((m_state.load() > ACCEPTING_CLIENTS ||
|
||||
if ((m_state.load() > WAITING_FOR_START_GAME ||
|
||||
m_game_setup->isGrandPrixStarted()) &&
|
||||
STKHost::get()->getPeerCount() == 0 &&
|
||||
m_game_setup->getPlayerCount() == 0 &&
|
||||
NetworkConfig::get()->getServerIdFile().empty())
|
||||
{
|
||||
if (RaceEventManager::getInstance() &&
|
||||
@ -571,29 +591,20 @@ void ServerLobby::update(int ticks)
|
||||
delete exit_result_screen;
|
||||
std::lock_guard<std::mutex> lock(m_connection_mutex);
|
||||
m_game_setup->stopGrandPrix();
|
||||
m_state = NetworkConfig::get()->isLAN() ?
|
||||
ACCEPTING_CLIENTS : REGISTER_SELF_ADDRESS;
|
||||
updatePlayerList(true/*force_update*/);
|
||||
NetworkString* server_info = getNetworkString();
|
||||
server_info->setSynchronous(true);
|
||||
server_info->addUInt8(LE_SERVER_INFO);
|
||||
m_game_setup->addServerInfo(server_info);
|
||||
sendMessageToPeers(server_info);
|
||||
delete server_info;
|
||||
setup();
|
||||
resetServer();
|
||||
}
|
||||
|
||||
if (m_game_setup)
|
||||
{
|
||||
// Remove disconnected players if in these two states
|
||||
m_game_setup->update(m_state.load() == ACCEPTING_CLIENTS ||
|
||||
m_game_setup->update(m_state.load() == WAITING_FOR_START_GAME ||
|
||||
m_state.load() == SELECTING);
|
||||
}
|
||||
switch (m_state.load())
|
||||
{
|
||||
case SET_PUBLIC_ADDRESS:
|
||||
case REGISTER_SELF_ADDRESS:
|
||||
case ACCEPTING_CLIENTS:
|
||||
case WAITING_FOR_START_GAME:
|
||||
case WAIT_FOR_WORLD_LOADED:
|
||||
case WAIT_FOR_RACE_STARTED:
|
||||
{
|
||||
@ -645,16 +656,7 @@ void ServerLobby::update(int ticks)
|
||||
sendMessageToPeers(exit_result_screen, /*reliable*/true);
|
||||
delete exit_result_screen;
|
||||
std::lock_guard<std::mutex> lock(m_connection_mutex);
|
||||
m_state = NetworkConfig::get()->isLAN() ?
|
||||
ACCEPTING_CLIENTS : REGISTER_SELF_ADDRESS;
|
||||
updatePlayerList(true/*force_update*/);
|
||||
NetworkString* server_info = getNetworkString();
|
||||
server_info->setSynchronous(true);
|
||||
server_info->addUInt8(LE_SERVER_INFO);
|
||||
m_game_setup->addServerInfo(server_info);
|
||||
sendMessageToPeers(server_info);
|
||||
delete server_info;
|
||||
setup();
|
||||
resetServer();
|
||||
}
|
||||
break;
|
||||
case ERROR_LEAVE:
|
||||
@ -748,7 +750,7 @@ void ServerLobby::startSelection(const Event *event)
|
||||
{
|
||||
if (event != NULL)
|
||||
{
|
||||
if (m_state != ACCEPTING_CLIENTS)
|
||||
if (m_state != WAITING_FOR_START_GAME)
|
||||
{
|
||||
Log::warn("ServerLobby",
|
||||
"Received startSelection while being in state %d",
|
||||
@ -791,10 +793,13 @@ void ServerLobby::startSelection(const Event *event)
|
||||
}
|
||||
}
|
||||
|
||||
ProtocolManager::lock()->findAndTerminate(PROTOCOL_CONNECTION);
|
||||
if (NetworkConfig::get()->isWAN())
|
||||
if (!allowJoinedPlayersWaiting())
|
||||
{
|
||||
unregisterServer(false/*now*/);
|
||||
ProtocolManager::lock()->findAndTerminate(PROTOCOL_CONNECTION);
|
||||
if (NetworkConfig::get()->isWAN() )
|
||||
{
|
||||
unregisterServer(false/*now*/);
|
||||
}
|
||||
}
|
||||
|
||||
NetworkString *ns = getNetworkString(1);
|
||||
@ -809,7 +814,7 @@ void ServerLobby::startSelection(const Event *event)
|
||||
auto peers = STKHost::get()->getPeers();
|
||||
for (auto peer : peers)
|
||||
{
|
||||
if (!peer->isValidated())
|
||||
if (!peer->isValidated() || peer->isWaitingForGame())
|
||||
continue;
|
||||
peer->eraseServerKarts(m_available_kts.first, karts_erase);
|
||||
peer->eraseServerTracks(m_available_kts.second, tracks_erase);
|
||||
@ -855,16 +860,19 @@ void ServerLobby::startSelection(const Event *event)
|
||||
delete ns;
|
||||
|
||||
m_state = SELECTING;
|
||||
// Drop all pending players and keys
|
||||
for (auto& p : m_pending_connection)
|
||||
if (!allowJoinedPlayersWaiting())
|
||||
{
|
||||
if (auto peer = p.first.lock())
|
||||
peer->disconnect();
|
||||
// Drop all pending players and keys if doesn't allow joinning-waiting
|
||||
for (auto& p : m_pending_connection)
|
||||
{
|
||||
if (auto peer = p.first.lock())
|
||||
peer->disconnect();
|
||||
}
|
||||
m_pending_connection.clear();
|
||||
std::unique_lock<std::mutex> ul(m_keys_mutex);
|
||||
m_keys.clear();
|
||||
ul.unlock();
|
||||
}
|
||||
m_pending_connection.clear();
|
||||
std::unique_lock<std::mutex> ul(m_keys_mutex);
|
||||
m_keys.clear();
|
||||
ul.unlock();
|
||||
|
||||
// Will be changed after the first vote received
|
||||
m_timeout.store(std::numeric_limits<int64_t>::max());
|
||||
@ -916,7 +924,8 @@ void ServerLobby::checkIncomingConnectionRequests()
|
||||
const XMLNode * users_xml = result->getNode("users");
|
||||
std::map<uint32_t, KeyData> keys;
|
||||
auto sl = m_server_lobby.lock();
|
||||
if (!sl || sl->m_state.load() != ACCEPTING_CLIENTS)
|
||||
if (!sl || (sl->m_state.load() != WAITING_FOR_START_GAME &&
|
||||
!sl->allowJoinedPlayersWaiting()))
|
||||
return;
|
||||
|
||||
for (unsigned int i = 0; i < users_xml->getNumNodes(); i++)
|
||||
@ -956,7 +965,10 @@ void ServerLobby::checkIncomingConnectionRequests()
|
||||
const TransportAddress &addr = STKHost::get()->getPublicAddress();
|
||||
request->addParameter("address", addr.getIP() );
|
||||
request->addParameter("port", addr.getPort());
|
||||
request->addParameter("current-players", m_game_setup->getPlayerCount());
|
||||
request->addParameter("current-players",
|
||||
m_game_setup->getPlayerCount() + m_waiting_players_counts.load());
|
||||
request->addParameter("game-started",
|
||||
m_state.load() == WAITING_FOR_START_GAME ? 0 : 1);
|
||||
request->queue();
|
||||
|
||||
} // checkIncomingConnectionRequests
|
||||
@ -1236,6 +1248,8 @@ void ServerLobby::clientDisconnected(Event* event)
|
||||
return;
|
||||
|
||||
NetworkString* msg = getNetworkString(2);
|
||||
const bool waiting_peer_disconnected =
|
||||
event->getPeer()->isWaitingForGame();
|
||||
msg->setSynchronous(true);
|
||||
msg->addUInt8(LE_PLAYER_DISCONNECTED);
|
||||
msg->addUInt8((uint8_t)players_on_peer.size());
|
||||
@ -1245,7 +1259,17 @@ void ServerLobby::clientDisconnected(Event* event)
|
||||
msg->encodeString(name);
|
||||
Log::info("ServerLobby", "%s disconnected", name.c_str());
|
||||
}
|
||||
sendMessageToPeers(msg, /*reliable*/true);
|
||||
|
||||
// Don't show waiting peer disconnect message to in game player
|
||||
STKHost::get()->sendPacketToAllPeersWith([waiting_peer_disconnected]
|
||||
(STKPeer* p)
|
||||
{
|
||||
if (!p->isValidated())
|
||||
return false;
|
||||
if (!p->isWaitingForGame() && waiting_peer_disconnected)
|
||||
return false;
|
||||
return true;
|
||||
}, msg);
|
||||
updatePlayerList();
|
||||
delete msg;
|
||||
} // clientDisconnected
|
||||
@ -1281,8 +1305,9 @@ void ServerLobby::connectionRequested(Event* event)
|
||||
peer->cleanPlayerProfiles();
|
||||
|
||||
// can we add the player ?
|
||||
if (m_state != ACCEPTING_CLIENTS ||
|
||||
m_game_setup->isGrandPrixStarted())
|
||||
if (!allowJoinedPlayersWaiting() &&
|
||||
(m_state.load() != WAITING_FOR_START_GAME ||
|
||||
m_game_setup->isGrandPrixStarted()))
|
||||
{
|
||||
NetworkString *message = getNetworkString(2);
|
||||
message->setSynchronous(true);
|
||||
@ -1394,7 +1419,8 @@ void ServerLobby::connectionRequested(Event* event)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_game_setup->getPlayerCount() + player_count >
|
||||
if (m_game_setup->getPlayerCount() + player_count +
|
||||
m_waiting_players_counts.load() >
|
||||
NetworkConfig::get()->getMaxPlayers())
|
||||
{
|
||||
NetworkString *message = getNetworkString(2);
|
||||
@ -1415,7 +1441,8 @@ void ServerLobby::connectionRequested(Event* event)
|
||||
peer->getAddress().isLAN()) &&
|
||||
NetworkConfig::get()->isWAN() &&
|
||||
NetworkConfig::get()->onlyValidatedPlayers()) ||
|
||||
((player_count != 1 || m_scores.find(online_id) != m_scores.end()) &&
|
||||
((player_count != 1 || online_id == 0 ||
|
||||
m_scores.find(online_id) != m_scores.end()) &&
|
||||
NetworkConfig::get()->isRankedServer()))
|
||||
{
|
||||
NetworkString* message = getNetworkString(2);
|
||||
@ -1507,6 +1534,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr<STKPeer> peer,
|
||||
peer->sendPacket(server_info);
|
||||
delete server_info;
|
||||
|
||||
const bool game_started = m_state.load() != WAITING_FOR_START_GAME;
|
||||
NetworkString* message_ack = getNetworkString(4);
|
||||
message_ack->setSynchronous(true);
|
||||
// connection success -- return the host id of peer
|
||||
@ -1520,39 +1548,70 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr<STKPeer> peer,
|
||||
}
|
||||
message_ack->addUInt8(LE_CONNECTION_ACCEPTED).addUInt32(peer->getHostId())
|
||||
.addUInt32(NetworkConfig::m_server_version).addFloat(auto_start_timer);
|
||||
peer->sendPacket(message_ack);
|
||||
delete message_ack;
|
||||
|
||||
m_peers_ready[peer] = false;
|
||||
for (std::shared_ptr<NetworkPlayerProfile> npp : peer->getPlayerProfiles())
|
||||
if (game_started)
|
||||
{
|
||||
m_game_setup->addPlayer(npp);
|
||||
Log::info("ServerLobby", "New player %s with online id %u from %s.",
|
||||
StringUtils::wideToUtf8(npp->getName()).c_str(),
|
||||
npp->getOnlineId(), peer->getAddress().toString().c_str());
|
||||
peer->setWaitingForGame(true);
|
||||
for (auto& p : peer->getPlayerProfiles())
|
||||
m_waiting_players.push_back(p);
|
||||
updatePlayerList();
|
||||
peer->sendPacket(message_ack);
|
||||
delete message_ack;
|
||||
}
|
||||
updatePlayerList();
|
||||
|
||||
if (NetworkConfig::get()->isRankedServer())
|
||||
else
|
||||
{
|
||||
getRankingForPlayer(peer->getPlayerProfiles()[0]);
|
||||
peer->setWaitingForGame(false);
|
||||
m_peers_ready[peer] = false;
|
||||
for (std::shared_ptr<NetworkPlayerProfile>& npp :
|
||||
peer->getPlayerProfiles())
|
||||
{
|
||||
m_game_setup->addPlayer(npp);
|
||||
Log::info("ServerLobby",
|
||||
"New player %s with online id %u from %s.",
|
||||
StringUtils::wideToUtf8(npp->getName()).c_str(),
|
||||
npp->getOnlineId(), peer->getAddress().toString().c_str());
|
||||
}
|
||||
updatePlayerList();
|
||||
peer->sendPacket(message_ack);
|
||||
delete message_ack;
|
||||
|
||||
if (NetworkConfig::get()->isRankedServer())
|
||||
{
|
||||
getRankingForPlayer(peer->getPlayerProfiles()[0]);
|
||||
}
|
||||
}
|
||||
} // handleUnencryptedConnection
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ServerLobby::updatePlayerList(bool force_update)
|
||||
/** Called when any players change their setting (team for example), or
|
||||
* connection / disconnection, it will use the game_started parameter to
|
||||
* determine if this should be send to all peers in server or just in game.
|
||||
* \param update_when_reset_server If true, this message will be sent to
|
||||
* all peers.
|
||||
*/
|
||||
void ServerLobby::updatePlayerList(bool update_when_reset_server)
|
||||
{
|
||||
if (m_state.load() > ACCEPTING_CLIENTS && !force_update)
|
||||
const bool game_started = m_state.load() != WAITING_FOR_START_GAME &&
|
||||
!update_when_reset_server;
|
||||
|
||||
// No need to update player list (for started grand prix currently)
|
||||
if (!allowJoinedPlayersWaiting() &&
|
||||
m_state.load() > WAITING_FOR_START_GAME && !update_when_reset_server)
|
||||
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());
|
||||
pl->addUInt8(LE_UPDATE_PLAYER_LIST)
|
||||
.addUInt8((uint8_t)(game_started ? 1 : 0))
|
||||
.addUInt8((uint8_t)all_profiles.size());
|
||||
for (auto profile : all_profiles)
|
||||
{
|
||||
pl->addUInt32(profile->getHostId()).addUInt32(profile->getOnlineId())
|
||||
.addUInt8(profile->getLocalPlayerId())
|
||||
.encodeString(profile->getName());
|
||||
pl->addUInt8((uint8_t)
|
||||
(profile->getPeer()->isWaitingForGame() ? 1 : 0));
|
||||
uint8_t server_owner = 0;
|
||||
if (m_server_owner_id.load() == profile->getPeer()->getHostId())
|
||||
server_owner = 1;
|
||||
@ -1564,14 +1623,24 @@ void ServerLobby::updatePlayerList(bool force_update)
|
||||
else
|
||||
pl->addUInt8(KART_TEAM_NONE);
|
||||
}
|
||||
sendMessageToPeers(pl);
|
||||
|
||||
// Don't send this message to in-game players
|
||||
STKHost::get()->sendPacketToAllPeersWith([game_started]
|
||||
(STKPeer* p)
|
||||
{
|
||||
if (!p->isValidated())
|
||||
return false;
|
||||
if (!p->isWaitingForGame() && game_started)
|
||||
return false;
|
||||
return true;
|
||||
}, pl);
|
||||
delete pl;
|
||||
} // updatePlayerList
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ServerLobby::updateServerOwner()
|
||||
{
|
||||
if (m_state.load() < ACCEPTING_CLIENTS ||
|
||||
if (m_state.load() < WAITING_FOR_START_GAME ||
|
||||
m_state.load() > RESULT_DISPLAY ||
|
||||
NetworkConfig::get()->isOwnerLess())
|
||||
return;
|
||||
@ -1660,7 +1729,8 @@ void ServerLobby::playerVote(Event* event)
|
||||
}
|
||||
|
||||
if (!checkDataSize(event, 4) ||
|
||||
event->getPeer()->getPlayerProfiles().empty())
|
||||
event->getPeer()->getPlayerProfiles().empty() ||
|
||||
event->getPeer()->isWaitingForGame())
|
||||
return;
|
||||
|
||||
// Check if first vote, if so start counter
|
||||
@ -1714,7 +1784,7 @@ std::tuple<std::string, uint8_t, bool, bool> ServerLobby::handleVote()
|
||||
auto peers = STKHost::get()->getPeers();
|
||||
for (auto peer : peers)
|
||||
{
|
||||
if (peer->hasPlayerProfiles())
|
||||
if (peer->hasPlayerProfiles() && !peer->isWaitingForGame())
|
||||
cur_players += 1.0f;
|
||||
}
|
||||
if (cur_players == 0.0f)
|
||||
@ -1887,8 +1957,9 @@ void ServerLobby::updateBanList()
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ServerLobby::waitingForPlayers() const
|
||||
{
|
||||
return m_state.load() == ACCEPTING_CLIENTS &&
|
||||
!m_game_setup->isGrandPrixStarted();
|
||||
if (m_game_setup->isGrandPrix() && m_game_setup->isGrandPrixStarted())
|
||||
return false;
|
||||
return m_state.load() >= WAITING_FOR_START_GAME;
|
||||
} // waitingForPlayers
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -2094,3 +2165,86 @@ void ServerLobby::configPeersStartTime()
|
||||
m_state.store(RACING);
|
||||
});
|
||||
} // configPeersStartTime
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ServerLobby::allowJoinedPlayersWaiting() const
|
||||
{
|
||||
return !m_game_setup->isGrandPrix();
|
||||
} // allowJoinedPlayersWaiting
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ServerLobby::updateWaitingPlayers()
|
||||
{
|
||||
// addWaitingPlayersToGame below will be called by main thread in case
|
||||
// resetServer
|
||||
std::lock_guard<std::mutex> lock(m_connection_mutex);
|
||||
|
||||
m_waiting_players.erase(std::remove_if(
|
||||
m_waiting_players.begin(), m_waiting_players.end(), []
|
||||
(const std::weak_ptr<NetworkPlayerProfile>& npp)->bool
|
||||
{
|
||||
return npp.expired();
|
||||
}), m_waiting_players.end());
|
||||
m_waiting_players_counts.store((uint32_t)m_waiting_players.size());
|
||||
} // updateWaitingPlayers
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ServerLobby::addWaitingPlayersToGame()
|
||||
{
|
||||
if (m_waiting_players.empty())
|
||||
return;
|
||||
for (auto& p : m_waiting_players)
|
||||
{
|
||||
auto npp = p.lock();
|
||||
if (!npp)
|
||||
continue;
|
||||
auto peer = npp->getPeer();
|
||||
assert(peer);
|
||||
uint32_t online_id = npp->getOnlineId();
|
||||
if (NetworkConfig::get()->isRankedServer())
|
||||
{
|
||||
if (m_scores.find(online_id) != m_scores.end())
|
||||
{
|
||||
NetworkString* message = getNetworkString(2);
|
||||
message->setSynchronous(true);
|
||||
message->addUInt8(LE_CONNECTION_REFUSED)
|
||||
.addUInt8(RR_INVALID_PLAYER);
|
||||
peer->sendPacket(message, true/*reliable*/, false/*encrypted*/);
|
||||
peer->reset();
|
||||
delete message;
|
||||
Log::verbose("ServerLobby", "Player refused: invalid player");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
peer->setWaitingForGame(false);
|
||||
m_peers_ready[peer] = false;
|
||||
m_game_setup->addPlayer(npp);
|
||||
Log::info("ServerLobby", "New player %s with online id %u from %s.",
|
||||
StringUtils::wideToUtf8(npp->getName()).c_str(),
|
||||
npp->getOnlineId(), peer->getAddress().toString().c_str());
|
||||
|
||||
if (NetworkConfig::get()->isRankedServer())
|
||||
{
|
||||
getRankingForPlayer(peer->getPlayerProfiles()[0]);
|
||||
}
|
||||
}
|
||||
m_waiting_players.clear();
|
||||
m_waiting_players_counts.store(0);
|
||||
} // addWaitingPlayersToGame
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ServerLobby::resetServer()
|
||||
{
|
||||
addWaitingPlayersToGame();
|
||||
m_state = NetworkConfig::get()->isLAN() ?
|
||||
WAITING_FOR_START_GAME : REGISTER_SELF_ADDRESS;
|
||||
updatePlayerList(true/*update_when_reset_server*/);
|
||||
NetworkString* server_info = getNetworkString();
|
||||
server_info->setSynchronous(true);
|
||||
server_info->addUInt8(LE_SERVER_INFO);
|
||||
m_game_setup->addServerInfo(server_info);
|
||||
sendMessageToPeersInServer(server_info);
|
||||
delete server_info;
|
||||
setup();
|
||||
} // resetServer
|
||||
|
@ -46,7 +46,7 @@ public:
|
||||
{
|
||||
SET_PUBLIC_ADDRESS, // Waiting to receive its public ip address
|
||||
REGISTER_SELF_ADDRESS, // Register with STK online server
|
||||
ACCEPTING_CLIENTS, // In lobby, accepting clients
|
||||
WAITING_FOR_START_GAME, // In lobby, waiting for (auto) start game
|
||||
SELECTING, // kart, track, ... selection started
|
||||
LOAD_WORLD, // Server starts loading world
|
||||
WAIT_FOR_WORLD_LOADED, // Wait for clients and server to load world
|
||||
@ -136,6 +136,12 @@ private:
|
||||
|
||||
NetworkString* m_result_ns;
|
||||
|
||||
std::vector<std::weak_ptr<NetworkPlayerProfile> > m_waiting_players;
|
||||
|
||||
std::atomic<uint32_t> m_waiting_players_counts;
|
||||
|
||||
bool m_registered_for_once_only;
|
||||
|
||||
// connection management
|
||||
void clientDisconnected(Event* event);
|
||||
void connectionRequested(Event* event);
|
||||
@ -151,7 +157,7 @@ private:
|
||||
void handleChat(Event* event);
|
||||
void unregisterServer(bool now);
|
||||
void createServerIdFile();
|
||||
void updatePlayerList(bool force_update = false);
|
||||
void updatePlayerList(bool update_when_reset_server = false);
|
||||
void updateServerOwner();
|
||||
bool checkPeersReady() const
|
||||
{
|
||||
@ -212,6 +218,9 @@ private:
|
||||
void sendBadConnectionMessageToPeer(std::shared_ptr<STKPeer> p);
|
||||
std::pair<int, float> getHitCaptureLimit(float num_karts);
|
||||
void configPeersStartTime();
|
||||
void updateWaitingPlayers();
|
||||
void resetServer();
|
||||
void addWaitingPlayersToGame();
|
||||
public:
|
||||
ServerLobby();
|
||||
virtual ~ServerLobby();
|
||||
@ -227,10 +236,13 @@ public:
|
||||
void finishedLoadingWorld() OVERRIDE;
|
||||
ServerState getCurrentState() const { return m_state.load(); }
|
||||
void updateBanList();
|
||||
virtual bool waitingForPlayers() const OVERRIDE;
|
||||
bool waitingForPlayers() const;
|
||||
uint32_t getWaitingPlayersCount() const
|
||||
{ return m_waiting_players_counts.load(); }
|
||||
virtual bool allPlayersReady() const OVERRIDE
|
||||
{ return m_state.load() >= WAIT_FOR_RACE_STARTED; }
|
||||
virtual bool isRacing() const OVERRIDE { return m_state.load() == RACING; }
|
||||
bool allowJoinedPlayersWaiting() const;
|
||||
|
||||
}; // class ServerLobby
|
||||
|
||||
|
@ -738,7 +738,7 @@ void STKHost::mainLoop()
|
||||
std::unique_lock<std::mutex> peer_lock(m_peers_mutex);
|
||||
const float timeout = UserConfigParams::m_validation_timeout;
|
||||
bool need_ping = false;
|
||||
if (sl && !sl->isRacing() &&
|
||||
if (sl && (!sl->isRacing() || sl->allowJoinedPlayersWaiting()) &&
|
||||
last_ping_time < StkTime::getRealTimeMs())
|
||||
{
|
||||
// If not racing, send an reliable packet at the same rate with
|
||||
@ -749,6 +749,7 @@ void STKHost::mainLoop()
|
||||
need_ping = true;
|
||||
}
|
||||
|
||||
ENetPacket* packet = NULL;
|
||||
if (need_ping)
|
||||
{
|
||||
m_peer_pings.getData().clear();
|
||||
@ -772,22 +773,25 @@ void STKHost::mainLoop()
|
||||
ECT_DISCONNECT);
|
||||
}
|
||||
}
|
||||
BareNetworkString ping_packet;
|
||||
uint64_t network_timer = getNetworkTimer();
|
||||
ping_packet.addUInt64(network_timer);
|
||||
ping_packet.addUInt8((uint8_t)m_peer_pings.getData().size());
|
||||
for (auto& p : m_peer_pings.getData())
|
||||
ping_packet.addUInt32(p.first).addUInt32(p.second);
|
||||
ping_packet.getBuffer().insert(
|
||||
ping_packet.getBuffer().begin(), g_ping_packet.begin(),
|
||||
g_ping_packet.end());
|
||||
packet = enet_packet_create(ping_packet.getData(),
|
||||
ping_packet.getTotalSize(), ENET_PACKET_FLAG_RELIABLE);
|
||||
}
|
||||
|
||||
for (auto it = m_peers.begin(); it != m_peers.end();)
|
||||
{
|
||||
if (need_ping)
|
||||
if (need_ping &&
|
||||
(!sl->allowJoinedPlayersWaiting() ||
|
||||
!sl->isRacing() || it->second->isWaitingForGame()))
|
||||
{
|
||||
BareNetworkString ping_packet;
|
||||
uint64_t network_timer = getNetworkTimer();
|
||||
ping_packet.addUInt64(network_timer);
|
||||
ping_packet.addUInt8((uint8_t)m_peer_pings.getData().size());
|
||||
for (auto& p : m_peer_pings.getData())
|
||||
ping_packet.addUInt32(p.first).addUInt32(p.second);
|
||||
ping_packet.getBuffer().insert(
|
||||
ping_packet.getBuffer().begin(), g_ping_packet.begin(),
|
||||
g_ping_packet.end());
|
||||
ENetPacket* packet = enet_packet_create(ping_packet.getData(),
|
||||
ping_packet.getTotalSize(), ENET_PACKET_FLAG_RELIABLE);
|
||||
enet_peer_send(it->first, EVENT_CHANNEL_UNENCRYPTED, packet);
|
||||
}
|
||||
|
||||
@ -1026,12 +1030,15 @@ void STKHost::handleDirectSocketRequest(Network* direct_socket,
|
||||
s.addUInt32(NetworkConfig::m_server_version);
|
||||
s.encodeString(name);
|
||||
s.addUInt8(NetworkConfig::get()->getMaxPlayers());
|
||||
s.addUInt8((uint8_t)sl->getGameSetup()->getPlayerCount());
|
||||
s.addUInt8((uint8_t)(sl->getGameSetup()->getPlayerCount() +
|
||||
sl->getWaitingPlayersCount()));
|
||||
s.addUInt16(m_private_port);
|
||||
s.addUInt8((uint8_t)race_manager->getDifficulty());
|
||||
s.addUInt8((uint8_t)NetworkConfig::get()->getServerMode());
|
||||
s.addUInt8(!NetworkConfig::get()->getPassword().empty());
|
||||
s.addUInt8(0);
|
||||
s.addUInt8((uint8_t)
|
||||
(sl->getCurrentState() == ServerLobby::WAITING_FOR_START_GAME ?
|
||||
0 : 1));
|
||||
direct_socket->sendRawPacket(s, sender);
|
||||
} // if message is server-requested
|
||||
else if (command == connection_cmd)
|
||||
@ -1123,7 +1130,22 @@ bool STKHost::isConnectedTo(const TransportAddress& peer)
|
||||
} // isConnectedTo
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Sends data to all peers
|
||||
/** Sends data to all validated peers currently in server
|
||||
* \param data Data to sent.
|
||||
* \param reliable If the data should be sent reliable or now.
|
||||
*/
|
||||
void STKHost::sendPacketToAllPeersInServer(NetworkString *data, bool reliable)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_peers_mutex);
|
||||
for (auto p : m_peers)
|
||||
{
|
||||
if (p.second->isValidated())
|
||||
p.second->sendPacket(data, reliable);
|
||||
}
|
||||
} // sendPacketToAllPeersInServer
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Sends data to all validated peers currently in game
|
||||
* \param data Data to sent.
|
||||
* \param reliable If the data should be sent reliable or now.
|
||||
*/
|
||||
@ -1132,13 +1154,13 @@ void STKHost::sendPacketToAllPeers(NetworkString *data, bool reliable)
|
||||
std::lock_guard<std::mutex> lock(m_peers_mutex);
|
||||
for (auto p : m_peers)
|
||||
{
|
||||
if (p.second->isValidated())
|
||||
if (p.second->isValidated() && !p.second->isWaitingForGame())
|
||||
p.second->sendPacket(data, reliable);
|
||||
}
|
||||
} // sendPacketExcept
|
||||
} // sendPacketToAllPeers
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Sends data to all peers except the specified one.
|
||||
/** Sends data to all validated peers except the specified currently in game
|
||||
* \param peer Peer which will not receive the message.
|
||||
* \param data Data to sent.
|
||||
* \param reliable If the data should be sent reliable or now.
|
||||
@ -1150,13 +1172,32 @@ void STKHost::sendPacketExcept(STKPeer* peer, NetworkString *data,
|
||||
for (auto p : m_peers)
|
||||
{
|
||||
STKPeer* stk_peer = p.second.get();
|
||||
if (!stk_peer->isSamePeer(peer) && p.second->isValidated())
|
||||
if (!stk_peer->isSamePeer(peer) && p.second->isValidated() &&
|
||||
!p.second->isWaitingForGame())
|
||||
{
|
||||
stk_peer->sendPacket(data, reliable);
|
||||
}
|
||||
}
|
||||
} // sendPacketExcept
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Sends data to peers with custom rule
|
||||
* \param predicate boolean function for peer to predicate whether to send
|
||||
* \param data Data to sent.
|
||||
* \param reliable If the data should be sent reliable or now.
|
||||
*/
|
||||
void STKHost::sendPacketToAllPeersWith(std::function<bool(STKPeer*)> predicate,
|
||||
NetworkString* data, bool reliable)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_peers_mutex);
|
||||
for (auto p : m_peers)
|
||||
{
|
||||
STKPeer* stk_peer = p.second.get();
|
||||
if (predicate(stk_peer))
|
||||
stk_peer->sendPacket(data, reliable);
|
||||
}
|
||||
} // sendPacketToAllPeersWith
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Sends a message from a client to the server. */
|
||||
void STKHost::sendToServer(NetworkString *data, bool reliable)
|
||||
|
@ -38,6 +38,7 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <list>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@ -210,8 +211,14 @@ public:
|
||||
//-------------------------------------------------------------------------
|
||||
void shutdown();
|
||||
//-------------------------------------------------------------------------
|
||||
void sendPacketToAllPeersInServer(NetworkString *data,
|
||||
bool reliable = true);
|
||||
// ------------------------------------------------------------------------
|
||||
void sendPacketToAllPeers(NetworkString *data, bool reliable = true);
|
||||
// ------------------------------------------------------------------------
|
||||
void sendPacketToAllPeersWith(std::function<bool(STKPeer*)> predicate,
|
||||
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.
|
||||
*/
|
||||
|
@ -40,6 +40,7 @@ STKPeer::STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id)
|
||||
m_connected_time = StkTime::getRealTimeMs();
|
||||
m_validated.store(false);
|
||||
m_average_ping.store(0);
|
||||
m_waiting_for_game.store(true);
|
||||
} // STKPeer
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -64,6 +64,9 @@ protected:
|
||||
/** True if this peer is validated by server. */
|
||||
std::atomic_bool m_validated;
|
||||
|
||||
/** True if this peer is waiting for game. */
|
||||
std::atomic_bool m_waiting_for_game;
|
||||
|
||||
/** Host id of this peer. */
|
||||
uint32_t m_host_id;
|
||||
|
||||
@ -170,6 +173,11 @@ public:
|
||||
uint32_t getAveragePing() const { return m_average_ping.load(); }
|
||||
// ------------------------------------------------------------------------
|
||||
ENetPeer* getENetPeer() const { return m_enet_peer; }
|
||||
// ------------------------------------------------------------------------
|
||||
void setWaitingForGame(bool val) { m_waiting_for_game.store(val); }
|
||||
// ------------------------------------------------------------------------
|
||||
bool isWaitingForGame() const { return m_waiting_for_game.load(); }
|
||||
|
||||
}; // STKPeer
|
||||
|
||||
#endif // STK_PEER_HPP
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include "io/file_manager.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/protocols/connect_to_server.hpp"
|
||||
#include "network/protocols/lobby_protocol.hpp"
|
||||
#include "network/protocols/client_lobby.hpp"
|
||||
#include "network/server.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
@ -115,9 +115,12 @@ void NetworkingLobby::loadedFromFile()
|
||||
(file_manager->getAsset(FileManager::GUI, "difficulty_medium.png"));
|
||||
video::ITexture* icon_3 = irr_driver->getTexture
|
||||
(file_manager->getAsset(FileManager::GUI, "main_help.png"));
|
||||
video::ITexture* icon_4 = irr_driver->getTexture
|
||||
(file_manager->getAsset(FileManager::GUI, "hourglass.png"));
|
||||
m_icon_bank->addTextureAsSprite(icon_1);
|
||||
m_icon_bank->addTextureAsSprite(icon_2);
|
||||
m_icon_bank->addTextureAsSprite(icon_3);
|
||||
m_icon_bank->addTextureAsSprite(icon_4);
|
||||
const int screen_width = irr_driver->getFrameSize().Width;
|
||||
m_icon_bank->setScale(screen_width > 1280 ? 0.4f : 0.25f);
|
||||
} // loadedFromFile
|
||||
@ -136,7 +139,9 @@ void NetworkingLobby::init()
|
||||
{
|
||||
Screen::init();
|
||||
|
||||
m_player_names.clear();
|
||||
m_allow_change_team = false;
|
||||
m_has_auto_start_in_server = false;
|
||||
m_ping_update_timer = 0.0f;
|
||||
m_cur_starting_timer = m_start_threshold = m_start_timeout =
|
||||
m_server_max_player = std::numeric_limits<float>::max();
|
||||
@ -210,8 +215,43 @@ void NetworkingLobby::onUpdate(float delta)
|
||||
{
|
||||
if (NetworkConfig::get()->isServer())
|
||||
return;
|
||||
if (m_timeout_message->isVisible() && m_player_list)
|
||||
|
||||
m_ping_update_timer += delta;
|
||||
if (m_player_list && m_ping_update_timer > 2.0f)
|
||||
{
|
||||
m_ping_update_timer = 0.0f;
|
||||
updatePlayerPings();
|
||||
}
|
||||
|
||||
//I18N: In the networking lobby, display ping when connected
|
||||
const uint32_t ping = STKHost::get()->getClientPingToServer();
|
||||
if (ping != 0)
|
||||
m_header->setText(_("Lobby (ping: %dms)", ping), false);
|
||||
|
||||
auto cl = LobbyProtocol::get<ClientLobby>();
|
||||
if (cl && cl->isWaitingForGame())
|
||||
{
|
||||
m_start_button->setVisible(false);
|
||||
m_exit_widget->setVisible(true);
|
||||
m_timeout_message->setVisible(true);
|
||||
//I18N: In the networking lobby, show when player is required to wait
|
||||
//before the current game finish
|
||||
core::stringw msg = _("Please wait for current game to be finished.");
|
||||
m_timeout_message->setText(msg, true);
|
||||
core::stringw total_msg;
|
||||
for (auto& string : m_server_info)
|
||||
{
|
||||
total_msg += string;
|
||||
total_msg += L"\n";
|
||||
}
|
||||
m_text_bubble->setText(total_msg, true);
|
||||
m_cur_starting_timer = std::numeric_limits<float>::max();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_has_auto_start_in_server && m_player_list)
|
||||
{
|
||||
m_timeout_message->setVisible(true);
|
||||
float cur_player = (float)(m_player_list->getItemCount());
|
||||
if (cur_player >= m_server_max_player * m_start_threshold &&
|
||||
m_cur_starting_timer == std::numeric_limits<float>::max())
|
||||
@ -242,6 +282,10 @@ void NetworkingLobby::onUpdate(float delta)
|
||||
m_timeout_message->setText(msg, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_timeout_message->setVisible(false);
|
||||
}
|
||||
|
||||
if (m_state == LS_ADD_PLAYERS)
|
||||
{
|
||||
@ -259,8 +303,7 @@ void NetworkingLobby::onUpdate(float delta)
|
||||
|
||||
m_start_button->setVisible(false);
|
||||
m_exit_widget->setVisible(true);
|
||||
auto lp = LobbyProtocol::get<LobbyProtocol>();
|
||||
if (!lp || !lp->waitingForPlayers())
|
||||
if (!cl || !cl->isLobbyReady())
|
||||
{
|
||||
core::stringw connect_msg;
|
||||
if (m_joined_server)
|
||||
@ -287,20 +330,10 @@ void NetworkingLobby::onUpdate(float delta)
|
||||
m_text_bubble->setText(total_msg, true);
|
||||
}
|
||||
|
||||
m_ping_update_timer += delta;
|
||||
if (m_player_list && m_ping_update_timer > 2.0f)
|
||||
{
|
||||
m_ping_update_timer = 0.0f;
|
||||
updatePlayerPings();
|
||||
}
|
||||
if (STKHost::get()->isAuthorisedToControl())
|
||||
{
|
||||
m_start_button->setVisible(true);
|
||||
}
|
||||
//I18N: In the networking lobby, display ping when connected
|
||||
const uint32_t ping = STKHost::get()->getClientPingToServer();
|
||||
if (ping != 0)
|
||||
m_header->setText(_("Lobby (ping: %dms)", ping), false);
|
||||
|
||||
} // onUpdate
|
||||
|
||||
@ -508,7 +541,7 @@ void NetworkingLobby::initAutoStartTimer(bool grand_prix_started,
|
||||
if (start_threshold == 0.0f || start_timeout == 0.0f)
|
||||
return;
|
||||
|
||||
m_timeout_message->setVisible(true);
|
||||
m_has_auto_start_in_server = true;
|
||||
m_start_threshold = grand_prix_started ? 0.0f : start_threshold;
|
||||
m_start_timeout = start_timeout;
|
||||
m_server_max_player = (float)server_max_player;
|
||||
|
@ -74,7 +74,7 @@ private:
|
||||
float m_cur_starting_timer, m_start_threshold, m_start_timeout,
|
||||
m_server_max_player;
|
||||
|
||||
bool m_allow_change_team;
|
||||
bool m_allow_change_team, m_has_auto_start_in_server;
|
||||
|
||||
GUIEngine::IconButtonWidget* m_back_widget;
|
||||
GUIEngine::LabelWidget* m_header;
|
||||
|
Loading…
x
Reference in New Issue
Block a user