/*! \brief Called when a new player is connected to the server * \param event : Event providing the information. * * Format of the data : * Byte 0 1 2 * ------------------------------------- * Size | 1 | 1 | | * Data | player_id | hostid | player name | * ------------------------------------- */ void ClientLobbyRoomProtocol::newPlayer(Event* event) { if (!checkDataSize(event, 2)) return; const NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint8_t host_id = data.getUInt8(); core::stringw name; data.decodeStringW(&name); // FIXME need adjusting when splitscreen is used/ if(STKHost::get()->getGameSetup()->isLocalMaster(player_id)) { Log::error("ClientLobbyRoomProtocol", "The server notified me that I'm a new player in the " "room (not normal)."); } else if (m_setup->getProfile(player_id) == NULL) { Log::verbose("ClientLobbyRoomProtocol", "New player connected."); NetworkPlayerProfile* profile = new NetworkPlayerProfile(name, player_id, host_id); m_setup->addPlayer(profile); NetworkingLobby::getInstance()->addPlayer(profile); } else { Log::error("ClientLobbyRoomProtocol", "One of the player notified in the list is myself."); } } // newPlayer
/*! \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
/*! \brief Called when the server accepts the connection. * \param event : Event providing the information. * * Format of the data : * Byte 0 1 2 3 * --------------------------------------------------------- * Size | 1 | 1 | 1 | | * Data | player_id| hostid | authorised |playernames* | * --------------------------------------------------------- */ void ClientLobbyRoomProtocol::connectionAccepted(Event* event) { // At least 3 bytes should remain now if(!checkDataSize(event, 3)) return; NetworkString &data = event->data(); STKPeer* peer = event->getPeer(); // Accepted // ======== Log::info("ClientLobbyRoomProtocol", "The server accepted the connection."); // self profile irr::core::stringw name; if (PlayerManager::getCurrentOnlineState() == PlayerProfile::OS_SIGNED_IN) name = PlayerManager::getCurrentOnlineUserName(); else name = PlayerManager::getCurrentPlayer()->getName(); uint8_t my_player_id = data.getUInt8(); uint8_t my_host_id = data.getUInt8(); uint8_t authorised = data.getUInt8(); // Store this client's authorisation status in the peer information // for the server. event->getPeer()->setAuthorised(authorised!=0); STKHost::get()->setMyHostId(my_host_id); NetworkPlayerProfile* profile = new NetworkPlayerProfile(name, my_player_id, my_host_id); STKHost::get()->getGameSetup()->setLocalMaster(my_player_id); m_setup->setNumLocalPlayers(1); // connection token uint32_t token = data.getToken(); peer->setClientServerToken(token); // Add all players // =============== while (data.size() > 0) { uint8_t player_id = data.getUInt8(); uint8_t host_id = data.getUInt8(); irr::core::stringw name; int bytes_read = data.decodeStringW(&name); NetworkPlayerProfile* profile2 = new NetworkPlayerProfile(name, player_id, host_id); m_setup->addPlayer(profile2); // Inform the network lobby of all players so that the GUI can // show all currently connected players. NetworkingLobby::getInstance()->addPlayer(profile2); } // Add self after other players so that player order is identical // on server and all clients. m_setup->addPlayer(profile); NetworkingLobby::getInstance()->addPlayer(profile); m_server = event->getPeer(); m_state = CONNECTED; } // connectionAccepted
/*! \brief Called when a player votes for a minor race mode. * \param event : Event providing the information. * * Format of the data : * Byte 0 1 * ------------------------------- * Size | 1 | 4 | * Data | player id | minor mode vote | * ------------------------------- */ void ClientLobbyRoomProtocol::playerMinorVote(Event* event) { if (!checkDataSize(event, 2)) return; const NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint8_t minor = data.getUInt8(); m_setup->getRaceConfig()->setPlayerMinorVote(player_id, minor); } // playerMinorVote
/*! \brief Called when a player votes for a major race mode. * \param event : Event providing the information. * * Format of the data : * Byte 0 1 2 * ---------------------------------------- * Size | 1 | 1 | 1 | * Data | player id | laps | track number (gp) | * ---------------------------------------- */ void ClientLobbyRoomProtocol::playerLapsVote(Event* event) { if (!checkDataSize(event, 3)) return; const NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint8_t laps = data.getUInt8(); uint8_t number = data.getUInt8(); m_setup->getRaceConfig()->setPlayerLapsVote(player_id, laps, number); } // playerLapsVote
/*! \brief Called when a player votes for a track. * \param event : Event providing the information. * * Format of the data : * Byte 0 1 2 3 * -------------------------------------------------- * Size | 1 | 1 | 1 | N | * Data | player id | track number (gp) | N | track name | * -------------------------------------------------- */ void ClientLobbyRoomProtocol::playerTrackVote(Event* event) { if (!checkDataSize(event, 3)) return; const NetworkString &data = event->data(); std::string track_name; uint8_t player_id = data.getUInt8(); uint8_t number = data.getUInt8(); int N = data.decodeString(&track_name); m_setup->getRaceConfig()->setPlayerTrackVote(player_id, track_name, number); } // playerTrackVote
/*! \brief Called when a player votes for a minor race mode. * \param event : Event providing the information. * * Format of the data : * Byte 0 1 * ------------------------------- * Size | 1 | 4 | * Data | player-id | minor mode vote | * ------------------------------- */ void ServerLobbyRoomProtocol::playerMinorVote(Event* event) { if (!checkDataSize(event, 1)) return; NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint32_t minor = data.getUInt32(); m_setup->getRaceConfig()->setPlayerMinorVote(player_id, minor); // Send the vote to everybody (including the sender) NetworkString *other = getNetworkString(3); other->addUInt8(LE_VOTE_MINOR).addUInt8(player_id).addUInt8(minor); sendMessageToPeersChangingToken(other); delete other; } // playerMinorVote
/*! \brief Called when all karts have finished the race. * \param event : Event providing the information. * * Format of the data : * Byte 0 1 * ------------------------------- * Size | 1 | 1 | | * Data | Kart 1 ID | kart id 2 | ... | * ------------------------------- */ void ClientLobbyRoomProtocol::raceFinished(Event* event) { if(!checkDataSize(event, 1)) return; NetworkString &data = event->data(); Log::error("ClientLobbyRoomProtocol", "Server notified that the race is finished."); // stop race protocols Protocol* protocol = ProtocolManager::getInstance() ->getProtocol(PROTOCOL_CONTROLLER_EVENTS); if (protocol) ProtocolManager::getInstance()->requestTerminate(protocol); else Log::error("ClientLobbyRoomProtocol", "No controller events protocol registered."); protocol = ProtocolManager::getInstance() ->getProtocol(PROTOCOL_KART_UPDATE); if (protocol) ProtocolManager::getInstance()->requestTerminate(protocol); else Log::error("ClientLobbyRoomProtocol", "No kart update protocol registered."); protocol = ProtocolManager::getInstance() ->getProtocol(PROTOCOL_GAME_EVENTS); if (protocol) ProtocolManager::getInstance()->requestTerminate(protocol); else Log::error("ClientLobbyRoomProtocol", "No game events protocol registered."); // finish the race WorldWithRank* ranked_world = (WorldWithRank*)(World::getWorld()); ranked_world->beginSetKartPositions(); ranked_world->setPhase(WorldStatus::RESULT_DISPLAY_PHASE); int position = 1; while(data.size()>0) { uint8_t kart_id = data.getUInt8(); ranked_world->setKartPosition(kart_id,position); Log::info("ClientLobbyRoomProtocol", "Kart %d has finished #%d", kart_id, position); position++; } ranked_world->endSetKartPositions(); m_state = RACE_FINISHED; ranked_world->terminateRace(); } // raceFinished
/*! \brief Called when a player votes for a major race mode. * \param event : Event providing the information. * * Format of the data : * Byte 0 1 2 * ---------------------------------------- * Size | 1 | 1 | 1 | * Data | player id | laps | track number (gp) | * ---------------------------------------- */ void ServerLobbyRoomProtocol::playerLapsVote(Event* event) { if (!checkDataSize(event, 2)) return; NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint8_t lap_count = data.getUInt8(); uint8_t track_nb = data.getUInt8(); m_setup->getRaceConfig()->setPlayerLapsVote(player_id, lap_count, track_nb); NetworkString *other = getNetworkString(4); other->addUInt8(LE_VOTE_LAPS).addUInt8(player_id).addUInt8(lap_count) .addUInt8(track_nb); sendMessageToPeersChangingToken(other); delete other; } // playerLapsVote
/*! \brief Called when the server tells to update a player's kart. * \param event : Event providing the information. * * Format of the data : * Byte 0 1 2 3 N+3 * -------------------------------------------------- * Size | 1 | 1 | N | * Data | player id | N (kart name size) | kart name | * -------------------------------------------------- */ void ClientLobbyRoomProtocol::kartSelectionUpdate(Event* event) { if(!checkDataSize(event, 3)) return; const NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); std::string kart_name; data.decodeString(&kart_name); if (!m_setup->isKartAvailable(kart_name)) { Log::error("ClientLobbyRoomProtocol", "The updated kart is taken already."); } m_setup->setPlayerKart(player_id, kart_name); NetworkKartSelectionScreen::getInstance()->playerSelected(player_id, kart_name); } // kartSelectionUpdate
/*! \brief Called when a player votes for the reverse mode of a race * \param event : Event providing the information. * * Format of the data : * Byte 0 1 2 * -------------------------------------------- * Size | 1 | 1 | 1 | * Data | player id | reversed | track number (gp) | * -------------------------------------------- */ void ServerLobbyRoomProtocol::playerReversedVote(Event* event) { if (!checkDataSize(event, 3)) return; NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint8_t reverse = data.getUInt8(); uint8_t nb_track = data.getUInt8(); m_setup->getRaceConfig()->setPlayerReversedVote(player_id, reverse!=0, nb_track); // Send the vote to everybody (including the sender) NetworkString *other = getNetworkString(4); other->addUInt8(LE_VOTE_REVERSE).addUInt8(player_id).addUInt8(reverse) .addUInt8(nb_track); sendMessageToPeersChangingToken(other); delete other; } // playerReversedVote
/*! \brief Called when a player votes for a track. * \param event : Event providing the information. * * Format of the data : * Byte 0 1 2 3 * -------------------------------------------------- * Size | 1 | 1 | 1 | N | * Data | player id | track number (gp) | N | track name | * -------------------------------------------------- */ void ServerLobbyRoomProtocol::playerTrackVote(Event* event) { if (!checkDataSize(event, 3)) return; NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); // As which track this track should be used, e.g. 1st track: Sandtrack // 2nd track Mathclass, ... uint8_t track_number = data.getUInt8(); std::string track_name; int N = data.decodeString(&track_name); m_setup->getRaceConfig()->setPlayerTrackVote(player_id, track_name, track_number); // Send the vote to everybody (including the sender) NetworkString *other = getNetworkString(3+1+data.size()); other->addUInt8(LE_VOTE_TRACK).addUInt8(player_id).addUInt8(track_number) .encodeString(track_name); sendMessageToPeersChangingToken(other); delete other; if(m_setup->getRaceConfig()->getNumTrackVotes()==m_setup->getPlayerCount()) startGame(); } // playerTrackVote
/*! \brief Called when the server refuses the kart selection request. * \param event : Event providing the information. * * Format of the data : * Byte 0 * ---------------- * Size | 1 | * Data | refusal code | * ---------------- */ void ClientLobbyRoomProtocol::kartSelectionRefused(Event* event) { if(!checkDataSize(event, 1)) return; const NetworkString &data = event->data(); switch (data.getUInt8()) // the error code { case 0: Log::info("ClientLobbyRoomProtocol", "Kart selection refused : already taken."); break; case 1: Log::info("ClientLobbyRoomProtocol", "Kart selection refused : not available."); break; default: Log::info("ClientLobbyRoomProtocol", "Kart selection refused."); break; } } // kartSelectionRefused
/*! \brief Called when the server refuses the connection. * \param event : Event providing the information. * * Format of the data : * Byte 0 * ---------------- * Size | 1 | * Data | refusal code | * ---------------- */ void ClientLobbyRoomProtocol::connectionRefused(Event* event) { if (!checkDataSize(event, 1)) return; const NetworkString &data = event->data(); switch (data.getUInt8()) // the second byte { case 0: Log::info("ClientLobbyRoomProtocol", "Connection refused : too many players."); break; case 1: Log::info("ClientLobbyRoomProtocol", "Connection refused : banned."); break; case 2: Log::info("ClientLobbyRoomProtocol", "Client busy."); break; default: Log::info("ClientLobbyRoomProtocol", "Connection refused."); break; } } // connectionRefused
/*! \brief Called when a new player is disconnected * \param event : Event providing the information. * * Format of the data : * Byte 0 * -------------- * Size | 1 | * Data | player id *| * -------------- */ void ClientLobbyRoomProtocol::disconnectedPlayer(Event* event) { if (!checkDataSize(event, 1)) return; NetworkString &data = event->data(); while(data.size()>0) { const NetworkPlayerProfile *profile = m_setup->getProfile(data.getUInt8()); if (m_setup->removePlayer(profile)) { Log::info("ClientLobbyRoomProtocol", "Player %d removed successfully.", profile->getGlobalPlayerId()); } else { Log::error("ClientLobbyRoomProtocol", "The disconnected peer wasn't known."); } } // while STKHost::get()->removePeer(event->getPeer()); } // disconnectedPlayer
/** Called when receiving a message. On the client side the message is a ping * from the server, which is answered back. On the server the received message * is a reply to a previous ping request. The server will keep track of * average latency. */ bool LatencyProtocol::notifyEventAsynchronous(Event* event) { if (event->getType() != EVENT_TYPE_MESSAGE) return true; if(!checkDataSize(event, 5)) return true; const NetworkString &data = event->data(); uint32_t request = data.getUInt8(); uint32_t sequence = data.getUInt32(); const std::vector<STKPeer*> &peers = STKHost::get()->getPeers(); assert(peers.size() > 0); // Find the right peer id. The host id (i.e. each host sendings its // host id) can not be used here, since host ids can have gaps (if a // host should disconnect) uint8_t peer_id = -1; for (unsigned int i = 0; i < peers.size(); i++) { if (peers[i]->isSamePeer(event->getPeer())) { peer_id = i; break; } } if (request) { // Only a client should receive a request for a ping response assert(NetworkConfig::get()->isClient()); NetworkString *response = getNetworkString(5); // The '0' indicates a response to a ping request response->addUInt8(0).addUInt32(sequence); event->getPeer()->sendPacket(response, false); delete response; } else // receive response to a ping request { // Only a server should receive this kind of message assert(NetworkConfig::get()->isServer()); if (sequence >= m_pings[peer_id].size()) { Log::warn("LatencyProtocol", "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]; 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("LatencyProtocol", "Peer %d sequence %d ping %u average %u at %lf", peer_id, sequence, (unsigned int)((current_time - m_pings[peer_id][sequence])*1000), m_average_ping[peer_id], StkTime::getRealTime()); } return true; } // notifyEventAsynchronous
//----------------------------------------------------------------------------------------- astra::CFloat32Data3DMemory * allocateDataObject(const std::string & sDataType, const mxArray * const geometry, const mxArray * const data, const mxArray * const unshare, const mxArray * const zIndex) { astra::CFloat32Data3DMemory* pDataObject3D = NULL; bool bUnshare = true; if (unshare) { if (!mexIsScalar(unshare)) { mexErrMsgTxt("Argument 5 (read-only) must be scalar"); return NULL; } // unshare the array if we're not linking read-only bUnshare = !(bool)mxGetScalar(unshare); } mwIndex iZ = 0; if (zIndex) { if (!mexIsScalar(zIndex)) { mexErrMsgTxt("Argument 6 (Z) must be scalar"); return NULL; } iZ = (mwSignedIndex)mxGetScalar(zIndex); } // SWITCH DataType if (sDataType == "-vol") { // Read geometry astra::Config* cfg = structToConfig("VolumeGeometry3D", geometry); astra::CVolumeGeometry3D* pGeometry = new astra::CVolumeGeometry3D(); if (!pGeometry->initialize(*cfg)) { mexErrMsgTxt("Geometry class not initialized. \n"); delete pGeometry; delete cfg; return NULL; } delete cfg; // If data is specified, check dimensions if (data && !mexIsScalar(data)) { if (! (zIndex ? checkDataSize(data, pGeometry, iZ) : checkDataSize(data, pGeometry)) ) { mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n"); delete pGeometry; return NULL; } } // Initialize data object #ifdef USE_MATLAB_UNDOCUMENTED if (unshare) { CFloat32CustomMemoryMatlab3D* pHandle = new CFloat32CustomMemoryMatlab3D(data, bUnshare, iZ); // Initialize data object pDataObject3D = new astra::CFloat32VolumeData3DMemory(pGeometry, pHandle); } else { pDataObject3D = new astra::CFloat32VolumeData3DMemory(pGeometry); } #else pDataObject3D = new astra::CFloat32VolumeData3DMemory(pGeometry); #endif delete pGeometry; } else if (sDataType == "-sino" || sDataType == "-proj3d" || sDataType == "-sinocone") { // Read geometry astra::Config* cfg = structToConfig("ProjectionGeometry3D", geometry); // FIXME: Change how the base class is created. (This is duplicated // in Projector3D.cpp.) std::string type = cfg->self.getAttribute("type"); astra::CProjectionGeometry3D* pGeometry = 0; if (type == "parallel3d") { pGeometry = new astra::CParallelProjectionGeometry3D(); } else if (type == "parallel3d_vec") { pGeometry = new astra::CParallelVecProjectionGeometry3D(); } else if (type == "cone") { pGeometry = new astra::CConeProjectionGeometry3D(); } else if (type == "cone_vec") { pGeometry = new astra::CConeVecProjectionGeometry3D(); } else { mexErrMsgTxt("Invalid geometry type.\n"); return NULL; } if (!pGeometry->initialize(*cfg)) { mexErrMsgTxt("Geometry class not initialized. \n"); delete pGeometry; delete cfg; return NULL; } delete cfg; // If data is specified, check dimensions if (data && !mexIsScalar(data)) { if (! (zIndex ? checkDataSize(data, pGeometry, iZ) : checkDataSize(data, pGeometry)) ) { mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n"); delete pGeometry; return NULL; } } // Initialize data object #ifdef USE_MATLAB_UNDOCUMENTED if (unshare) { CFloat32CustomMemoryMatlab3D* pHandle = new CFloat32CustomMemoryMatlab3D(data, bUnshare, iZ); // Initialize data object pDataObject3D = new astra::CFloat32ProjectionData3DMemory(pGeometry, pHandle); } else { pDataObject3D = new astra::CFloat32ProjectionData3DMemory(pGeometry); } #else pDataObject3D = new astra::CFloat32ProjectionData3DMemory(pGeometry); #endif delete pGeometry; } else { mexErrMsgTxt("Invalid datatype. Please specify '-vol' or '-proj3d'. \n"); return NULL; } // Check initialization if (!pDataObject3D->isInitialized()) { mexErrMsgTxt("Couldn't initialize data object.\n"); delete pDataObject3D; return NULL; } return pDataObject3D; }