adding a protocol to start a game, added features in the synchronization protocol

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/hilnius@13215 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hilnius 2013-07-14 21:19:22 +00:00
parent 75df500884
commit c50a24a25d
12 changed files with 193 additions and 42 deletions

Binary file not shown.

View File

@ -37,8 +37,6 @@ void* waitInput(void* data)
std::string str = "";
bool stop = false;
int n = 0;
bool success = false;
uint32_t ping = 0;
while(!stop)
{
@ -69,7 +67,7 @@ void* waitInput(void* data)
}
else if (str == "synchronize")
{
ProtocolManager::getInstance()->requestStart(new SynchronizationProtocol(&ping, &success));
ProtocolManager::getInstance()->requestStart(new SynchronizationProtocol());
}
else if (NetworkManager::getInstance()->getPeers().size() > 0)
{

View File

@ -19,6 +19,7 @@
#include "network/protocols/client_lobby_room_protocol.hpp"
#include "network/network_manager.hpp"
#include "network/protocols/start_game_protocol.hpp"
#include "online/current_online_user.hpp"
#include "utils/log.hpp"
@ -70,6 +71,8 @@ void ClientLobbyRoomProtocol::notifyEvent(Event* event)
disconnectedPlayer(event);
else if (message_type == 0x03) // kart selection update
kartSelectionUpdate(event);
else if (message_type == 0x04) // start race
startGame(event);
else if (message_type == 0x80) // connection refused
connectionRefused(event);
else if (message_type == 0x81) // connection accepted
@ -357,3 +360,33 @@ void ClientLobbyRoomProtocol::kartSelectionUpdate(Event* event)
}
//-----------------------------------------------------------------------------
/*! \brief Called when the race needs to be started.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5
* -------------
* Size | 1 | 4 |
* Data | 4 | token |
* -------------
*/
void ClientLobbyRoomProtocol::startGame(Event* event)
{
if (event->data.size() < 5 || event->data[0] != 4)
{
Log::error("ClientLobbyRoomProtocol", "A message notifying a kart "
"selection update wasn't formated as expected.");
return;
}
uint8_t token = event->data.gui32(1);
if (token == NetworkManager::getInstance()->getPeers()[0]->getClientServerToken())
{
m_listener->requestStart(new StartGameProtocol(m_setup));
}
else
Log::error("ClientLobbyRoomProtocol", "Bad token when starting game");
}
//-----------------------------------------------------------------------------

View File

@ -24,6 +24,7 @@ class ClientLobbyRoomProtocol : public LobbyRoomProtocol
void connectionRefused(Event* event); //!< Callback function on connection refusal
void kartSelectionRefused(Event* event);
void kartSelectionUpdate(Event* event);
void startGame(Event* event);
TransportAddress m_server_address;
STKPeer* m_server;

View File

@ -159,6 +159,19 @@ void ServerLobbyRoomProtocol::update()
break;
}
}
//-----------------------------------------------------------------------------
void ServerLobbyRoomProtocol::startGame()
{
std::vector<STKPeer*> peers = NetworkManager::getInstance()->getPeers();
for (unsigned int i = 0; i < peers.size(); i++)
{
NetworkString ns;
ns.ai8(0x04).ai8(4).ai32(peers[i]->getClientServerToken()); // start game
}
}
//-----------------------------------------------------------------------------
void ServerLobbyRoomProtocol::kartDisconnected(Event* event)

View File

@ -13,6 +13,8 @@ class ServerLobbyRoomProtocol : public LobbyRoomProtocol
virtual void setup();
virtual void update();
void startGame();
protected:
void kartDisconnected(Event* event);
void connectionRequested(Event* event);

View File

