stk-code_catmod/src/network/protocols/start_game_protocol.cpp

210 lines
7.9 KiB
C++

#include "network/protocols/start_game_protocol.hpp"
#include "config/player_manager.hpp"
#include "input/device_manager.hpp"
#include "input/input_manager.hpp"
#include "challenges/unlock_manager.hpp"
#include "modes/world.hpp"
#include "network/network_manager.hpp"
#include "network/protocol_manager.hpp"
#include "network/game_setup.hpp"
#include "network/network_world.hpp"
#include "network/protocols/synchronization_protocol.hpp"
#include "online/online_profile.hpp"
#include "race/race_manager.hpp"
#include "states_screens/kart_selection.hpp"
#include "states_screens/network_kart_selection.hpp"
#include "utils/log.hpp"
#include "utils/time.hpp"
StartGameProtocol::StartGameProtocol(GameSetup* game_setup)
: Protocol(NULL, PROTOCOL_START_GAME)
{
m_game_setup = game_setup;
std::vector<NetworkPlayerProfile*> players = m_game_setup->getPlayers();
for (unsigned int i = 0; i < players.size(); i++)
{
m_player_states.insert(std::pair<NetworkPlayerProfile*, STATE>(players[i], LOADING));
}
m_ready_count = 0;
}
StartGameProtocol::~StartGameProtocol()
{
}
bool StartGameProtocol::notifyEventAsynchronous(Event* event)
{
NetworkString data = event->data();
if (data.size() < 5)
{
Log::error("StartGameProtocol", "Too short message.");
return true;
}
uint32_t token = data.gui32();
uint8_t ready = data.gui8(4);
STKPeer* peer = (*(event->peer));
if (peer->getClientServerToken() != token)
{
Log::error("StartGameProtocol", "Bad token received.");
return true;
}
if (m_listener->isServer() && ready) // on server, player is ready
{
Log::info("StartGameProtocol", "One of the players 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));
if (protocol)
{
protocol->startCountdown(5000); // 5 seconds countdown
Log::info("StartGameProtocol", "All players ready, starting countdown.");
m_ready = true;
return true;
}
else
Log::error("StartGameProtocol", "The Synchronization protocol hasn't been started.");
}
}
else // on the client, we shouldn't even receive messages.
{
Log::error("StartGameProtocol", "Received a message with bad format.");
}
return true;
}
void StartGameProtocol::setup()
{
m_state = NONE;
m_ready_count = 0;
m_ready = false;
Log::info("SynchronizationProtocol", "Ready !");
}
bool sort_karts (NetworkPlayerProfile* a, NetworkPlayerProfile* b)
{ return (a->race_id < b->race_id); }
void StartGameProtocol::update()
{
if (m_state == NONE)
{
// if no synchronization protocol exists, create one
m_listener->requestStart(new SynchronizationProtocol());
Log::info("StartGameProtocol", "SynchronizationProtocol started.");
// race startup sequence
NetworkWorld::getInstance<NetworkWorld>()->start(); // builds it and starts
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();
std::sort(players.begin(), players.end(), sort_karts);
// have to add self first
for (unsigned int i = 0; i < players.size(); i++)
{
bool is_me = (players[i]->user_profile ==
PlayerManager::getCurrentOnlineProfile());
if (is_me)
{
NetworkPlayerProfile* profile = players[i];
RemoteKartInfo rki(profile->race_id, profile->kart_name,
profile->user_profile->getUserName(), profile->race_id, !is_me);
rki.setGlobalPlayerId(profile->race_id);
rki.setLocalPlayerId(is_me?0:1);
rki.setHostId(profile->race_id);
PlayerProfile* profile_to_use = PlayerManager::getCurrentPlayer();
assert(profile_to_use);
InputDevice* device = input_manager->getDeviceList()->getLatestUsedDevice();
int new_player_id = 0;
if (StateManager::get()->getActivePlayers().size() >= 1) // more than one player, we're the first
new_player_id = 0;
else
new_player_id = StateManager::get()->createActivePlayer( profile_to_use, device);
device->setPlayer(StateManager::get()->getActivePlayer(new_player_id));
input_manager->getDeviceList()->setSinglePlayer(StateManager::get()->getActivePlayer(new_player_id));
race_manager->setPlayerKart(i, rki);
race_manager->setLocalKartInfo(new_player_id, profile->kart_name);
Log::info("StartGameProtocol", "Self player device added."); // self config
NetworkWorld::getInstance()->m_self_kart = profile->kart_name;
}
}
for (unsigned int i = 0; i < players.size(); i++)
{
bool is_me = (players[i]->user_profile ==
PlayerManager::getCurrentOnlineProfile());
NetworkPlayerProfile* profile = players[i];
RemoteKartInfo rki(profile->race_id, profile->kart_name,
profile->user_profile->getUserName(), profile->race_id, !is_me);
rki.setGlobalPlayerId(profile->race_id);
// on the server, the race id must be the local one.
rki.setLocalPlayerId(m_listener->isServer()?profile->race_id:(is_me?0:1));
rki.setHostId(profile->race_id);
Log::info("StartGameProtocol", "Creating kart %s for Player#%d with race_id %d", profile->kart_name.c_str(), i, profile->race_id);
if (!is_me)
{
StateManager::get()->createActivePlayer( NULL, NULL );
race_manager->setPlayerKart(i, rki);
}
}
race_manager->computeRandomKartList();
Log::info("StartGameProtocol", "Player configuration ready.");
m_state = SYNCHRONIZATION_WAIT;
/*
KartSelectionScreen* s = KartSelectionScreen::getInstance();
s->setMultiplayer(false);
s->setFromOverworld(false);
s->push();*/
}
else if (m_state == SYNCHRONIZATION_WAIT)
{
SynchronizationProtocol* protocol = static_cast<SynchronizationProtocol*>
(m_listener->getProtocol(PROTOCOL_SYNCHRONIZATION));
if (protocol)
{
// now the synchronization protocol exists.
Log::info("StartGameProtocol", "Starting the race loading.");
race_manager->startSingleRace("jungle", 1, false);
World::getWorld()->setNetworkWorld(true);
m_state = LOADING;
}
}
else if (m_state == LOADING)
{
if (m_ready)
{
m_state = READY;
}
}
else if (m_state == READY)
{
// set karts into the network game setup
NetworkManager::getInstance()->getGameSetup()->bindKartsToProfiles();
m_state = EXITING;
m_listener->requestTerminate(this);
}
}
void StartGameProtocol::ready() // on clients, means the loading is finished
{
if (!m_listener->isServer()) // if we're a client
{
assert(NetworkManager::getInstance()->getPeerCount() == 1);
NetworkString ns;
ns.ai32(NetworkManager::getInstance()->getPeers()[0]->getClientServerToken()).ai8(1);
Log::info("StartGameProtocol", "Player ready, notifying server.");
m_listener->sendMessage(this, ns, true);
m_state = READY;
m_ready = true;
return;
}
else // on the server
{
}
}