/*! \brief Called when a player asks to select a kart. * \param event : Event providing the information. * * Format of the data : * Byte 0 1 2 * ---------------------------------------------- * Size | 1 | 1 | N | * Data |player id | N (kart name size) | kart name | * ---------------------------------------------- */ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event) { if(m_state!=SELECTING) { Log::warn("Server", "Received kart selection while in state %d.", m_state); return; } if (!checkDataSize(event, 1)) return; const NetworkString &data = event->data(); STKPeer* peer = event->getPeer(); uint8_t player_id = data.getUInt8(); std::string kart_name; data.decodeString(&kart_name); // check if selection is possible if (!m_selection_enabled) { NetworkString *answer = getNetworkString(2); // selection still not started answer->addUInt8(LE_KART_SELECTION_REFUSED).addUInt8(2); peer->sendPacket(answer); delete answer; return; } // check if somebody picked that kart if (!m_setup->isKartAvailable(kart_name)) { NetworkString *answer = getNetworkString(2); // kart is already taken answer->addUInt8(LE_KART_SELECTION_REFUSED).addUInt8(0); peer->sendPacket(answer); delete answer; return; } // check if this kart is authorized if (!m_setup->isKartAllowed(kart_name)) { NetworkString *answer = getNetworkString(2); // kart is not authorized answer->addUInt8(LE_KART_SELECTION_REFUSED).addUInt8(1); peer->sendPacket(answer); delete answer; return; } // send a kart update to everyone NetworkString *answer = getNetworkString(3+kart_name.size()); // This message must be handled synchronously on the client. answer->setSynchronous(true); // kart update (3), 1, race id answer->addUInt8(LE_KART_SELECTION_UPDATE).addUInt8(player_id) .encodeString(kart_name); sendMessageToPeersChangingToken(answer); delete answer; m_setup->setPlayerKart(player_id, kart_name); } // kartSelectionRequested
// ---------------------------------------------------------------------------- void GameEventsProtocol::sendStartupBoost(uint8_t kart_id) { NetworkString *ns = getNetworkString(); ns->setSynchronous(true); ns->addUInt8(GE_STARTUP_BOOST).addUInt8(kart_id); sendToServer(ns, /*reliable*/true); delete ns; } // sendStartupBoost
/** This function is called from the server when a kart finishes a race. It * sends a notification to all clients about this event. * \param kart The kart that finished the race. * \param time The time at which the kart finished. */ void GameEventsProtocol::kartFinishedRace(AbstractKart *kart, float time) { NetworkString *ns = getNetworkString(20); ns->setSynchronous(true); ns->addUInt8(GE_KART_FINISHED_RACE).addUInt8(kart->getWorldKartId()) .addFloat(time); sendMessageToPeers(ns, /*reliable*/true); delete ns; } // kartFinishedRace
/** Checks if the race is finished, and if so informs the clients and switches * to state RESULT_DISPLAY, during which the race result gui is shown and all * clients can click on 'continue'. */ void ServerLobbyRoomProtocol::checkRaceFinished() { assert(RaceEventManager::getInstance()->isRunning()); assert(World::getWorld()); if(!RaceEventManager::getInstance()->isRaceOver()) return; m_player_ready_counter = 0; // Set the delay before the server forces all clients to exit the race // result screen and go back to the lobby m_timeout = (float)(StkTime::getRealTime()+15.0f); m_state = RESULT_DISPLAY; // calculate karts ranks : int num_karts = race_manager->getNumberOfKarts(); std::vector<int> karts_results; std::vector<float> karts_times; for (int j = 0; j < num_karts; 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; } } } const std::vector<STKPeer*> &peers = STKHost::get()->getPeers(); NetworkString *total = getNetworkString(1 + karts_results.size()); total->setSynchronous(true); total->addUInt8(LE_RACE_FINISHED); for (unsigned int i = 0; i < karts_results.size(); i++) { total->addUInt8(karts_results[i]); // kart pos = i+1 Log::info("ServerLobbyRoomProtocol", "Kart %d finished #%d", karts_results[i], i + 1); } sendMessageToPeersChangingToken(total, /*reliable*/ true); delete total; Log::info("ServerLobbyRoomProtocol", "End of game message sent"); } // checkRaceFinished
// ---------------------------------------------------------------------------- bool GameEventsProtocol::notifyEvent(Event* event) { // Avoid crash in case that we still receive race events when // the race is actually over. if (event->getType() != EVENT_TYPE_MESSAGE || !World::getWorld()) return true; NetworkString &data = event->data(); if (data.size() < 1) // for type { Log::warn("GameEventsProtocol", "Too short message."); return true; } uint8_t type = data.getUInt8(); CaptureTheFlag* ctf = dynamic_cast<CaptureTheFlag*>(World::getWorld()); FreeForAll* ffa = dynamic_cast<FreeForAll*>(World::getWorld()); SoccerWorld* sw = dynamic_cast<SoccerWorld*>(World::getWorld()); LinearWorld* lw = dynamic_cast<LinearWorld*>(World::getWorld()); switch (type) { case GE_KART_FINISHED_RACE: kartFinishedRace(data); break; case GE_RESET_BALL: { if (!sw) throw std::invalid_argument("No soccer world"); sw->handleResetBallFromServer(data); break; } case GE_PLAYER_GOAL: { if (!sw) throw std::invalid_argument("No soccer world"); sw->handlePlayerGoalFromServer(data); break; } case GE_BATTLE_KART_SCORE: { if (!ffa) throw std::invalid_argument("No free-for-all world"); ffa->setKartScoreFromServer(data); break; } case GE_CTF_SCORED: { if (!ctf) throw std::invalid_argument("No CTF world"); uint8_t kart_id = data.getUInt8(); bool red_team_scored = data.getUInt8() == 1; int16_t new_kart_scores = data.getUInt16(); int new_red_scores = data.getUInt8(); int new_blue_scores = data.getUInt8(); ctf->ctfScored(kart_id, red_team_scored, new_kart_scores, new_red_scores, new_blue_scores); break; } case GE_STARTUP_BOOST: { if (NetworkConfig::get()->isServer()) { uint8_t kart_id = data.getUInt8(); if (!event->getPeer()->availableKartID(kart_id)) { Log::warn("GameProtocol", "Wrong kart id %d from %s.", kart_id, event->getPeer()->getAddress().toString().c_str()); return true; } float f = LobbyProtocol::get<ServerLobby>() ->getStartupBoostOrPenaltyForKart( event->getPeer()->getAveragePing(), kart_id); NetworkString *ns = getNetworkString(); ns->setSynchronous(true); ns->addUInt8(GE_STARTUP_BOOST).addUInt8(kart_id).addFloat(f); sendMessageToPeers(ns, true); delete ns; } else { uint8_t kart_id = data.getUInt8(); float boost = data.getFloat(); AbstractKart* k = World::getWorld()->getKart(kart_id); if (boost < 0.0f) { PlayerController* pc = dynamic_cast<PlayerController*>(k->getController()); pc->displayPenaltyWarning(); } else k->setStartupBoost(boost); } break; } case GE_CHECK_LINE: { if (!lw) throw std::invalid_argument("No linear world"); if (NetworkConfig::get()->isClient()) lw->updateCheckLinesClient(data); break; } default: Log::warn("GameEventsProtocol", "Unkown message type."); break; } return true; } // notifyEvent