141 lines
5.5 KiB
C++
141 lines
5.5 KiB
C++
#include "network/protocols/latency_protocol.hpp"
|
|
|
|
#include "network/event.hpp"
|
|
#include "network/network_config.hpp"
|
|
#include "network/stk_host.hpp"
|
|
#include "network/stk_peer.hpp"
|
|
#include "utils/time.hpp"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/** This protocol tries to determine the average latency between client and
|
|
* server. While this information is not used atm, it might be useful for
|
|
* the server to determine how much behind the clients it should start.
|
|
* FIXME: ATM the main thread will load the world as part of an update
|
|
* of the ProtocolManager (which updates the protocols). Since all protocols
|
|
* are locked dusing this update, the synchronisation protocol is actually
|
|
* delayed from starting while world is loading (since finding the protocol
|
|
* for a message requires the protocol lock) - causing at least two frames
|
|
* of significanlty delayed pings :(
|
|
*/
|
|
LatencyProtocol::LatencyProtocol()
|
|
: Protocol(PROTOCOL_SYNCHRONIZATION)
|
|
{
|
|
unsigned int size = STKHost::get()->getPeerCount();
|
|
m_pings.resize(size, std::map<uint32_t,double>());
|
|
m_successed_pings.resize(size, 0);
|
|
m_total_diff.resize(size, 0);
|
|
m_average_ping.resize(size, 0);
|
|
m_pings_count = 0;
|
|
} // LatencyProtocol
|
|
|
|
//-----------------------------------------------------------------------------
|
|
LatencyProtocol::~LatencyProtocol()
|
|
{
|
|
} // ~LatencyProtocol
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void LatencyProtocol::setup()
|
|
{
|
|
Log::info("LatencyProtocol", "Ready !");
|
|
} // setup
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/** Called when receiving a message. On the client side the message is a ping
|
|
* from the server, which is answered back. On the server the received message
|
|
* is a reply to a previous ping request. The server will keep track of
|
|
* average latency.
|
|
*/
|
|
bool LatencyProtocol::notifyEventAsynchronous(Event* event)
|
|
{
|
|
if (event->getType() != EVENT_TYPE_MESSAGE)
|
|
return true;
|
|
if(!checkDataSize(event, 5)) return true;
|
|
|
|
const NetworkString &data = event->data();
|
|
uint32_t request = data.getUInt8();
|
|
uint32_t sequence = data.getUInt32();
|
|
|
|
const std::vector<STKPeer*> &peers = STKHost::get()->getPeers();
|
|
assert(peers.size() > 0);
|
|
|
|
// Find the right peer id. The host id (i.e. each host sendings its
|
|
// host id) can not be used here, since host ids can have gaps (if a
|
|
// host should disconnect)
|
|
uint8_t peer_id = -1;
|
|
for (unsigned int i = 0; i < peers.size(); i++)
|
|
{
|
|
if (peers[i]->isSamePeer(event->getPeer()))
|
|
{
|
|
peer_id = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (request)
|
|
{
|
|
// Only a client should receive a request for a ping response
|
|
assert(NetworkConfig::get()->isClient());
|
|
NetworkString *response = getNetworkString(5);
|
|
// The '0' indicates a response to a ping request
|
|
response->addUInt8(0).addUInt32(sequence);
|
|
event->getPeer()->sendPacket(response, false);
|
|
delete response;
|
|
}
|
|
else // receive response to a ping request
|
|
{
|
|
// Only a server should receive this kind of message
|
|
assert(NetworkConfig::get()->isServer());
|
|
if (sequence >= m_pings[peer_id].size())
|
|
{
|
|
Log::warn("LatencyProtocol",
|
|
"The sequence# %u isn't known.", sequence);
|
|
return true;
|
|
}
|
|
double current_time = StkTime::getRealTime();
|
|
m_total_diff[peer_id] += current_time - m_pings[peer_id][sequence];
|
|
m_successed_pings[peer_id]++;
|
|
m_average_ping[peer_id] =
|
|
(int)((m_total_diff[peer_id]/m_successed_pings[peer_id])*1000.0);
|
|
|
|
Log::debug("LatencyProtocol",
|
|
"Peer %d sequence %d ping %u average %u at %lf",
|
|
peer_id, sequence,
|
|
(unsigned int)((current_time - m_pings[peer_id][sequence])*1000),
|
|
m_average_ping[peer_id],
|
|
StkTime::getRealTime());
|
|
}
|
|
return true;
|
|
} // notifyEventAsynchronous
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/** Waits for the countdown to be started. On the server the start of the
|
|
* countdown is triggered by ServerLobby::finishedLoadingWorld(),
|
|
* which is called once all clients have confirmed that they are ready to
|
|
* start. The server will send a ping request to each client once a second,
|
|
* and include the information if the countdown has started (and its current
|
|
* value). On the client the countdown is started in notifyEvenAsynchronous()
|
|
* when a server ping is received that indicates that the countdown has
|
|
* started. The measured times can be used later to estimate the latency
|
|
* between server and client.
|
|
*/
|
|
void LatencyProtocol::asynchronousUpdate()
|
|
{
|
|
float current_time = float(StkTime::getRealTime());
|
|
if (NetworkConfig::get()->isServer() && current_time > m_last_time+1)
|
|
{
|
|
const std::vector<STKPeer*> &peers = STKHost::get()->getPeers();
|
|
for (unsigned int i = 0; i < peers.size(); i++)
|
|
{
|
|
NetworkString *ping_request =
|
|
getNetworkString(5);
|
|
ping_request->addUInt8(1).addUInt32(m_pings[i].size());
|
|
m_pings[i] [ m_pings_count ] = current_time;
|
|
peers[i]->sendPacket(ping_request, false);
|
|
delete ping_request;
|
|
} // for i M peers
|
|
m_last_time = current_time;
|
|
m_pings_count++;
|
|
} // if current_time > m_last_time + 0.1
|
|
} // asynchronousUpdate
|
|
|