/*! \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
Exemple #2
0
/** Sends data to all peers except the specified one.
 *  \param peer Peer which will not receive the message.
 *  \param data Data to sent.
 *  \param reliable If the data should be sent reliable or now.
 */
void STKHost::sendPacketExcept(STKPeer* peer, const NetworkString& data,
                               bool reliable)
{
    for (unsigned int i = 0; i < m_peers.size(); i++)
    {
        STKPeer* p = m_peers[i];
        if (!p->isSamePeer(peer))
        {
            p->sendPacket(data, reliable);
        }
    }
}   // sendPacketExcept
/*! \brief Called when a player asks for a connection.
 *  \param event : Event providing the information.
 *
 *  Format of the data :
 *  Byte 0   1                
 *       ---------------------
 *  Size | 1 |1|             |
 *  Data | 4 |n| player name |
 *       ---------------------
 */
void ServerLobbyRoomProtocol::connectionRequested(Event* event)
{
    STKPeer* peer = event->getPeer();
    const NetworkString &data = event->data();

    // can we add the player ?
    if (m_setup->getPlayerCount() >= NetworkConfig::get()->getMaxPlayers() ||
        m_state!=ACCEPTING_CLIENTS                                           )
    {
        NetworkString *message = getNetworkString(2);
        // Len, error code: 2 = busy, 0 = too many players
        message->addUInt8(LE_CONNECTION_REFUSED)
                .addUInt8(m_state!=ACCEPTING_CLIENTS ? 2 : 0);

        // send only to the peer that made the request
        peer->sendPacket(message);
        delete message;
        Log::verbose("ServerLobbyRoomProtocol", "Player refused");
        return;
    }

    // Connection accepted.
    // ====================
    std::string name_u8;
    int len = data.decodeString(&name_u8);
    core::stringw name = StringUtils::utf8ToWide(name_u8);
    std::string password;
    data.decodeString(&password);
    bool is_authorised = (password==NetworkConfig::get()->getPassword());

    // Get the unique global ID for this player.
    m_next_player_id.lock();
    m_next_player_id.getData()++;
    int new_player_id = m_next_player_id.getData();
    m_next_player_id.unlock();
    if(m_setup->getLocalMasterID()==0)
        m_setup->setLocalMaster(new_player_id);

    // The host id has already been incremented when the peer
    // was added, so it is the right id now.
    int new_host_id = STKHost::get()->getNextHostId();

    // Notify everybody that there is a new player
    // -------------------------------------------
    NetworkString *message = getNetworkString(3+1+name_u8.size());
    // size of id -- id -- size of local id -- local id;
    message->addUInt8(LE_NEW_PLAYER_CONNECTED).addUInt8(new_player_id)
            .addUInt8(new_host_id).encodeString(name_u8);
    STKHost::get()->sendPacketExcept(peer, message);
    delete 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) & 0xff) << 24 |
                                (token_generator.get(RAND_MAX) & 0xff) << 16 |
                                (token_generator.get(RAND_MAX) & 0xff) <<  8 |
                                (token_generator.get(RAND_MAX) & 0xff));

    peer->setClientServerToken(token);
    peer->setAuthorised(is_authorised);
    peer->setHostId(new_host_id);

    const std::vector<NetworkPlayerProfile*> &players = m_setup->getPlayers();
    // send a message to the one that asked to connect
    // Estimate 10 as average name length
    NetworkString *message_ack = getNetworkString(4 + players.size() * (2+10));
    // connection success -- size of token -- token
    message_ack->addUInt8(LE_CONNECTION_ACCEPTED).addUInt8(new_player_id)
                .addUInt8(new_host_id).addUInt8(is_authorised);
    // Add all players so that this user knows (this new player is only added
    // to the list of players later, so the new player's info is not included)
    for (unsigned int i = 0; i < players.size(); i++)
    {
        message_ack->addUInt8(players[i]->getGlobalPlayerId())
                    .addUInt8(players[i]->getHostId())
                    .encodeString(players[i]->getName());
    }
    peer->sendPacket(message_ack);
    delete message_ack;

    NetworkPlayerProfile* profile = 
        new NetworkPlayerProfile(name, new_player_id, new_host_id);
    m_setup->addPlayer(profile);
    NetworkingLobby::getInstance()->addPlayer(profile);

    Log::verbose("ServerLobbyRoomProtocol", "New player.");

}   // connectionRequested