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

View File

@ -19,6 +19,7 @@
#include "network/protocols/client_lobby_room_protocol.hpp" #include "network/protocols/client_lobby_room_protocol.hpp"
#include "network/network_manager.hpp" #include "network/network_manager.hpp"
#include "network/protocols/start_game_protocol.hpp"
#include "online/current_online_user.hpp" #include "online/current_online_user.hpp"
#include "utils/log.hpp" #include "utils/log.hpp"
@ -70,6 +71,8 @@ void ClientLobbyRoomProtocol::notifyEvent(Event* event)
disconnectedPlayer(event); disconnectedPlayer(event);
else if (message_type == 0x03) // kart selection update else if (message_type == 0x03) // kart selection update
kartSelectionUpdate(event); kartSelectionUpdate(event);
else if (message_type == 0x04) // start race
startGame(event);
else if (message_type == 0x80) // connection refused else if (message_type == 0x80) // connection refused
connectionRefused(event); connectionRefused(event);
else if (message_type == 0x81) // connection accepted 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 connectionRefused(Event* event); //!< Callback function on connection refusal
void kartSelectionRefused(Event* event); void kartSelectionRefused(Event* event);
void kartSelectionUpdate(Event* event); void kartSelectionUpdate(Event* event);
void startGame(Event* event);
TransportAddress m_server_address; TransportAddress m_server_address;
STKPeer* m_server; STKPeer* m_server;

View File

@ -159,6 +159,19 @@ void ServerLobbyRoomProtocol::update()
break; 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) void ServerLobbyRoomProtocol::kartDisconnected(Event* event)

View File

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

View File

@ -1,6 +1,12 @@
#include "network/protocols/start_game_protocol.hpp" #include "network/protocols/start_game_protocol.hpp"
#include "network/network_manager.hpp"
#include "network/protocol_manager.hpp"
#include "network/game_setup.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) : StartGameProtocol::StartGameProtocol(GameSetup* game_setup) :
Protocol(NULL, PROTOCOL_START_GAME) Protocol(NULL, PROTOCOL_START_GAME)
@ -9,8 +15,10 @@ StartGameProtocol::StartGameProtocol(GameSetup* game_setup) :
std::vector<NetworkPlayerProfile*> players = m_game_setup->getPlayers(); std::vector<NetworkPlayerProfile*> players = m_game_setup->getPlayers();
for (unsigned int i = 0; i < players.size(); i++) 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() StartGameProtocol::~StartGameProtocol()
@ -19,19 +27,78 @@ StartGameProtocol::~StartGameProtocol()
void StartGameProtocol::notifyEvent(Event* event) 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() void StartGameProtocol::setup()
{ {
m_state = LOADING; 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() void StartGameProtocol::update()
{ {
if (m_state == LOADING) if (m_state == LOADING)
{ {
} }
else if (m_state == READY) 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 #define START_GAME_PROTOCOL_HPP
#include "network/protocol.hpp" #include "network/protocol.hpp"
#include <map>
class GameSetup; class GameSetup;
class NetworkPlayerProfile; class NetworkPlayerProfile;
@ -10,9 +11,12 @@ class StartGameProtocol : public Protocol
{ {
protected: protected:
enum STATE { LOADING, READY }; enum STATE { LOADING, READY };
std::vector<std::pair<NetworkPlayerProfile*, STATE> > m_player_states; std::map<NetworkPlayerProfile*, STATE> m_player_states;
GameSetup* m_game_setup; 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; STATE m_state;
@ -24,6 +28,9 @@ class StartGameProtocol : public Protocol
virtual void setup(); virtual void setup();
virtual void update(); virtual void update();
void ready();
void onReadyChange(bool* start);
}; };
#endif // START_GAME_PROTOCOL_HPP #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; unsigned int size = NetworkManager::getInstance()->getPeerCount();
m_successed = successed; m_pings.resize(size, std::map<uint32_t,double>());
m_pings.resize(NetworkManager::getInstance()->getPeerCount(), std::vector<std::pair<double,double> >(0)); m_pings_count.resize(size);
m_pings_count = 0; for (unsigned int i = 0; i < size; i++)
m_successed_pings = 0; {
m_total_diff = 0; 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); Log::warn("SynchronizationProtocol", "The sequence# %u isn't known.", sequence);
return; return;
} }
m_pings[peer_id][sequence].second = Time::getRealTime(); double current_time = Time::getRealTime();
m_total_diff += (m_pings[peer_id][sequence].second - m_pings[peer_id][sequence].first); m_total_diff[peer_id] += current_time - m_pings[peer_id][sequence];
Log::verbose("SynchronizationProtocol", "InstantPing is %u", (unsigned int)((m_pings[peer_id][sequence].second - m_pings[peer_id][sequence].first)*1000)); Log::verbose("SynchronizationProtocol", "InstantPing is %u",
m_successed_pings++; (unsigned int)((current_time - m_pings[peer_id][sequence])*1000));
*m_average_ping = (int)((m_total_diff/m_successed_pings)*1000.0); m_successed_pings[peer_id]++;
if ( *m_successed == false && m_successed_pings > 5) m_average_ping[peer_id] = (int)((m_total_diff[peer_id]/m_successed_pings[peer_id])*1000.0);
{
*m_successed = true; // success after 5 pings (we have good idea of ping) Log::verbose("SynchronizationProtocol", "Ping is %u", m_average_ping[peer_id]);
}
Log::verbose("SynchronizationProtocol", "Ping is %u", *m_average_ping);
} }
} }
@ -93,7 +96,7 @@ void SynchronizationProtocol::setup()
void SynchronizationProtocol::update() void SynchronizationProtocol::update()
{ {
static double timer = Time::getRealTime(); 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(); std::vector<STKPeer*> peers = NetworkManager::getInstance()->getPeers();
for (unsigned int i = 0; i < peers.size(); i++) 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()); 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()); Log::verbose("SynchronizationProtocol", "Added sequence number %u", m_pings[i].size());
timer = Time::getRealTime(); 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_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 #define SYNCHRONIZATION_PROTOCOL_HPP
#include "network/protocol.hpp" #include "network/protocol.hpp"
#include <list> #include <vector>
#include <utility> #include <map>
class SynchronizationProtocol : public Protocol class SynchronizationProtocol : public Protocol
{ {
public: public:
SynchronizationProtocol(uint32_t* ping, bool* successed); SynchronizationProtocol();
virtual ~SynchronizationProtocol(); virtual ~SynchronizationProtocol();
virtual void notifyEvent(Event* event); virtual void notifyEvent(Event* event);
virtual void setup(); virtual void setup();
virtual void update(); virtual void update();
void startCountdown(bool* ready, uint32_t ms_countdown);
protected: protected:
//!< stores the start time / arrival time of packets for each peer std::vector<std::map<uint32_t, double> > m_pings;
std::vector<std::vector<std::pair<double, double> > > m_pings; std::vector<uint32_t> m_average_ping;
uint32_t* m_average_ping; std::vector<uint32_t> m_pings_count;
uint32_t m_pings_count; std::vector<uint32_t> m_successed_pings;
uint32_t m_successed_pings; std::vector<double> m_total_diff;
double m_total_diff; bool* m_ready;
bool* m_successed;
}; };
#endif // SYNCHRONIZATION_PROTOCOL_HPP #endif // SYNCHRONIZATION_PROTOCOL_HPP