@ -1,6 +1,12 @@
#include "network/protocols/start_game_protocol.hpp"
#include "network/network_manager.hpp"
#include "network/protocol_manager.hpp"
#include "network/game_setup.hpp"
#include "network/protocols/synchronization_protocol.hpp"
#include "race/race_manager.hpp"
#include "utils/log.hpp"
#include "utils/time.hpp"
StartGameProtocol::StartGameProtocol(GameSetup* game_setup) :
Protocol(NULL, PROTOCOL_START_GAME)
@ -9,8 +15,10 @@ StartGameProtocol::StartGameProtocol(GameSetup* game_setup) :
std::vector<NetworkPlayerProfile*> players = m_game_setup->getPlayers();
for (unsigned int i = 0; i < players.size(); i++)
{
m_player_states.push_back(std::pair<NetworkPlayerProfile*, STATE>(players[i], LOADING));
m_player_states.insert(std::pair<NetworkPlayerProfile*, STATE>(players[i], LOADING));
}
m_ready_count = 0;
m_ready = NULL;
}
StartGameProtocol::~StartGameProtocol()
@ -19,19 +27,78 @@ StartGameProtocol::~StartGameProtocol()
void StartGameProtocol::notifyEvent(Event* event)
{
if (event->data.size() < 5)
{
Log::error("StartGameProtocol", "Too short message.");
return;
}
uint32_t token = event->data.gui32(0);
uint8_t ready = event->data.gui8(4);
STKPeer* peer = (*(event->peer));
if (peer->getClientServerToken() != token)
{
Log::error("StartGameProtocol", "Bad token received.");
return;
}
if (m_listener->isServer() && ready) // on server, player is ready
{
m_player_states[peer->getPlayerProfile()] = READY;
m_ready_count++;
if (m_ready_count == m_game_setup->getPlayerCount())
{
// everybody ready, synchronize
SynchronizationProtocol* protocol = static_cast<SynchronizationProtocol*>(m_listener->getProtocol(PROTOCOL_SYNCHRONIZATION));
protocol->startCountdown(m_ready, 5000); // 5 seconds countdown
Log::info("StartGameProtocol", "All players ready, starting countdown.");
m_state = READY;
}
}
// on the client, we shouldn't even receive messages.
}
void StartGameProtocol::setup()
{
m_state = LOADING;
race_manager->setNumKarts(m_game_setup->getPlayerCount());
race_manager->setNumPlayers(m_game_setup->getPlayerCount());
race_manager->setNumLocalPlayers(1);
std::vector<NetworkPlayerProfile*> players = m_game_setup->getPlayers();
for (unsigned int i = 0; i < players.size(); i++)
{
NetworkPlayerProfile* profile = players[i];
RemoteKartInfo rki(profile->race_id, profile->kart_name, profile->user_profile->getUserName(), profile->race_id);
rki.setGlobalPlayerId(profile->race_id);
rki.setLocalPlayerId(profile->race_id);
rki.setHostId(profile->race_id);
race_manager->setPlayerKart(i, rki);
}
// if no synchronization protocol exists, create one
SynchronizationProtocol* protocol = static_cast<SynchronizationProtocol*>(m_listener->getProtocol(PROTOCOL_SYNCHRONIZATION));
if (!protocol)
m_listener->requestStart(new SynchronizationProtocol());
}
void StartGameProtocol::update()
{
if (m_state == LOADING)
{
}
else if (m_state == READY)
{
m_listener->requestTerminate(this);
}
}
void StartGameProtocol::ready() // on clients, means the loading is finished
{
assert(m_listener->isServer() == false);
assert(NetworkManager::getInstance()->getPeerCount() == 1);
NetworkString ns;
ns.ai32(NetworkManager::getInstance()->getPeers()[0]->getClientServerToken()).ai8(1);
}
void StartGameProtocol::onReadyChange(bool* start)
{
m_ready = start;
}

View File

@ -2,6 +2,7 @@
#define START_GAME_PROTOCOL_HPP
#include "network/protocol.hpp"
#include <map>
class GameSetup;
class NetworkPlayerProfile;
@ -10,9 +11,12 @@ class StartGameProtocol : public Protocol
{
protected:
enum STATE { LOADING, READY };
std::vector<std::pair<NetworkPlayerProfile*, STATE> > m_player_states;
std::map<NetworkPlayerProfile*, STATE> m_player_states;
GameSetup* m_game_setup;
bool* m_ready; //!< Set to true when the game can start
int m_ready_count;
double m_sending_time;
STATE m_state;
@ -24,6 +28,9 @@ class StartGameProtocol : public Protocol
virtual void setup();
virtual void update();
void ready();
void onReadyChange(bool* start);
};
#endif // START_GAME_PROTOCOL_HPP

