Send our own reliable packet for a more accurate ping
This commit is contained in:
parent
de8730dbfc
commit
a44ce60991
@ -57,7 +57,7 @@ digraph interaction {
|
||||
"REQUESTING_CONNECTION" -> "?? TO BE DONE ??" [label="Connection refused by server"]
|
||||
"CONNECTED" -> "KART_SELECTION" [label="Server tells us to start kart selection"]
|
||||
"KART_SELECTION" -> "SELECTING_KARTS" [label="Show kart selection screen"]
|
||||
"SELECTING_KARTS" -> "PLAYING" [label="Server sends start race message"]
|
||||
"SELECTING_KARTS" -> "RACING" [label="Server sends start race message"]
|
||||
}
|
||||
\enddot
|
||||
Note that some states are actually managed outside of the client lobby. For
|
||||
@ -313,14 +313,6 @@ void ClientLobby::update(int ticks)
|
||||
m_state.store(REQUESTING_CONNECTION);
|
||||
}
|
||||
break;
|
||||
case REQUESTING_CONNECTION:
|
||||
break;
|
||||
case CONNECTED:
|
||||
break;
|
||||
case SELECTING_ASSETS:
|
||||
break;
|
||||
case PLAYING:
|
||||
break;
|
||||
case RACE_FINISHED:
|
||||
if (!RaceEventManager::getInstance()->protocolStopped() ||
|
||||
!GameProtocol::emptyInstance())
|
||||
@ -332,6 +324,10 @@ void ClientLobby::update(int ticks)
|
||||
m_state.store(EXITING);
|
||||
requestTerminate();
|
||||
break;
|
||||
case REQUESTING_CONNECTION:
|
||||
case CONNECTED:
|
||||
case SELECTING_ASSETS:
|
||||
case RACING:
|
||||
case EXITING:
|
||||
break;
|
||||
}
|
||||
@ -656,7 +652,7 @@ void ClientLobby::connectionRefused(Event* event)
|
||||
*/
|
||||
void ClientLobby::startGame(Event* event)
|
||||
{
|
||||
m_state.store(PLAYING);
|
||||
m_state.store(RACING);
|
||||
// Triggers the world finite state machine to go from WAIT_FOR_SERVER_PHASE
|
||||
// to READY_PHASE.
|
||||
World::getWorld()->setReadyToRace();
|
||||
|
@ -1,3 +1,21 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2018 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef CLIENT_LOBBY_HPP
|
||||
#define CLIENT_LOBBY_HPP
|
||||
|
||||
@ -42,7 +60,7 @@ private:
|
||||
REQUESTING_CONNECTION,
|
||||
CONNECTED, // means in the lobby room
|
||||
SELECTING_ASSETS, // in the kart selection or tracks screen
|
||||
PLAYING, // racing
|
||||
RACING, // racing
|
||||
RACE_FINISHED, // race result shown
|
||||
DONE,
|
||||
EXITING
|
||||
@ -79,9 +97,11 @@ public:
|
||||
{ return m_state.load() == CONNECTED; }
|
||||
virtual void asynchronousUpdate() OVERRIDE {}
|
||||
virtual bool allPlayersReady() const OVERRIDE
|
||||
{ return m_state.load() >= PLAYING; }
|
||||
{ return m_state.load() >= RACING; }
|
||||
bool waitingForServerRespond() const
|
||||
{ return m_state.load() == REQUESTING_CONNECTION; }
|
||||
virtual bool isRacing() const OVERRIDE { return m_state.load() == RACING; }
|
||||
|
||||
};
|
||||
|
||||
#endif // CLIENT_LOBBY_HPP
|
||||
|
@ -116,6 +116,7 @@ public:
|
||||
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; }
|
||||
|
||||
}; // class LobbyProtocol
|
||||
|
@ -1366,6 +1366,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr<STKPeer> peer,
|
||||
server_info->addUInt8(LE_SERVER_INFO);
|
||||
m_game_setup->addServerInfo(server_info);
|
||||
peer->sendPacket(server_info);
|
||||
delete server_info;
|
||||
|
||||
NetworkString* message_ack = getNetworkString(4);
|
||||
message_ack->setSynchronous(true);
|
||||
@ -1377,12 +1378,6 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr<STKPeer> peer,
|
||||
peer->sendPacket(message_ack);
|
||||
delete message_ack;
|
||||
|
||||
// Make sure it will always ping at least the frequency of state exchange
|
||||
// so enet will not ping when we exchange state but keep ping elsewhere
|
||||
// then in lobby the ping seen will be correct
|
||||
peer->setPingInterval(110);
|
||||
delete server_info;
|
||||
|
||||
m_peers_ready[peer] = std::make_pair(false, 0.0);
|
||||
for (std::shared_ptr<NetworkPlayerProfile> npp : peer->getPlayerProfiles())
|
||||
{
|
||||
|
@ -1,3 +1,21 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2018 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef SERVER_LOBBY_HPP
|
||||
#define SERVER_LOBBY_HPP
|
||||
|
||||
@ -219,6 +237,7 @@ public:
|
||||
virtual bool waitingForPlayers() const OVERRIDE;
|
||||
virtual bool allPlayersReady() const OVERRIDE
|
||||
{ return m_state.load() >= WAIT_FOR_RACE_STARTED; }
|
||||
virtual bool isRacing() const OVERRIDE { return m_state.load() == RACING; }
|
||||
|
||||
}; // class ServerLobby
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "network/stk_host.hpp"
|
||||
|
||||
#include "config/stk_config.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "network/event.hpp"
|
||||
@ -241,23 +242,19 @@ std::shared_ptr<LobbyProtocol> STKHost::create(SeparateProcess* p)
|
||||
* LocalPlayerController for each kart. Each remote player gets a
|
||||
* NULL ActivePlayer (the ActivePlayer is only used for assigning the input
|
||||
* device to each kart, achievements and highscores, so it's not needed for
|
||||
* remote players). It will also start the LatencyProtocol,
|
||||
* RaceEventManager and then load the world.
|
||||
|
||||
* TODO:
|
||||
* Once the server has received all
|
||||
* messages in notifyEventAsynchronous(), it will call startCountdown()
|
||||
* in the LatencyProtocol. The LatencyProtocol is
|
||||
* sending regular (once per second) pings to the clients and measure
|
||||
* the averate latency. Upon starting the countdown this information
|
||||
* is included in the ping request, so the clients can start the countdown
|
||||
* at that stage as well.
|
||||
*
|
||||
* Once the countdown is 0 (or below), the Synchronization Protocol will
|
||||
* start the protocols: KartUpdateProtocol, GameProtocol,
|
||||
* GameEventsProtocol. Then the LatencyProtocol is terminated
|
||||
* which indicates to the main loop to start the actual game.
|
||||
* remote players). It will also start the RaceEventManager and then load the
|
||||
* world.
|
||||
*/
|
||||
// ============================================================================
|
||||
constexpr std::array<uint8_t, 5> g_ping_packet {{ 255, 'p', 'i', 'n', 'g' }};
|
||||
|
||||
// ============================================================================
|
||||
constexpr bool isPingPacket(unsigned char* data, size_t length)
|
||||
{
|
||||
return length == g_ping_packet.size() && data[0] == g_ping_packet[0] &&
|
||||
data[1] == g_ping_packet[1] && data[2] == g_ping_packet[2] &&
|
||||
data[3] == g_ping_packet[3] && data[4] == g_ping_packet[4];
|
||||
} // isPingPacket
|
||||
|
||||
// ============================================================================
|
||||
/** The constructor for a server or client.
|
||||
@ -715,6 +712,7 @@ void STKHost::mainLoop()
|
||||
}
|
||||
}
|
||||
|
||||
double last_ping_time = StkTime::getRealTime();
|
||||
while (m_exit_timeout.load() > StkTime::getRealTime())
|
||||
{
|
||||
if (!is_server)
|
||||
@ -737,11 +735,28 @@ void STKHost::mainLoop()
|
||||
if (is_server)
|
||||
{
|
||||
std::unique_lock<std::mutex> peer_lock(m_peers_mutex);
|
||||
// Remove peer which has not been validated after a specific time
|
||||
// It is validated when the first connection request has finished
|
||||
const float timeout = UserConfigParams::m_validation_timeout;
|
||||
bool need_ping = false;
|
||||
if (sl && !sl->isRacing() &&
|
||||
last_ping_time < StkTime::getRealTime())
|
||||
{
|
||||
// If not racing, send an reliable packet at the same rate with
|
||||
// state exchange to keep enet ping accurate
|
||||
last_ping_time = StkTime::getRealTime() +
|
||||
1.0 / double(stk_config->m_network_state_frequeny);
|
||||
need_ping = true;
|
||||
}
|
||||
for (auto it = m_peers.begin(); it != m_peers.end();)
|
||||
{
|
||||
if (need_ping)
|
||||
{
|
||||
ENetPacket* packet = enet_packet_create(g_ping_packet.data(),
|
||||
g_ping_packet.size(), ENET_PACKET_FLAG_RELIABLE);
|
||||
enet_peer_send(it->first, EVENT_CHANNEL_UNENCRYPTED, packet);
|
||||
}
|
||||
|
||||
// Remove peer which has not been validated after a specific time
|
||||
// It is validated when the first connection request has finished
|
||||
if (!it->second->isValidated() &&
|
||||
(float)StkTime::getRealTime() >
|
||||
it->second->getConnectedTime() + timeout)
|
||||
@ -837,6 +852,11 @@ void STKHost::mainLoop()
|
||||
if (!stk_event && m_peers.find(event.peer) != m_peers.end())
|
||||
{
|
||||
auto& peer = m_peers.at(event.peer);
|
||||
if (isPingPacket(event.packet->data, event.packet->dataLength))
|
||||
{
|
||||
enet_packet_destroy(event.packet);
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
stk_event = new Event(&event, peer);
|
||||
|
Loading…
Reference in New Issue
Block a user