Implement auto-kick high ping player (default off)
This commit is contained in:
parent
14475762b8
commit
4d2e79da4c
@ -727,7 +727,7 @@ namespace UserConfigParams
|
|||||||
PARAM_DEFAULT(FloatUserConfigParam(20.0f, "validation-timeout",
|
PARAM_DEFAULT(FloatUserConfigParam(20.0f, "validation-timeout",
|
||||||
&m_network_group, "Timeout in seconds for validation of clients."));
|
&m_network_group, "Timeout in seconds for validation of clients."));
|
||||||
PARAM_PREFIX IntUserConfigParam m_server_max_players
|
PARAM_PREFIX IntUserConfigParam m_server_max_players
|
||||||
PARAM_DEFAULT(IntUserConfigParam(8, "server_max_players",
|
PARAM_DEFAULT(IntUserConfigParam(8, "server-max-players",
|
||||||
&m_network_group, "Maximum number of players on the server."));
|
&m_network_group, "Maximum number of players on the server."));
|
||||||
PARAM_PREFIX BoolUserConfigParam m_firewalled_server
|
PARAM_PREFIX BoolUserConfigParam m_firewalled_server
|
||||||
PARAM_DEFAULT(BoolUserConfigParam(true, "firewalled-server",
|
PARAM_DEFAULT(BoolUserConfigParam(true, "firewalled-server",
|
||||||
@ -750,6 +750,15 @@ namespace UserConfigParams
|
|||||||
"from this IP will be banned.",
|
"from this IP will be banned.",
|
||||||
{ { "0.0.0.0", 0u } }
|
{ { "0.0.0.0", 0u } }
|
||||||
));
|
));
|
||||||
|
PARAM_PREFIX IntUserConfigParam m_max_ping
|
||||||
|
PARAM_DEFAULT(IntUserConfigParam(300, "max-ping",
|
||||||
|
&m_network_group, "Maximum ping allowed for a player (in ms)."));
|
||||||
|
PARAM_PREFIX IntUserConfigParam m_jitter_tolerance
|
||||||
|
PARAM_DEFAULT(IntUserConfigParam(100, "jitter-tolerance",
|
||||||
|
&m_network_group, "Tolerance of jitter in network allowed (in ms)."));
|
||||||
|
PARAM_PREFIX BoolUserConfigParam m_kick_high_ping_players
|
||||||
|
PARAM_DEFAULT(BoolUserConfigParam(false, "kick-high-ping-players",
|
||||||
|
&m_network_group, "Kick players whose ping is above max-ping."));
|
||||||
|
|
||||||
// ---- Gamemode setup
|
// ---- Gamemode setup
|
||||||
PARAM_PREFIX UIntToUIntUserConfigParam m_num_karts_per_gamemode
|
PARAM_PREFIX UIntToUIntUserConfigParam m_num_karts_per_gamemode
|
||||||
|
@ -167,6 +167,7 @@ bool ClientLobby::notifyEventAsynchronous(Event* event)
|
|||||||
case LE_VOTE: displayPlayerVote(event); break;
|
case LE_VOTE: displayPlayerVote(event); break;
|
||||||
case LE_SERVER_OWNERSHIP: becomingServerOwner(); break;
|
case LE_SERVER_OWNERSHIP: becomingServerOwner(); break;
|
||||||
case LE_BAD_TEAM: handleBadTeam(); break;
|
case LE_BAD_TEAM: handleBadTeam(); break;
|
||||||
|
case LE_BAD_CONNECTION: handleBadConnection(); break;
|
||||||
default: break;
|
default: break;
|
||||||
} // switch
|
} // switch
|
||||||
|
|
||||||
@ -195,6 +196,10 @@ bool ClientLobby::notifyEventAsynchronous(Event* event)
|
|||||||
STKHost::get()->setErrorMessage(
|
STKHost::get()->setErrorMessage(
|
||||||
_("You were kicked from the server."));
|
_("You were kicked from the server."));
|
||||||
break;
|
break;
|
||||||
|
case PDI_BAD_CONNECTION:
|
||||||
|
STKHost::get()->setErrorMessage(
|
||||||
|
_("Bad network connection is detected."));
|
||||||
|
break;
|
||||||
} // switch
|
} // switch
|
||||||
STKHost::get()->requestShutdown();
|
STKHost::get()->requestShutdown();
|
||||||
return true;
|
return true;
|
||||||
@ -624,6 +629,14 @@ void ClientLobby::handleBadTeam()
|
|||||||
MessageQueue::add(MessageQueue::MT_ERROR, msg);
|
MessageQueue::add(MessageQueue::MT_ERROR, msg);
|
||||||
} // handleBadTeam
|
} // handleBadTeam
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void ClientLobby::handleBadConnection()
|
||||||
|
{
|
||||||
|
SFXManager::get()->quickSound("anvil");
|
||||||
|
core::stringw msg = _("Bad network connection is detected.");
|
||||||
|
MessageQueue::add(MessageQueue::MT_ERROR, msg);
|
||||||
|
} // handleBadConnection
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void ClientLobby::becomingServerOwner()
|
void ClientLobby::becomingServerOwner()
|
||||||
{
|
{
|
||||||
|
@ -46,6 +46,7 @@ private:
|
|||||||
void handleChat(Event* event);
|
void handleChat(Event* event);
|
||||||
void handleServerInfo(Event* event);
|
void handleServerInfo(Event* event);
|
||||||
void handleBadTeam();
|
void handleBadTeam();
|
||||||
|
void handleBadConnection();
|
||||||
void becomingServerOwner();
|
void becomingServerOwner();
|
||||||
|
|
||||||
void clearPlayers();
|
void clearPlayers();
|
||||||
|
@ -61,7 +61,8 @@ public:
|
|||||||
LE_SERVER_OWNERSHIP,
|
LE_SERVER_OWNERSHIP,
|
||||||
LE_KICK_HOST,
|
LE_KICK_HOST,
|
||||||
LE_CHANGE_TEAM,
|
LE_CHANGE_TEAM,
|
||||||
LE_BAD_TEAM
|
LE_BAD_TEAM,
|
||||||
|
LE_BAD_CONNECTION
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RejectReason : uint8_t
|
enum RejectReason : uint8_t
|
||||||
|
@ -199,7 +199,8 @@ void ServerLobby::setup()
|
|||||||
// the server are ready:
|
// the server are ready:
|
||||||
resetPeersReady();
|
resetPeersReady();
|
||||||
m_peers_votes.clear();
|
m_peers_votes.clear();
|
||||||
m_server_delay = 0.0;
|
m_server_delay = std::numeric_limits<double>::max();
|
||||||
|
m_server_max_ping = std::numeric_limits<double>::max();
|
||||||
m_timeout.store(std::numeric_limits<float>::max());
|
m_timeout.store(std::numeric_limits<float>::max());
|
||||||
m_waiting_for_reset = false;
|
m_waiting_for_reset = false;
|
||||||
|
|
||||||
@ -428,12 +429,34 @@ void ServerLobby::asynchronousUpdate()
|
|||||||
// Reset for next state usage
|
// Reset for next state usage
|
||||||
resetPeersReady();
|
resetPeersReady();
|
||||||
signalRaceStartToClients();
|
signalRaceStartToClients();
|
||||||
|
m_server_max_ping = StkTime::getRealTime() +
|
||||||
|
((double)UserConfigParams::m_max_ping / 1000.0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WAIT_FOR_RACE_STARTED:
|
case WAIT_FOR_RACE_STARTED:
|
||||||
// The function startedRaceOnClient() will trigger the
|
{
|
||||||
// next state.
|
const bool ping_timed_out =
|
||||||
|
m_server_max_ping < StkTime::getRealTime();
|
||||||
|
if (checkPeersReady() || ping_timed_out)
|
||||||
|
{
|
||||||
|
for (auto p : m_peers_ready)
|
||||||
|
{
|
||||||
|
auto cur_peer = p.first.lock();
|
||||||
|
if (!cur_peer)
|
||||||
|
continue;
|
||||||
|
if (ping_timed_out && p.second.second > m_server_max_ping)
|
||||||
|
sendBadConnectionMessageToPeer(cur_peer);
|
||||||
|
}
|
||||||
|
m_state = DELAY_SERVER;
|
||||||
|
const double jt =
|
||||||
|
(double)UserConfigParams::m_jitter_tolerance / 1000.0;
|
||||||
|
m_server_delay = StkTime::getRealTime() + jt;
|
||||||
|
Log::verbose("ServerLobby",
|
||||||
|
"Started delay at %lf to %lf with jitter tolerance %lf.",
|
||||||
|
StkTime::getRealTime(), m_server_delay, jt);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case DELAY_SERVER:
|
case DELAY_SERVER:
|
||||||
if (m_server_delay < StkTime::getRealTime())
|
if (m_server_delay < StkTime::getRealTime())
|
||||||
{
|
{
|
||||||
@ -501,6 +524,19 @@ void ServerLobby::asynchronousUpdate()
|
|||||||
|
|
||||||
} // asynchronousUpdate
|
} // asynchronousUpdate
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void ServerLobby::sendBadConnectionMessageToPeer(std::shared_ptr<STKPeer> p)
|
||||||
|
{
|
||||||
|
const unsigned max_ping = UserConfigParams::m_max_ping;
|
||||||
|
Log::warn("ServerLobby", "Peer %s cannot catch up with max ping %d, it"
|
||||||
|
" started at %lf.", p->getAddress().toString().c_str(), max_ping,
|
||||||
|
StkTime::getRealTime());
|
||||||
|
NetworkString* msg = getNetworkString();
|
||||||
|
msg->addUInt8(LE_BAD_CONNECTION);
|
||||||
|
p->sendPacket(msg, /*reliable*/true);
|
||||||
|
delete msg;
|
||||||
|
} // sendBadConnectionMessageToPeer
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
/** Simple finite state machine. Once this
|
/** Simple finite state machine. Once this
|
||||||
* is known, register the server and its address with the stk server so that
|
* is known, register the server and its address with the stk server so that
|
||||||
@ -1783,53 +1819,22 @@ void ServerLobby::finishedLoadingWorldClient(Event *event)
|
|||||||
/** Called when a notification from a client is received that the client has
|
/** Called when a notification from a client is received that the client has
|
||||||
* started the race. Once all clients have informed the server that they
|
* started the race. Once all clients have informed the server that they
|
||||||
* have started the race, the server can start. This makes sure that the
|
* have started the race, the server can start. This makes sure that the
|
||||||
* server's local time is behind all clients by (at least) their latency,
|
* server's local time is behind all clients by at most max ping,
|
||||||
* which in turn means that when the server simulates local time T all
|
* which in turn means that when the server simulates local time T all
|
||||||
* messages from clients at their local time T should have arrived at
|
* messages from clients at their local time T should have arrived at
|
||||||
* the server, which creates smoother play experience.
|
* the server, which creates smoother play experience.
|
||||||
*/
|
*/
|
||||||
void ServerLobby::startedRaceOnClient(Event *event)
|
void ServerLobby::startedRaceOnClient(Event *event)
|
||||||
{
|
{
|
||||||
|
if (m_state.load() != WAIT_FOR_RACE_STARTED)
|
||||||
|
{
|
||||||
|
sendBadConnectionMessageToPeer(event->getPeerSP());
|
||||||
|
return;
|
||||||
|
}
|
||||||
std::shared_ptr<STKPeer> peer = event->getPeerSP();
|
std::shared_ptr<STKPeer> peer = event->getPeerSP();
|
||||||
m_peers_ready.at(peer) = std::make_pair(true, StkTime::getRealTime());
|
m_peers_ready.at(peer) = std::make_pair(true, StkTime::getRealTime());
|
||||||
Log::info("ServerLobby", "Peer %d has started race at %lf",
|
Log::info("ServerLobby", "Peer %s has started race at %lf",
|
||||||
peer->getHostId(), StkTime::getRealTime());
|
peer->getAddress().toString().c_str(), StkTime::getRealTime());
|
||||||
|
|
||||||
if (checkPeersReady())
|
|
||||||
{
|
|
||||||
std::vector<std::pair<STKPeer*, double> > mapping;
|
|
||||||
for (auto p : m_peers_ready)
|
|
||||||
{
|
|
||||||
auto peer = p.first.lock();
|
|
||||||
if (!peer)
|
|
||||||
continue;
|
|
||||||
mapping.emplace_back(peer.get(), p.second.second);
|
|
||||||
}
|
|
||||||
std::sort(mapping.begin(), mapping.end(),
|
|
||||||
[](const std::pair<STKPeer*, double>& a,
|
|
||||||
const std::pair<STKPeer*, double>& b)->bool
|
|
||||||
{
|
|
||||||
return a.second > b.second;
|
|
||||||
});
|
|
||||||
for (unsigned i = 0; i < mapping.size(); i++)
|
|
||||||
{
|
|
||||||
// Server delay is 0.1, so it's around 12 ticks
|
|
||||||
// (0.1 * 120 (physics fps)) for the highest ping client
|
|
||||||
if (i == 0)
|
|
||||||
GameProtocol::lock()->addInitialTicks(mapping[0].first, 12);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const double diff = mapping[0].second - mapping[i].second;
|
|
||||||
assert(diff >= 0.0);
|
|
||||||
GameProtocol::lock()->addInitialTicks(mapping[i].first,
|
|
||||||
12 + stk_config->time2Ticks((float)diff));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_state = DELAY_SERVER;
|
|
||||||
m_server_delay = StkTime::getRealTime() + 0.1;
|
|
||||||
Log::verbose("ServerLobby", "Started delay at %lf set delay to %lf",
|
|
||||||
StkTime::getRealTime(), m_server_delay);
|
|
||||||
}
|
|
||||||
} // startedRaceOnClient
|
} // startedRaceOnClient
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -90,12 +90,12 @@ private:
|
|||||||
std::map<std::weak_ptr<STKPeer>, std::tuple<std::string, uint8_t, bool>,
|
std::map<std::weak_ptr<STKPeer>, std::tuple<std::string, uint8_t, bool>,
|
||||||
std::owner_less<std::weak_ptr<STKPeer> > > m_peers_votes;
|
std::owner_less<std::weak_ptr<STKPeer> > > m_peers_votes;
|
||||||
|
|
||||||
/** Keeps track of an artificial server delay (which makes sure that the
|
/** Keeps track of an artificial server delay, which is used to compensate
|
||||||
* data from all clients has arrived when the server computes a certain
|
* for network jitter. */
|
||||||
* timestep.(. It stores the real time since epoch + delta (atm 0.1
|
|
||||||
* seconds), which is the real time at which the server should start. */
|
|
||||||
double m_server_delay;
|
double m_server_delay;
|
||||||
|
|
||||||
|
double m_server_max_ping;
|
||||||
|
|
||||||
bool m_has_created_server_id_file;
|
bool m_has_created_server_id_file;
|
||||||
|
|
||||||
/** It indicates if this server is unregistered with the stk server. */
|
/** It indicates if this server is unregistered with the stk server. */
|
||||||
@ -218,6 +218,7 @@ private:
|
|||||||
double getModeSpread();
|
double getModeSpread();
|
||||||
double scalingValueForTime(double time);
|
double scalingValueForTime(double time);
|
||||||
void checkRaceFinished();
|
void checkRaceFinished();
|
||||||
|
void sendBadConnectionMessageToPeer(std::shared_ptr<STKPeer> p);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ServerLobby();
|
ServerLobby();
|
||||||
|
@ -753,6 +753,20 @@ void STKHost::mainLoop()
|
|||||||
{
|
{
|
||||||
m_peer_pings.getData()[p.second->getHostId()] =
|
m_peer_pings.getData()[p.second->getHostId()] =
|
||||||
p.second->getPing();
|
p.second->getPing();
|
||||||
|
const unsigned ap = p.second->getAveragePing();
|
||||||
|
const unsigned max_ping = UserConfigParams::m_max_ping;
|
||||||
|
if (UserConfigParams::m_kick_high_ping_players &&
|
||||||
|
p.second->isValidated() && ap > max_ping)
|
||||||
|
{
|
||||||
|
Log::info("STKHost", "%s with ping %d is higher than"
|
||||||
|
" %d ms, kick.",
|
||||||
|
p.second->getAddress().toString().c_str(),
|
||||||
|
ap, max_ping);
|
||||||
|
std::lock_guard<std::mutex> lock(m_enet_cmd_mutex);
|
||||||
|
m_enet_cmd.emplace_back(p.second->getENetPeer(),
|
||||||
|
(ENetPacket*)NULL, PDI_BAD_CONNECTION,
|
||||||
|
ECT_DISCONNECT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto it = m_peers.begin(); it != m_peers.end();)
|
for (auto it = m_peers.begin(); it != m_peers.end();)
|
||||||
|
@ -17,9 +17,11 @@
|
|||||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
#include "network/stk_peer.hpp"
|
#include "network/stk_peer.hpp"
|
||||||
|
#include "config/stk_config.hpp"
|
||||||
#include "config/user_config.hpp"
|
#include "config/user_config.hpp"
|
||||||
#include "network/crypto.hpp"
|
#include "network/crypto.hpp"
|
||||||
#include "network/event.hpp"
|
#include "network/event.hpp"
|
||||||
|
#include "network/network_config.hpp"
|
||||||
#include "network/network_string.hpp"
|
#include "network/network_string.hpp"
|
||||||
#include "network/stk_host.hpp"
|
#include "network/stk_host.hpp"
|
||||||
#include "network/transport_address.hpp"
|
#include "network/transport_address.hpp"
|
||||||
@ -37,6 +39,7 @@ STKPeer::STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id)
|
|||||||
m_host_id = host_id;
|
m_host_id = host_id;
|
||||||
m_connected_time = (float)StkTime::getRealTime();
|
m_connected_time = (float)StkTime::getRealTime();
|
||||||
m_validated.store(false);
|
m_validated.store(false);
|
||||||
|
m_average_ping = 0;
|
||||||
} // STKPeer
|
} // STKPeer
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -150,10 +153,23 @@ bool STKPeer::isSamePeer(const ENetPeer* peer) const
|
|||||||
/** Returns the ping to this peer from host, it waits for 3 seconds for a
|
/** Returns the ping to this peer from host, it waits for 3 seconds for a
|
||||||
* stable ping returned by enet measured in ms.
|
* stable ping returned by enet measured in ms.
|
||||||
*/
|
*/
|
||||||
uint32_t STKPeer::getPing() const
|
uint32_t STKPeer::getPing()
|
||||||
{
|
{
|
||||||
if ((float)StkTime::getRealTime() - m_connected_time < 3.0f)
|
if ((float)StkTime::getRealTime() - m_connected_time < 3.0f)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (NetworkConfig::get()->isServer())
|
||||||
|
{
|
||||||
|
// Average ping in 5 seconds
|
||||||
|
const unsigned ap = stk_config->m_network_state_frequeny * 5;
|
||||||
|
m_previous_pings.push_back(m_enet_peer->roundTripTime);
|
||||||
|
while (m_previous_pings.size() > ap)
|
||||||
|
{
|
||||||
|
m_previous_pings.pop_front();
|
||||||
|
m_average_ping =
|
||||||
|
(uint32_t)(std::accumulate(m_previous_pings.begin(),
|
||||||
|
m_previous_pings.end(), 0) / m_previous_pings.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
return m_enet_peer->roundTripTime;
|
return m_enet_peer->roundTripTime;
|
||||||
} // getPing
|
} // getPing
|
||||||
|
|
||||||
|
@ -30,7 +30,9 @@
|
|||||||
#include <enet/enet.h>
|
#include <enet/enet.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <deque>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <numeric>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -45,6 +47,7 @@ enum PeerDisconnectInfo : unsigned int
|
|||||||
PDI_TIMEOUT = 0, //!< Timeout disconnected (default in enet).
|
PDI_TIMEOUT = 0, //!< Timeout disconnected (default in enet).
|
||||||
PDI_NORMAL = 1, //!< Normal disconnction with acknowledgement
|
PDI_NORMAL = 1, //!< Normal disconnction with acknowledgement
|
||||||
PDI_KICK = 2, //!< Kick disconnection
|
PDI_KICK = 2, //!< Kick disconnection
|
||||||
|
PDI_BAD_CONNECTION = 3, //!< Bad connection disconnection
|
||||||
}; // PeerDisconnectInfo
|
}; // PeerDisconnectInfo
|
||||||
|
|
||||||
/*! \class STKPeer
|
/*! \class STKPeer
|
||||||
@ -76,6 +79,10 @@ protected:
|
|||||||
|
|
||||||
std::unique_ptr<Crypto> m_crypto;
|
std::unique_ptr<Crypto> m_crypto;
|
||||||
|
|
||||||
|
std::deque<uint32_t> m_previous_pings;
|
||||||
|
|
||||||
|
uint32_t m_average_ping;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id);
|
STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id);
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
@ -152,12 +159,15 @@ public:
|
|||||||
void setPingInterval(uint32_t interval)
|
void setPingInterval(uint32_t interval)
|
||||||
{ enet_peer_ping_interval(m_enet_peer, interval); }
|
{ enet_peer_ping_interval(m_enet_peer, interval); }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
uint32_t getPing() const;
|
uint32_t getPing();
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
Crypto* getCrypto() const { return m_crypto.get(); }
|
Crypto* getCrypto() const { return m_crypto.get(); }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
void setCrypto(std::unique_ptr<Crypto>&& c);
|
void setCrypto(std::unique_ptr<Crypto>&& c);
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
uint32_t getAveragePing() const { return m_average_ping; }
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
ENetPeer* getENetPeer() const { return m_enet_peer; }
|
||||||
}; // STKPeer
|
}; // STKPeer
|
||||||
|
|
||||||
#endif // STK_PEER_HPP
|
#endif // STK_PEER_HPP
|
||||||
|
Loading…
Reference in New Issue
Block a user