Beispiel #1
0
void sendDialogMessage(Player* player, QString& message, QString NPCName, quint16 iconId)
{
    QByteArray data(1,0);
    data[0] = 0x11; // Request number
    data += stringToData(message);
    data += stringToData(NPCName);
    data += (quint8)(iconId&0xFF);
    data += (quint8)((iconId>>8)&0xFF);

    sendMessage(player,MsgUserReliableOrdered4, data);
}
void sendChatMessage(Player* player, QString message, QString author, quint8 chatType)
{
    QByteArray idAndAccess(5,0);
    idAndAccess[0] = player->pony.netviewId;
    idAndAccess[1] = player->pony.netviewId << 8;
    idAndAccess[2] = player->pony.netviewId << 16;
    idAndAccess[3] = player->pony.netviewId << 24;
    idAndAccess[4] = 0x0; // Access level
    QByteArray data(2,0);
    data[0] = 0xf; // RPC ID
    data[1] = chatType;
    data += stringToData(author);
    data += stringToData(message);
    data += idAndAccess;

    sendMessage(player,MsgUserReliableOrdered4,data); // Sends a 46
}
Beispiel #3
0
void Pony::saveInventory()
{
    win.logMsg(QObject::tr("%1 UDP: Saving Inventory for %2 (%3)").arg(LOG_INFO).arg(QString().setNum(netviewId)).arg(owner->name));

    QDir playerPath(QDir::currentPath());
    playerPath.cd("data");
    playerPath.cd("players");
    playerPath.mkdir(owner->name.toLatin1());

    QFile file(QDir::currentPath()+"/data/players/"+owner->name.toLatin1()+"/inventory.lpd");
    if (!file.open(QIODevice::ReadWrite))
    {
        win.logMsg(QObject::tr("%1 UDP: Error Saving Inventory for %2 (%3)").arg(LOG_SEVERE).arg(QString().setNum(netviewId)).arg(owner->name));
        return;
    }
    QByteArray invData = file.readAll();

    // Try to find an existing entry for this pony, if found delete it. Then go at the end.
    for (int i=0; i<invData.size();)
    {
        // Read the name
        QString entryName = dataToString(invData.mid(i));
        int nameSize = entryName.size()+getVUint32Size(invData.mid(i));
        //win.logMessage("saveInventory : Reading entry "+entryName);

        quint8 invSize = invData[i+nameSize+4];
        quint8 wornSize = invData[i+nameSize+4+1+invSize*9]; // Serialized sizeof InventoryItem is 9
        if (entryName == this->name) // Delete the entry, we'll rewrite it at the end
        {
            invData.remove(i,nameSize+4+1+invSize*9+1+wornSize*5);
            break;
        }
        else // Skip this entry
            i += nameSize+4+1+invSize*9+1+wornSize*5;
    }

    // Now add our data at the end of the file
    QByteArray newEntry = stringToData(this->name);
    newEntry += uint32ToData(nBits);
    newEntry += uint8ToData(inv.size());
    for (const InventoryItem& item : inv)
    {
        newEntry += uint8ToData(item.index);
        newEntry += uint32ToData(item.id);
        newEntry += uint32ToData(item.amount);
    }
    newEntry += uint8ToData(wornItm.size());
    for (const WearableItem& item : wornItm)
    {
        newEntry += uint8ToData(item.index);
        newEntry += uint32ToData(item.id);
    }
    invData += newEntry;
    file.resize(0);
    file.write(invData);
    file.close();
}
Beispiel #4
0
void sendAddViewAddShop(Player* player, Pony* npcShop)
{
    QByteArray data;
    data += 0x0A; // AddView RPC
    data += uint16ToData(npcShop->netviewId);
    data += uint16ToData(npcShop->netviewId);
    //data += uint16ToData(player->pony.netviewId);
    data += stringToData("AddShop");

    sendMessage(player, MsgUserReliableOrdered6, data);
}
Beispiel #5
0
void sendDialogOptions(Player* player, QList<QString>& answers)
{
    QByteArray data(5,0);
    data[0] = 0xC; // Request number
    data[1] = (quint8)(answers.size()&0xFF);
    data[2] = (quint8)((answers.size()>>8)&0xFF);
    data[3] = (quint8)((answers.size()>>16)&0xFF);
    data[4] = (quint8)((answers.size()>>24)&0xFF);
    for (int i=0; i<answers.size(); i++)
        data += stringToData(answers[i]);

    sendMessage(player,MsgUserReliableOrdered4, data);
}
void Pony::saveQuests()
{
    win.logMessage("UDP: Saving quests for "+QString().setNum(netviewId)+" ("+owner->name+")", udpTag);

    QDir playerPath(QDir::currentPath());
    playerPath.cd("data");
    playerPath.cd("players");
    playerPath.mkdir(owner->name.toLatin1());

    QFile file(QDir::currentPath()+"/data/players/"+owner->name.toLatin1()+"/quests.dat");
    if (!file.open(QIODevice::ReadWrite))
    {
        win.logMessage("Error saving quests for "+QString().setNum(netviewId)+" ("+owner->name+")", udpTag);
        return;
    }
    QByteArray questData = file.readAll();

    // Try to find an existing entry for this pony, if found delete it. Then go at the end.
    for (int i=0; i<questData.size();)
    {
        // Read the name
        QString entryName = dataToString(questData.mid(i));
        int nameSize = entryName.size()+getVUint32Size(questData.mid(i));
        //win.logMessage("saveQuests : Reading entry "+entryName);

        quint16 entryDataSize = 4 * dataToUint16(questData.mid(i+nameSize));
        if (entryName == this->name) // Delete the entry, we'll rewrite it at the end
        {
            questData.remove(i,nameSize+entryDataSize+2);
            break;
        }
        else
            i += nameSize+entryDataSize+2;
    }

    // Now add our data at the end of the file
    QByteArray newEntry = stringToData(this->name);
    newEntry += (quint8)(quests.size() & 0xFF);
    newEntry += (quint8)((quests.size() >> 8) & 0xFF);
    for (const Quest& quest : quests)
    {
        newEntry += (quint8)(quest.id & 0xFF);
        newEntry += (quint8)((quest.id >> 8) & 0xFF);
        newEntry += (quint8)(quest.state & 0xFF);
        newEntry += (quint8)((quest.state >> 8) & 0xFF);
    }
    questData += newEntry;
    file.resize(0);
    file.write(questData);
    file.close();
}
void sendNetviewInstantiate(Player *player, QString key, quint16 ViewId, quint16 OwnerId, UVector pos, UQuaternion rot)
{
    QByteArray data(1,1);
    data += stringToData(key);
    QByteArray data2(4,0);
    data2[0]=ViewId;
    data2[1]=ViewId>>8;
    data2[2]=OwnerId;
    data2[3]=OwnerId>>8;
    data += data2;
    data += vectorToData(pos);
    data += quaternionToData(rot);
    sendMessage(player, MsgUserReliableOrdered6, data);
}
Beispiel #8
0
void sendBeginShop(Player* player, Pony* npcShop)
{
    QByteArray data;
    data += uint16ToData(npcShop->netviewId);
    data += 0x16; // BeginShop

    data += uint32ToData(npcShop->inv.size());

    for (const InventoryItem& item : npcShop->inv)
    {
        data += uint32ToData(item.id);
        data += uint32ToData(item.amount);
    }
    data += stringToData("Wearable Items");

    sendMessage(player, MsgUserReliableOrdered18, data);
}
void sendLoadSceneRPC(Player* player, QString sceneName) // Loads a scene and send to the default spawn
{
    win.logMessage(QString("UDP: Loading scene \"") + sceneName + "\" on "+QString().setNum(player->pony.netviewId));
    Vortex vortex = findVortex(sceneName, 0);
    if (vortex.destName.isEmpty())
    {
        win.logMessage("UDP: Scene not in vortex DB. Aborting scene load.");
        return;
    }

    Scene* scene = findScene(sceneName);
    Scene* oldScene = findScene(player->pony.sceneName);
    if (scene->name.isEmpty() || oldScene->name.isEmpty())
    {
        win.logMessage("UDP: Can't find the scene, aborting");
        return;
    }

    // Update scene players
    //win.logMessage("sendLoadSceneRPC: locking");
    levelLoadMutex.lock();
    player->inGame=1;
    player->pony.pos = vortex.destPos;
    player->pony.sceneName = sceneName;
    player->lastValidReceivedAnimation.clear(); // Changing scenes resets animations
    Player::removePlayer(oldScene->players, player->IP, player->port);
    if (oldScene->name != sceneName)
    {
        // Send remove RPC to the other players of the old scene
        for (int i=0; i<oldScene->players.size(); i++)
            sendNetviewRemove(oldScene->players[i], player->pony.netviewId);

        // Send instantiate to the players of the new scene
        for (int i=0; i<scene->players.size(); i++)
            if (scene->players[i]->inGame>=2)
                sendNetviewInstantiate(player, scene->players[i]);
    }
    scene->players << player;

    QByteArray data(1,5);
    data += stringToData(sceneName);
    sendMessage(player,MsgUserReliableOrdered6,data); // Sends a 48
    //win.logMessage("sendLoadSceneRPC: unlocking");
    levelLoadMutex.unlock();
}
void Player::savePonies(Player *player, QList<Pony> ponies)
{
    win.logMessage("UDP: Saving ponies for "+QString().setNum(player->pony.netviewId)+" ("+player->name+")", sysTag);

    QDir playerPath(QDir::currentPath());
    playerPath.cd("data");
    playerPath.cd("players");
    playerPath.mkdir(player->name.toLatin1());

    QFile file(QDir::currentPath()+"/data/players/"+player->name.toLatin1()+"/ponies.dat");
    file.open(QIODevice::ReadWrite | QIODevice::Truncate);
    for (int i=0; i<ponies.size(); i++)
    {
        file.write(ponies[i].ponyData);
        file.write(vectorToData(ponies[i].pos));
        file.write(stringToData(ponies[i].sceneName.toLower()));
    }
}
Beispiel #11
0
void sendNetviewInstantiate(Player *player)
{
    win.logMessage("UDP: Send instantiate for/to "+QString().setNum(player->pony.netviewId));
    QByteArray data(1,1);
    data += stringToData("PlayerBase");
    QByteArray data2(4,0);
    data2[0]=player->pony.netviewId;
    data2[1]=player->pony.netviewId>>8;
    data2[2]=player->pony.id;
    data2[3]=player->pony.id>>8;
    data += data2;
    data += vectorToData(player->pony.pos);
    data += quaternionToData(player->pony.rot);
    sendMessage(player, MsgUserReliableOrdered6, data);

    win.logMessage(QString("Instantiate at ")+QString().setNum(player->pony.pos.x)+" "
                   +QString().setNum(player->pony.pos.y)+" "
                   +QString().setNum(player->pony.pos.z));
}
Beispiel #12
0
void sendLoadSceneRPC(Player* player, QString sceneName, UVector pos) // Loads a scene and send to the given pos
{
    win.logMessage(QString(QString("UDP: Loading scene \"")+sceneName
                           +"\" to "+QString().setNum(player->pony.netviewId)
                           +" at "+QString().setNum(pos.x)+" "
                           +QString().setNum(pos.y)+" "
                           +QString().setNum(pos.z)));

    Scene* scene = findScene(sceneName);
    Scene* oldScene = findScene(player->pony.sceneName);
    if (scene->name.isEmpty() || oldScene->name.isEmpty())
    {
        win.logMessage("UDP: Can't find the scene, aborting");
        return;
    }

    // Update scene players
    //win.logMessage("sendLoadSceneRPC pos: locking");
    levelLoadMutex.lock();
    player->inGame=1;
    player->pony.pos = pos;
    player->pony.sceneName = sceneName.toLower();
    player->lastValidReceivedAnimation.clear(); // Changing scenes resets animations
    Player::removePlayer(oldScene->players, player->IP, player->port);
    if (oldScene->name.toLower() != sceneName.toLower())
    {
        // Send remove RPC to the other players of the old scene
        for (int i=0; i<oldScene->players.size(); i++)
            sendNetviewRemove(oldScene->players[i], player->pony.netviewId);

        // Send instantiate to the players of the new scene
        for (int i=0; i<scene->players.size(); i++)
            if (scene->players[i]->inGame>=2)
                sendNetviewInstantiate(&player->pony, scene->players[i]);
    }
    scene->players << player;

    QByteArray data(1,5);
    data += stringToData(sceneName.toLower());
    sendMessage(player,MsgUserReliableOrdered6,data); // Sends a 48
    //win.logMessage("sendLoadSceneRPC pos: unlocking");
    levelLoadMutex.unlock();
}
Beispiel #13
0
void sendNetviewInstantiate(Player *src, Player *dst)
{
    win.logMessage("UDP: Send instantiate for "+QString().setNum(src->pony.netviewId)
                   +" to "+QString().setNum(dst->pony.netviewId));
    QByteArray data(1,1);
    data += stringToData("PlayerBase");
    QByteArray data2(4,0);
    data2[0]=src->pony.netviewId;
    data2[1]=src->pony.netviewId>>8;
    data2[2]=src->pony.id;
    data2[3]=src->pony.id>>8;
    data += data2;
    data += vectorToData(src->pony.pos);
    data += quaternionToData(src->pony.rot);
    sendMessage(dst, MsgUserReliableOrdered6, data);

   //win.logMessage(QString("Instantiate at ")+QString().setNum(rSrc.pony.pos.x)+" "
   //                +QString().setNum(rSrc.pony.pos.y)+" "
   //                +QString().setNum(rSrc.pony.pos.z));
}
void receiveMessage(Player* player)
{
    QByteArray msg = *(player->receivedDatas);
    int msgSize=5 + (((unsigned char)msg[3]) + (((unsigned char)msg[4]) << 8))/8;

#if UDP_SIMULATE_PACKETLOSS
    if (qrand() % 100 <= UDP_RECV_PERCENT_DROPPED)
    {
        //app.logMessage("UDP: Received packet dropped !");
        *(player->receivedDatas) = player->receivedDatas->mid(msgSize);
        if (player->receivedDatas->size())
            receiveMessage(player);
        return; // When we're done with the recursion, we still need to skip this message.
    }
    else
    {
        //app.logMessage("UDP: Received packet got through !");
    }
#endif

    // Check the sequence (seq) of the received messag
    if ((unsigned char)msg[0] >= MsgUserReliableOrdered1 && (unsigned char)msg[0] <= MsgUserReliableOrdered32)
    {
        quint16 seq = (quint8)msg[1] + ((quint8)msg[2]<<8);
        quint8 channel = ((unsigned char)msg[0])-MsgUserReliableOrdered1;
        if (seq <= player->udpRecvSequenceNumbers[channel] && player->udpRecvSequenceNumbers[channel]!=0)
        {
            // If this is a missing packet, accept it
            MessageHead missingMsg;
            missingMsg.channel = channel;
            missingMsg.seq = seq;
            if (player->udpRecvMissing.contains(missingMsg))
            {
                logMessage(QObject::tr("UDP: Processing retransmission (-%1) from %2")
                               .arg(player->udpRecvSequenceNumbers[channel]-seq).arg(player->pony.netviewId));
                for (int i=0; i<player->udpRecvMissing.size(); i++)
                    if (player->udpRecvMissing[i] == missingMsg)
                        player->udpRecvMissing.remove(i);
            }
            else
            {
                // We already processed this packet, we should discard it
#if DEBUG_LOG
                app.logMessage("UDP: Discarding double message (-"+QString().setNum(player->udpRecvSequenceNumbers[channel]-seq)
                               +") from "+QString().setNum(player->pony.netviewId));
                app.logMessage("UDP: Message was : "+QString(player->receivedDatas->left(msgSize).toHex().data()));
#endif
                player->nReceivedDups++;
                if (player->nReceivedDups >= 100) // Kick the player if he's infinite-looping on us
                {
                    logMessage(QObject::tr("UDP: Kicking %1 : Too many packet dups").arg(player->pony.netviewId));
                    sendMessage(player,MsgDisconnect, "You were kicked for lagging the server, sorry. You can login again.");
                    Player::disconnectPlayerCleanup(player); // Save game and remove the player
                    return;
                }
                *(player->receivedDatas) = player->receivedDatas->mid(msgSize);

                // Ack if needed, so that the client knows to move on already.
                if ((unsigned char)msg[0] >= MsgUserReliableOrdered1 && (unsigned char)msg[0] <= MsgUserReliableOrdered32) // UserReliableOrdered
                {
#if DEBUG_LOG
                    app.logMessage("UDP: ACKing discarded message");
#endif
                    QByteArray data(3,0);
                    data[0] = (quint8)(msg[0]); // ack type
                    data[1] = (quint8)(((quint8)msg[1])/2); // seq
                    data[2] = (quint8)(((quint8)msg[2])/2); // seq
                    sendMessage(player, MsgAcknowledge, data);
                }
                if (player->receivedDatas->size())
                    receiveMessage(player);
                return; // When we're done with the recursion, we still need to skip this message.
            }
        }
        else if (seq > player->udpRecvSequenceNumbers[channel]+2) // If a message was skipped, keep going.
        {
            logMessage(QObject::tr("UDP: Unordered message (+%1) received from %2")
                           .arg(seq-player->udpRecvSequenceNumbers[channel]).arg(player->pony.netviewId));
            player->udpRecvSequenceNumbers[channel] = seq;

            // Mark the packets we skipped as missing
            for (int i=player->udpRecvSequenceNumbers[channel]+2; i<seq; i+=2)
            {
                MessageHead missing;
                missing.channel = channel;
                missing.seq = i;
                player->udpRecvMissing.append(missing);
            }
        }
        else
        {
            if (player->nReceivedDups > 0) // If he stopped sending dups, forgive him slowly.
                player->nReceivedDups--;
            //app.logMessage("UDP: Received message (="+QString().setNum(seq)
            //               +") from "+QString().setNum(player->pony.netviewId));
            player->udpRecvSequenceNumbers[channel] = seq;
        }
    }

    // Process the received message
    if ((unsigned char)msg[0] == MsgPing) // Ping
    {
        //app.logMessage("UDP: Ping received from "+player->IP+":"+QString().setNum(player->port)
        //        +" ("+QString().setNum((timestampNow() - player->lastPingTime))+"s)");
        player->lastPingNumber = (quint8)msg[5];
        player->lastPingTime = timestampNow();
        sendMessage(player,MsgPong);
    }
    else if ((unsigned char)msg[0] == MsgPong) // Pong
    {
#if DEBUG_LOG
        //app.logMessage("UDP: Pong received");
#endif
    }
    else if ((unsigned char)msg[0] == MsgConnect) // Connect SYN
    {
        msg.resize(18); // Supprime le message LocalHail et le Timestamp
        msg = msg.right(13); // Supprime le Header
#if DEBUG_LOG
        app.logMessage(QString("UDP: Connecting ..."));
#endif

        for (int i=0; i<32; i++) // Reset sequence counters
            player->udpSequenceNumbers[i]=0;

        if (!player->connected)
            sendMessage(player, MsgConnectResponse, msg);
    }
    else if ((unsigned char)msg[0] == MsgConnectionEstablished) // Connect ACK
    {
        if (player->connected)
            logMessage(QObject::tr("UDP: Received duplicate connect ACK"));
        else
        {
            logMessage(QObject::tr("UDP: Connected to client"));
            player->connected=true;
            for (int i=0; i<32; i++) // Reset sequence counters
                player->udpSequenceNumbers[i]=0;
            onConnectAckReceived(player); // Clean the reliable message queue from SYN|ACKs

            // Start game
    #if DEBUG_LOG
            logMessage(QString("UDP: Starting game"));
    #endif
            // Set player id
            SceneEntity::lastIdMutex.lock();
            player->pony.id = SceneEntity::getNewId();
            player->pony.netviewId = SceneEntity::getNewNetviewId();
            SceneEntity::lastIdMutex.unlock();
            logMessage(QObject::tr("UDP: Set id request : %1/%2").arg(player->pony.id).arg(player->pony.netviewId));
            QByteArray id(3,0); // Set player Id request
            id[0]=4;
            id[1]=(quint8)(player->pony.id&0xFF);
            id[2]=(quint8)((player->pony.id>>8)&0xFF);
            sendMessage(player,MsgUserReliableOrdered6,id);

            // Load characters screen request
            QByteArray data(1,5);
            data += stringToData("characters");
            sendMessage(player,MsgUserReliableOrdered6,data);
        }
    }
    else if ((unsigned char)msg[0] == MsgAcknowledge) // Acknowledge
void receiveMessage(Player* player)
{
    QByteArray msg = *(player->receivedDatas);
    int msgSize=5 + (((unsigned char)msg[3]) + (((unsigned char)msg[4]) << 8))/8;

    // Check the sequence (seq) of the received message
    if ((unsigned char)msg[0] >= MsgUserReliableOrdered1 && (unsigned char)msg[0] <= MsgUserReliableOrdered32)
    {
        quint16 seq = (quint8)msg[1] + ((quint8)msg[2]<<8);
        quint8 channel = ((unsigned char)msg[0])-MsgUserReliableOrdered1;
        if (seq <= player->udpRecvSequenceNumbers[channel] && player->udpRecvSequenceNumbers[channel]!=0)
        {
            // If this is a missing packet, accept it
            MessageHead missingMsg;
            missingMsg.channel = channel;
            missingMsg.seq = seq;
            if (player->udpRecvMissing.contains(missingMsg))
            {
                win.logMessage("UDP: Processing retransmission (-"+QString().setNum(player->udpRecvSequenceNumbers[channel]-seq)
                               +") from "+QString().setNum(player->pony.netviewId));
                for (int i=0; i<player->udpRecvMissing.size(); i++)
                    if (player->udpRecvMissing[i] == missingMsg)
                        player->udpRecvMissing.remove(i);
            }
            else
            {
                // We already processed this packet, we should discard it
                win.logMessage("UDP: Discarding double message (-"+QString().setNum(player->udpRecvSequenceNumbers[channel]-seq)
                               +") from "+QString().setNum(player->pony.netviewId));
                //win.logMessage("UDP: Message was : "+QString(player->receivedDatas->left(msgSize).toHex().data()));
                player->nReceivedDups++;
                if (player->nReceivedDups >= 100) // Kick the player if he's infinite-looping on us
                {
                    win.logMessage(QString("UDP: Kicking "+QString().setNum(player->pony.netviewId)+" : Too many packet dups."));
                    sendMessage(player,MsgDisconnect, "You were kicked for lagging the server, sorry. You can login again.");
                    Player::disconnectPlayerCleanup(player); // Save game and remove the player
                    return;
                }
                *(player->receivedDatas) = player->receivedDatas->mid(msgSize);

                // Ack if needed, so that the client knows to move on already.
                if ((unsigned char)msg[0] >= MsgUserReliableOrdered1 && (unsigned char)msg[0] <= MsgUserReliableOrdered32) // UserReliableOrdered
                {
                    //win.logMessage("UDP: ACKing discarded message");
                    QByteArray data(3,0);
                    data[0] = (quint8)msg[0]; // ack type
                    data[1] = ((quint8)msg[1])/2; // seq
                    data[2] = ((quint8)msg[2])/2; // seq
                    sendMessage(player, MsgAcknowledge, data);
                }
                if (player->receivedDatas->size())
                    receiveMessage(player);
                return; // When we're done with the recursion, we still need to skip this message.
            }
        }
        else if (seq > player->udpRecvSequenceNumbers[channel]+2) // If a message was skipped, keep going.
        {
            win.logMessage("UDP: Unordered message (+"+QString().setNum(seq-player->udpRecvSequenceNumbers[channel])
                           +") received from "+QString().setNum(player->pony.netviewId));
            player->udpRecvSequenceNumbers[channel] = seq;

            // Mark the packets we skipped as missing
            for (int i=player->udpRecvSequenceNumbers[channel]+2; i<seq; i+=2)
            {
                MessageHead missing;
                missing.channel = channel;
                missing.seq = i;
                player->udpRecvMissing.append(missing);
            }
        }
        else
        {
            if (player->nReceivedDups > 0) // If he stopped sending dups, forgive him slowly.
                player->nReceivedDups--;
            //win.logMessage("UDP: Received message (="+QString().setNum(seq)
            //               +") from "+QString().setNum(player->pony.netviewId));
            player->udpRecvSequenceNumbers[channel] = seq;
        }
    }

    // Process the received message
    if ((unsigned char)msg[0] == MsgPing) // Ping
    {
        //win.logMessage("UDP: Ping received from "+player->IP+":"+QString().setNum(player->port)
        //        +" ("+QString().setNum((timestampNow() - player->lastPingTime))+"s)");
        player->lastPingNumber = (quint8)msg[5];
        player->lastPingTime = timestampNow();
        sendMessage(player,MsgPong);
    }
    else if ((unsigned char)msg[0] == MsgPong) // Pong
    {
        win.logMessage("UDP: Pong received");
    }
    else if ((unsigned char)msg[0] == MsgConnect) // Connect SYN
    {
        msg.resize(18); // Supprime le message LocalHail et le Timestamp
        msg = msg.right(13); // Supprime le Header

        win.logMessage(QString("UDP: Connecting ..."));

        for (int i=0; i<32; i++) // Reset sequence counters
            player->udpSequenceNumbers[i]=0;

        sendMessage(player, MsgConnectResponse, msg);
    }
    else if ((unsigned char)msg[0] == MsgConnectionEstablished) // Connect ACK
    {
        win.logMessage("UDP: Connected to client");
        player->connected=true;
        for (int i=0; i<32; i++) // Reset sequence counters
            player->udpSequenceNumbers[i]=0;

        // Start game
        win.logMessage(QString("UDP: Starting game"));

        // Set local player id
        win.lastId++;
        win.lastNetviewId++;
        player->pony.id = win.lastId;
        player->pony.netviewId = win.lastNetviewId;

        win.logMessage("UDP: Set id request : " + QString().setNum(player->pony.id) + "/" + QString().setNum(player->pony.netviewId));

        // Set player Id request
        QByteArray id(3,0);
        id[0]=4;
        id[1]=player->pony.id;
        id[2]=player->pony.id>>8;
        sendMessage(player,MsgUserReliableOrdered6,id); // Sends a 48

        // Load Characters screen requets
        QByteArray data(1,5);
        data += stringToData("Characters");
        sendMessage(player,MsgUserReliableOrdered6,data); // Sends a 48
    }