View File

@ -5,14 +5,19 @@
//-----------------------------------------------------------------------------
SynchronizationProtocol::SynchronizationProtocol(uint32_t* ping, bool* successed) : Protocol(NULL, PROTOCOL_SYNCHRONIZATION)
SynchronizationProtocol::SynchronizationProtocol() : Protocol(NULL, PROTOCOL_SYNCHRONIZATION)
{
m_average_ping = ping;
m_successed = successed;
m_pings.resize(NetworkManager::getInstance()->getPeerCount(), std::vector<std::pair<double,double> >(0));
m_pings_count = 0;
m_successed_pings = 0;
m_total_diff = 0;
unsigned int size = NetworkManager::getInstance()->getPeerCount();
m_pings.resize(size, std::map<uint32_t,double>());
m_pings_count.resize(size);
for (unsigned int i = 0; i < size; i++)
{
m_pings_count[i] = 0;
}
m_successed_pings.resize(size);
m_total_diff.resize(size);
m_average_ping.resize(size);
m_ready = NULL;
}
//-----------------------------------------------------------------------------
@ -69,16 +74,14 @@ void SynchronizationProtocol::notifyEvent(Event* event)
Log::warn("SynchronizationProtocol", "The sequence# %u isn't known.", sequence);
return;
}
m_pings[peer_id][sequence].second = Time::getRealTime();
m_total_diff += (m_pings[peer_id][sequence].second - m_pings[peer_id][sequence].first);
Log::verbose("SynchronizationProtocol", "InstantPing is %u", (unsigned int)((m_pings[peer_id][sequence].second - m_pings[peer_id][sequence].first)*1000));
m_successed_pings++;
*m_average_ping = (int)((m_total_diff/m_successed_pings)*1000.0);
if ( *m_successed == false && m_successed_pings > 5)
{
*m_successed = true; // success after 5 pings (we have good idea of ping)
}
Log::verbose("SynchronizationProtocol", "Ping is %u", *m_average_ping);
double current_time = Time::getRealTime();
m_total_diff[peer_id] += current_time - m_pings[peer_id][sequence];
Log::verbose("SynchronizationProtocol", "InstantPing is %u",
(unsigned int)((current_time - m_pings[peer_id][sequence])*1000));
m_successed_pings[peer_id]++;
m_average_ping[peer_id] = (int)((m_total_diff[peer_id]/m_successed_pings[peer_id])*1000.0);
Log::verbose("SynchronizationProtocol", "Ping is %u", m_average_ping[peer_id]);
}
}
@ -93,7 +96,7 @@ void SynchronizationProtocol::setup()
void SynchronizationProtocol::update()
{
static double timer = Time::getRealTime();
if (Time::getRealTime() > timer+0.1 && m_pings_count < 100) // max 100 pings (10 seconds)
if (Time::getRealTime() > timer+0.1)
{
std::vector<STKPeer*> peers = NetworkManager::getInstance()->getPeers();
for (unsigned int i = 0; i < peers.size(); i++)
@ -102,11 +105,17 @@ void SynchronizationProtocol::update()
ns.ai8(i).addUInt32(peers[i]->getClientServerToken()).addUInt8(1).addUInt32(m_pings[i].size());
Log::verbose("SynchronizationProtocol", "Added sequence number %u", m_pings[i].size());
timer = Time::getRealTime();
m_pings[i].push_back(std::pair<double, double>(timer, 0.0));
m_pings[i].insert(std::pair<int,double>(m_pings_count[i], timer));
m_listener->sendMessage(this, peers[i], ns, false);
m_pings_count[i]++;
}
m_pings_count++;
}
}
//-----------------------------------------------------------------------------
void SynchronizationProtocol::startCountdown(bool* ready, uint32_t ms_countdown)
{
m_ready = ready;
}

View File