View File

@ -24,6 +24,7 @@
#include "network/protocols/get_peer_address.hpp" #include "network/protocols/get_peer_address.hpp"
#include "network/protocols/connect_to_server.hpp" #include "network/protocols/connect_to_server.hpp"
#include "network/protocols/stop_server.hpp" #include "network/protocols/stop_server.hpp"
#include "network/protocols/server_lobby_room_protocol.hpp"
#include "main_loop.hpp" #include "main_loop.hpp"
#include "utils/log.hpp" #include "utils/log.hpp"
@ -49,6 +50,12 @@ void* waitInput2(void* data)
{ {
ServerNetworkManager::getInstance()->kickAllPlayers(); 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()); uint32_t id = ProtocolManager::getInstance()->requestStart(new StopServer());

View File

@ -42,6 +42,8 @@
#include "modes/world.hpp" #include "modes/world.hpp"
#include "modes/three_strikes_battle.hpp" #include "modes/three_strikes_battle.hpp"
#include "modes/soccer_world.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_lose.hpp"
#include "states_screens/grand_prix_win.hpp" #include "states_screens/grand_prix_win.hpp"
#include "states_screens/kart_selection.hpp" #include "states_screens/kart_selection.hpp"
@ -460,6 +462,17 @@ void RaceManager::startNextRace()
m_kart_status[i].m_last_time = 0; 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 } // startNextRace
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -775,23 +788,23 @@ void RaceManager::startSingleRace(const std::string &track_ident,
*/ */
void RaceManager::setupPlayerKartInfo() void RaceManager::setupPlayerKartInfo()
{ {
std::vector<RemoteKartInfo> m_kart_info; std::vector<RemoteKartInfo> kart_info;
// Get the local kart info // Get the local kart info
for(unsigned int i=0; i<getNumLocalPlayers(); i++) 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) // 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 // Set the player kart information
setNumPlayers(m_kart_info.size()); setNumPlayers(kart_info.size());
// Set the global player ID for each player // 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); kart_info[i].setGlobalPlayerId(i);
setPlayerKart(i, m_kart_info[i]); setPlayerKart(i, kart_info[i]);
} }
computeRandomKartList(); computeRandomKartList();