/*! \brief Called when a player asks to select a kart. * \param event : Event providing the information. * * Format of the data : * Byte 0 1 5 6 N+6 * --------------------------------------------------- * Size | 1 | 4 | 1 | N | * Data | 4 | priv token | N (kart name size) | kart name | * --------------------------------------------------- */ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event) { NetworkString data = event->data(); STKPeer* peer = *(event->peer); if (!checkDataSizeAndToken(event, 6)) return; uint8_t kart_name_size = data.gui8(5); std::string kart_name = data.gs(6, kart_name_size); if (kart_name.size() != kart_name_size) { Log::error("ServerLobbyRoomProtocol", "Kart names sizes differ: told:" "%d, real: %d.", kart_name_size, kart_name.size()); return; } // check if selection is possible if (!m_selection_enabled) { NetworkString answer; answer.ai8(0x82).ai8(1).ai8(2); // selection still not started m_listener->sendMessage(this, peer, answer); return; } // check if somebody picked that kart if (!m_setup->isKartAvailable(kart_name)) { NetworkString answer; answer.ai8(0x82).ai8(1).ai8(0); // kart is already taken m_listener->sendMessage(this, peer, answer); return; } // check if this kart is authorized if (!m_setup->isKartAllowed(kart_name)) { NetworkString answer; answer.ai8(0x82).ai8(1).ai8(1); // kart is not authorized m_listener->sendMessage(this, peer, answer); return; } // send a kart update to everyone NetworkString answer; // kart update (3), 1, race id answer.ai8(0x03).ai8(1).ai8(peer->getPlayerProfile()->race_id); // kart name size, kart name answer.ai8(kart_name.size()).as(kart_name); m_listener->sendMessage(this, answer); m_setup->setPlayerKart(peer->getPlayerProfile()->race_id, kart_name); }
void ProtocolManager::sendMessageExcept(Protocol* sender, STKPeer* peer, const NetworkString& message, bool reliable) { NetworkString newMessage; newMessage.ai8(sender->getProtocolType()); // add one byte to add protocol type newMessage += message; NetworkManager::getInstance()->sendPacketExcept(peer, newMessage, reliable); }
/*! \brief Called when a player votes for a minor race mode. * \param event : Event providing the information. * * Format of the data : * Byte 0 1 5 6 7 * ---------------------------------------- * Size | 1 | 4 | 1 | 1 | * Data | 4 | priv token | 1 | minor mode vote | * ---------------------------------------- */ void ServerLobbyRoomProtocol::playerMinorVote(Event* event) { NetworkString data = event->data(); STKPeer* peer = *(event->peer); if (!checkDataSizeAndToken(event, 7)) return; if (!isByteCorrect(event, 5, 1)) return; uint8_t player_id = peer->getPlayerProfile()->race_id; m_setup->getRaceConfig()->setPlayerMinorVote(player_id, data[6]); // Send the vote to everybody (including the sender) NetworkString other; other.ai8(1).ai8(player_id); // add the player id data.removeFront(5); // remove the token other += data; // add the data NetworkString prefix; prefix.ai8(0xc2); // prefix the token with the ype sendMessageToPeersChangingToken(prefix, other); }
void ServerLobbyRoomProtocol::startSelection() { std::vector<STKPeer*> peers = NetworkManager::getInstance()->getPeers(); for (unsigned int i = 0; i < peers.size(); i++) { NetworkString ns; ns.ai8(0x05).ai8(4).ai32(peers[i]->getClientServerToken()); // start selection m_listener->sendMessage(this, peers[i], ns, true); // reliably } m_selection_enabled = true; }
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 m_listener->sendMessage(this, peers[i], ns, true); // reliably } m_listener->requestStart(new StartGameProtocol(m_setup)); m_in_race = true; }
void SynchronizationProtocol::asynchronousUpdate() { static double timer = StkTime::getRealTime(); double current_time = StkTime::getRealTime(); if (m_countdown_activated) { m_countdown -= (current_time - m_last_countdown_update); m_last_countdown_update = current_time; Log::debug("SynchronizationProtocol", "Update! Countdown remaining : %f", m_countdown); if (m_countdown < 0.0 && !m_has_quit) { m_has_quit = true; Log::info("SynchronizationProtocol", "Countdown finished. Starting now."); m_listener->requestStart(new KartUpdateProtocol()); m_listener->requestStart(new ControllerEventsProtocol()); m_listener->requestStart(new GameEventsProtocol()); m_listener->requestTerminate(this); return; } static int seconds = -1; if (seconds == -1) { seconds = (int)(ceil(m_countdown)); } else if (seconds != (int)(ceil(m_countdown))) { seconds = (int)(ceil(m_countdown)); Log::info("SynchronizationProtocol", "Starting in %d seconds.", seconds); } } if (current_time > timer+0.1) { std::vector<STKPeer*> peers = NetworkManager::getInstance()->getPeers(); for (unsigned int i = 0; i < peers.size(); i++) { NetworkString ns; ns.ai8(i).addUInt32(peers[i]->getClientServerToken()).addUInt8(1).addUInt32(m_pings[i].size()); // now add the countdown if necessary if (m_countdown_activated && m_listener->isServer()) { ns.addUInt32((int)(m_countdown*1000.0)); Log::debug("SynchronizationProtocol", "CNTActivated: Countdown value : %f", m_countdown); } Log::verbose("SynchronizationProtocol", "Added sequence number %u for peer %d", m_pings[i].size(), i); timer = current_time; 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]++; } } }
void ServerLobbyRoomProtocol::kartDisconnected(Event* event) { STKPeer* peer = *(event->peer); if (peer->getPlayerProfile() != NULL) // others knew him { NetworkString msg; msg.ai8(0x02).ai8(1).ai8(peer->getPlayerProfile()->race_id); m_listener->sendMessage(this, msg); Log::info("ServerLobbyRoomProtocol", "Player disconnected : id %d", peer->getPlayerProfile()->race_id); m_setup->removePlayer(peer->getPlayerProfile()->race_id); NetworkManager::getInstance()->removePeer(peer); } else Log::info("ServerLobbyRoomProtocol", "The DC peer wasn't registered."); }
bool SynchronizationProtocol::notifyEventAsynchronous(Event* event) { if (event->type != EVENT_TYPE_MESSAGE) return true; NetworkString data = event->data(); if (data.size() < 10) { Log::warn("SynchronizationProtocol", "Received a message too short."); return true; } uint8_t talk_id = data.gui8(); uint32_t token = data.gui32(1); uint32_t request = data.gui8(5); uint32_t sequence = data.gui32(6); std::vector<STKPeer*> peers = NetworkManager::getInstance()->getPeers(); assert(peers.size() > 0); if (m_listener->isServer()) { if (talk_id > peers.size()) { Log::warn("SynchronizationProtocol", "The ID isn't known."); return true; } } uint8_t peer_id = 0; for (unsigned int i = 0; i < peers.size(); i++) { if (peers[i]->isSamePeer(*event->peer)) { peer_id = i; } } if (peers[peer_id]->getClientServerToken() != token) { Log::warn("SynchronizationProtocol", "Bad token from peer %d", talk_id); return true; } if (request) { NetworkString response; response.ai8(data.gui8(talk_id)).ai32(token).ai8(0).ai32(sequence); m_listener->sendMessage(this, peers[peer_id], response, false); Log::verbose("SynchronizationProtocol", "Answering sequence %u", sequence); if (data.size() == 14 && !m_listener->isServer()) // countdown time in the message { uint32_t time_to_start = data.gui32(10); Log::debug("SynchronizationProtocol", "Request to start game in %d.", time_to_start); if (!m_countdown_activated) startCountdown(time_to_start); else m_countdown = (double)(time_to_start/1000.0); } else Log::verbose("SynchronizationProtocol", "No countdown for now."); } else // response { if (sequence >= m_pings[peer_id].size()) { Log::warn("SynchronizationProtocol", "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]; 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::debug("SynchronizationProtocol", "Ping is %u", m_average_ping[peer_id]); } return true; }
/*! \brief Called when a player asks for a connection. * \param event : Event providing the information. * * Format of the data : * Byte 0 1 5 * ------------------------ * Size | 1 | 4 | * Data | 4 | global player id | * ------------------------ */ void ServerLobbyRoomProtocol::connectionRequested(Event* event) { STKPeer* peer = *(event->peer); NetworkString data = event->data(); if (data.size() != 5 || data[0] != 4) { Log::warn("ServerLobbyRoomProtocol", "Receiving badly formated message. Size is %d and first byte %d", data.size(), data[0]); return; } uint32_t player_id = 0; player_id = data.getUInt32(1); // can we add the player ? if (m_setup->getPlayerCount() < ServerNetworkManager::getInstance()->getMaxPlayers()) //accept { // add the player to the game setup m_next_id = m_setup->getPlayerCount(); // notify everybody that there is a new player NetworkString message; // new player (1) -- size of id -- id -- size of local id -- local id; message.ai8(1).ai8(4).ai32(player_id).ai8(1).ai8(m_next_id); m_listener->sendMessageExcept(this, peer, message); /// now answer to the peer that just connected RandomGenerator token_generator; // use 4 random numbers because rand_max is probably 2^15-1. uint32_t token = (uint32_t)(((token_generator.get(RAND_MAX)<<24) & 0xff) + ((token_generator.get(RAND_MAX)<<16) & 0xff) + ((token_generator.get(RAND_MAX)<<8) & 0xff) + ((token_generator.get(RAND_MAX) & 0xff))); // send a message to the one that asked to connect NetworkString message_ack; // connection success (129) -- size of token -- token message_ack.ai8(0x81).ai8(1).ai8(m_next_id).ai8(4).ai32(token).ai8(4).ai32(player_id); // add all players so that this user knows std::vector<NetworkPlayerProfile*> players = m_setup->getPlayers(); for (unsigned int i = 0; i < players.size(); i++) { // do not duplicate the player into the message if (players[i]->race_id != m_next_id && players[i]->user_profile->getID() != player_id) message_ack.ai8(1).ai8(players[i]->race_id).ai8(4).ai32(players[i]->user_profile->getID()); } m_listener->sendMessage(this, peer, message_ack); peer->setClientServerToken(token); NetworkPlayerProfile* profile = new NetworkPlayerProfile(); profile->race_id = m_next_id; profile->kart_name = ""; profile->user_profile = new Online::OnlineProfile(player_id, ""); m_setup->addPlayer(profile); peer->setPlayerProfile(profile); Log::verbose("ServerLobbyRoomProtocol", "New player."); } // accept player else // refuse the connection with code 0 (too much players) { NetworkString message; message.ai8(0x80); // 128 means connection refused message.ai8(1); // 1 bytes for the error code message.ai8(0); // 0 = too much players // send only to the peer that made the request m_listener->sendMessage(this, peer, message); Log::verbose("ServerLobbyRoomProtocol", "Player refused"); } }
void ServerLobbyRoomProtocol::checkRaceFinished() { assert(NetworkWorld::getInstance()->isRunning()); assert(World::getWorld()); // if race is over, give the final score to everybody if (NetworkWorld::getInstance()->isRaceOver()) { // calculate karts ranks : int num_players = race_manager->getNumberOfKarts(); std::vector<int> karts_results; std::vector<float> karts_times; for (int j = 0; j < num_players; j++) { float kart_time = race_manager->getKartRaceTime(j); for (unsigned int i = 0; i < karts_times.size(); i++) { if (kart_time < karts_times[i]) { karts_times.insert(karts_times.begin()+i, kart_time); karts_results.insert(karts_results.begin()+i, j); break; } } } std::vector<STKPeer*> peers = NetworkManager::getInstance()->getPeers(); NetworkString queue; for (unsigned int i = 0; i < karts_results.size(); i++) { queue.ai8(1).ai8(karts_results[i]); // kart pos = i+1 Log::info("ServerLobbyRoomProtocol", "Kart %d finished #%d", karts_results[i], i+1); } for (unsigned int i = 0; i < peers.size(); i++) { NetworkString ns; ns.ai8(0x06).ai8(4).ai32(peers[i]->getClientServerToken()); NetworkString total = ns + queue; m_listener->sendMessage(this, peers[i], total, true); } Log::info("ServerLobbyRoomProtocol", "End of game message sent"); m_in_race = false; // stop race protocols Protocol* protocol = NULL; protocol = m_listener->getProtocol(PROTOCOL_CONTROLLER_EVENTS); if (protocol) m_listener->requestTerminate(protocol); else Log::error("ClientLobbyRoomProtocol", "No controller events protocol registered."); protocol = m_listener->getProtocol(PROTOCOL_KART_UPDATE); if (protocol) m_listener->requestTerminate(protocol); else Log::error("ClientLobbyRoomProtocol", "No kart update protocol registered."); protocol = m_listener->getProtocol(PROTOCOL_GAME_EVENTS); if (protocol) m_listener->requestTerminate(protocol); else Log::error("ClientLobbyRoomProtocol", "No game events protocol registered."); // notify the network world that it is stopped NetworkWorld::getInstance()->stop(); // exit the race now race_manager->exitRace(); race_manager->setAIKartOverride(""); } else { //Log::info("ServerLobbyRoomProtocol", "Phase is %d", World::getWorld()->getPhase()); } }