@ -2,27 +2,28 @@
#define SYNCHRONIZATION_PROTOCOL_HPP
#include "network/protocol.hpp"
#include <list>
#include <utility>
#include <vector>
#include <map>
class SynchronizationProtocol : public Protocol
{
public:
SynchronizationProtocol(uint32_t* ping, bool* successed);
SynchronizationProtocol();
virtual ~SynchronizationProtocol();
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
void startCountdown(bool* ready, uint32_t ms_countdown);
protected:
//!< stores the start time / arrival time of packets for each peer
std::vector<std::vector<std::pair<double, double> > > m_pings;
uint32_t* m_average_ping;
uint32_t m_pings_count;
uint32_t m_successed_pings;
double m_total_diff;
bool* m_successed;
std::vector<std::map<uint32_t, double> > m_pings;
std::vector<uint32_t> m_average_ping;
std::vector<uint32_t> m_pings_count;
std::vector<uint32_t> m_successed_pings;
std::vector<double> m_total_diff;
bool* m_ready;
};
#endif // SYNCHRONIZATION_PROTOCOL_HPP

View File

@ -24,6 +24,7 @@
#include "network/protocols/get_peer_address.hpp"
#include "network/protocols/connect_to_server.hpp"
#include "network/protocols/stop_server.hpp"
#include "network/protocols/server_lobby_room_protocol.hpp"
#include "main_loop.hpp"
#include "utils/log.hpp"
@ -49,6 +50,12 @@ void* waitInput2(void* data)
{
ServerNetworkManager::getInstance()->kickAllPlayers();
}
else if (str == "start")
{
ServerLobbyRoomProtocol* protocol = static_cast<ServerLobbyRoomProtocol*>(ProtocolManager::getInstance()->getProtocol(PROTOCOL_LOBBY_ROOM));
assert(protocol);
protocol->startGame();
}
}
uint32_t id = ProtocolManager::getInstance()->requestStart(new StopServer());

View File

@ -42,6 +42,8 @@
#include "modes/world.hpp"
#include "modes/three_strikes_battle.hpp"
#include "modes/soccer_world.hpp"
#include "network/protocol_manager.hpp"
#include "network/protocols/start_game_protocol.hpp"
#include "states_screens/grand_prix_lose.hpp"
#include "states_screens/grand_prix_win.hpp"
#include "states_screens/kart_selection.hpp"
@ -460,6 +462,17 @@ void RaceManager::startNextRace()
m_kart_status[i].m_last_time = 0;
}
StartGameProtocol* protocol = static_cast<StartGameProtocol*>(
ProtocolManager::getInstance()->getProtocol(PROTOCOL_START_GAME));
if (protocol) // if this protocol exists, that's that we play online
{
bool ready = false;
protocol->ready();
protocol->onReadyChange(&ready);
while(!ready) // wait the protocol to say we can start
{
}
}
} // startNextRace
//-----------------------------------------------------------------------------
@ -775,23 +788,23 @@ void RaceManager::startSingleRace(const std::string &track_ident,
*/
void RaceManager::setupPlayerKartInfo()
{
std::vector<RemoteKartInfo> m_kart_info;
std::vector<RemoteKartInfo> kart_info;
// Get the local kart info
for(unsigned int i=0; i<getNumLocalPlayers(); i++)
m_kart_info.push_back(getLocalKartInfo(i));
kart_info.push_back(getLocalKartInfo(i));
// Now sort by (hostid, playerid)
std::sort(m_kart_info.begin(), m_kart_info.end());
std::sort(kart_info.begin(), kart_info.end());
// Set the player kart information
setNumPlayers(m_kart_info.size());
setNumPlayers(kart_info.size());
// Set the global player ID for each player
for(unsigned int i=0; i<m_kart_info.size(); i++)
for(unsigned int i=0; i<kart_info.size(); i++)
{
m_kart_info[i].setGlobalPlayerId(i);
setPlayerKart(i, m_kart_info[i]);
kart_info[i].setGlobalPlayerId(i);
setPlayerKart(i, kart_info[i]);
}
computeRandomKartList();