RakNet & Irrlicht
Proposé par nabouill

le 20 October 2009 à 23h 47mn 38s

35054 visualisations


:                                                                                                                                     
RakNet est un moteur de réseau multiplateforme écrit en C++ et pensé pour le domaine du jeu vidéo principalement. Je vous laisse le soin de lire la licence
INFO
Licence RakNet

RakNet à l’avantage d’être assez simple à utiliser et est relativement rapide. En plus les fichiers sources sont très très bien commentés.
Ici, je ne vais pas faire un tuto très détaillé de toutes les fonctions de RakNet, mais simplement utiliser les notions de base, qui seront déjà suffisantes pour créer une petite application en réseaux. Pour les détails, n’hésiter pas a faire un tour dans la
INFO
documentation RakNet.


Le déroulement du tuto :
Les préparatifs
Ma vision de l’utilisation de RakNet dans mes applications
Introduction rapide au réseau
Un paquet !
Les fonctions principal que l’on va utiliser
1er application : une petite console pour comprendre
2e application : RakNet et Irrlicht – Ninja !


 




Les préparatifs

Commençons par télécharger RakNet
Download RakNet
Compilez le avec votre IDE favoris (les projets sont créent et configuré pour les IDE les plus courant, juste a lancer la compilation et c’est réglé). Récupérez la DLL pour vos projets.

On peut utiliser RakNet de 2 façons :
-Replica : Un système qui permet de répliquer la même chose sur tous les clients connectés au serveur automatiquement. (Le système replica utilise le système BitStream)

-BitStream : Une autre façon, celle de tout faire a la main. A nous d’écrire les données à envoyer, et de les lire. Il faut une bonne organisation pour ne pas lire n’importe quoi à la réception.

Nous allons nous utiliser le BlitStream. D’abord parce que je préfère bien contrôler les paquets, savoir ce que j’envoie et quand je l’envoie. Mais aussi, parce que je ne sais pas encore très bien utiliser le Replica tongue



Ma vision de l’utilisation de RakNet dans mes applications

Personnellement, je préfère créer une application « serveur » et une application « client ».
On peut très bien faire une application qui fait les deux, mais sur une application assez lourde, on a vite fait de s’emmêler les pédales sur la gestion des paquets. Chacun son rôle !




Introduction rapide au réseau

Les machines doivent être toutes reliées sur un réseau (qu’il soit local ou internet) évidement.
Pour que les machines communiquent entre elle, elle utilise une adresse IP et un numéro de port.


-L’adresse IP :
Il faut donc impérativement connaitre l’adresse IP du serveur pour pouvoir si connecter.
Si on veut utiliser le même PC pour faire tourner à la fois le client et le serveur, on utilisera l’adresse 127.0.0.1, c’est une adresse réservé à l’ordinateur lui-même.

-Le port :
Le port est un numéro utilisé par le PC pour en quelque sorte savoir sur quelle application on se connecte. Imaginer que vous avez 2 application serveur sur le même PC et qu’il passe tout les 2 sur le port 5000 (par exemple) Il y aurait vite un conflit entre le client et le/les serveurs.
On préféra donc lancer un serveur sur le port 5000 et l’autre sur le port 5001.


Un paquet !

On peut imaginer un tube avec des cases. Case 1, case 2, case 3…
C’est à nous de mettre ce qu’on veut dans les cases, des variables de n’importe quels types.
Du moment qu’on sait les relire a l’autre bout.



Les fonctions principal que l’on va utiliser

Voici en gros les chose que l’on va utiliser pendant le tuto.
Vous retrouverez tout cela bien en détail dans la doc de RakNet bien sûr.


Code c++ :

//creation de l’interface client ou serveur
RakPeerInterface *client = RakNetworkFactory::GetRakPeerInterface();

Code c++ :

// creation d’un paquet
Packet *packet;

Code c++ :

//Demarrage du client
Startup (unsigned short maxConnections,
            int _threadSleepTimer,
            SocketDescriptor *socketDescriptors,
            unsigned socketDescriptorCount)
//exemple
client->Startup( unsigned short maxConnections, int _threadSleepTimer, SocketDescriptor *socketDescriptors, unsigned socketDescriptorCount )

Code c++ :

// definie le nombre de client maxi ( reserver au serveur bien sur)
SetMaximumIncomingConnections (unsigned short numberAllowed)
//exemple
server->SetMaximumIncomingConnections(int nbClientMaxi);

Code c++ :

//Connection du client
Connect (const char *host,
             unsigned short remotePort,
             const char *passwordData,
             int passwordDataLength,
             unsigned connectionSocketIndex=0,
             unsigned sendConnectionAttemptCount=7,
             unsigned timeBetweenSendConnectionAttemptsMS=500,
             RakNetTime timeoutTime=0)
//exemple
client->Connect(ipServer, portServer, 0,0);

Code c++ :

// le système BitStream
BitStream (unsigned char *_data,
                const unsigned int lengthInBytes,
                bool _copyData)
//exemple
RakNet::BitStream dataStream(packet->data, packet->length, false);

Code c++ :

//ecriture d’une case dans le paquet
Write (templateType var)
//exemple
int nombre = 10;
dataStream.Write(nombre);

Code c++ :

//lecture d’une case dans le paquet
Read (templateType &var)
//exemple
int nombre;
dataStream.Read(nombre);

Code c++ :

//on supprime le packet
DeallocatePacket (Packet *packet)
//exemple
client->DeallocatePacket(packet);

Code c++ :

//envoie d’un packet
Send (const RakNet::BitStream *bitStream,
         PacketPriority priority,
         PacketReliability reliability,
         char orderingChannel,
         SystemAddress systemAddress,
         bool broadcast)=0
//exemple :
client->Send(&dataStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, true);
//on notera ici la prioriter du paquet (LOW_PRIORITY, MEDIUM_PRIORITY, HIGH_PRIORITY)
//ainsi  que le  SystemAddress qui correspond au client a qui on n'envoie PAS le paquet, dans cette exemple on l'envoie a tous

Code c++ :

//suppression du client ou du serveur
RakNetworkFactory::DestroyRakPeerInterface(client);


Avec ça, on devrait déjà en faire pas mal smile
INFO
Je vous conseil quand même d'allez faire un petit tour dans la doc pour voir ça de plus prêt documentation RakNet.


1er application : une petite console pour comprendre

Une petite application pour tester la connexion a un serveur et l'envoie de paquet/réception de données.
Ce programme va simplement lancer un serveur, puis un client qui va envoyer sont nom au serveur si ça connexion est accepté.
Puis le serveur va avertir tous les clients déjà connecté qu'un nouveau client est arrivé.


LE SERVEUR
Créez une application console appelé "serveur"et linker les lib.

Code c++ :


#include "RakNetworkFactory.h"
#include "RakPeerInterface.h"
#include "MessageIdentifiers.h"
#include <BitStream.h>
#include <RakNetTypes.h>

#include <conio.h>// for getch()

// creation de nos propre ID
const unsigned char PACKET_ID_MESSAGE_DIT = 100;

///////////////////////////////////////////////////////////////////////////////////////////////////////
///                     MES FONCTIONS
///////////////////////////////////////////////////////////////////////////////////////////////////////

// une fonction qui va nous servir a envoyer un message au clients
void sendAMessage(RakPeerInterface *serveur, Packet* packet, char name[])
{
    char message[100];// on creer de quoi ecrire un message
    //on met ça en forme
    sprintf(message, "Le client <%s> vient de se connecter\n", name);

    RakNet::BitStream data;// creation de nos data a envoyer
    data.Write(PACKET_ID_MESSAGE_DIT);// on ecrit l'ID de notre packet
    data.Write(message);// on ecrit notre message
    // et on ça a nos client    //envoie a tout le monde sauf a celui qui nous avait envoyer le paquet "packet->systemAddress"
    serveur->Send(&data, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, true);
}


///////////////////////////////////////////////////////////////////////////////////////////////////////
///                     LA FONCTIONS MAIN
///////////////////////////////////////////////////////////////////////////////////////////////////////
int main(void)
{

    int maxClient = 10;
    int portServeur = 10000;

    // création de l'interface serveur
    RakPeerInterface *serveur = RakNetworkFactory::GetRakPeerInterface();
    // creation d'un packet
    Packet * packet = NULL;

    // demarrage du serveur
    serveur->Startup(maxClient, 10, &SocketDescriptor(portServeur,0), 1);
    //OBLIGATOIRE, sinnon on n'accepte aucun client
    serveur->SetMaximumIncomingConnections(maxClient);

    printf("Demarrage du serveur sur le port %d\n", portServeur);
    printf("Avec %d client maxi\n", maxClient);


    //la grande boucle
    bool continuer = true;
    while(continuer)
    {
        //on verifie si on a reçu un packet
        packet = serveur->Receive();
        if(packet != NULL)// si oui
        {
               unsigned char packetID;
                //creation de data que l'on est pret a recevoir
                RakNet::BitStream dataStream(packet->data, packet->length, false);

                dataStream.Read(packetID);// on commence par lire l'ID du paquet que l'on vient de recevoir

                char charTempo[50];// on creer un tableau de char pour nous permette d'y ecrrire quelque chose

                switch(packetID)
                {

                    case ID_NEW_INCOMING_CONNECTION:
                            break;

                    case PACKET_ID_MESSAGE_DIT:
                            // on sait que l'on va receptionner un message envoyer par notre client^^
                            dataStream.Read(charTempo);// on lis les données que l'on vient de recevoir
                                                    //on les stocks directement dans notre tableau de char
                            printf("Bienvenue a %s .\n", charTempo);
                            // on utilise notre fonction pour dire a tous les clients ce qu'on vient de recevoir
                            sendAMessage(serveur, packet, charTempo);
                            break;

                    case ID_NO_FREE_INCOMING_CONNECTIONS:
                            // ID automatiquement reçu si on client tente de se connecter mais que le nombre de client maxi est atteint
                            printf("le serveur est plein.\n");
                            break;

                    case ID_CONNECTION_LOST:
                            //ID automatiquement reçu si on client perd la connection
                            printf("Un client a perdu la connection.\n");
                            break;

                    default:
                        // si on l'ID d'un paquet que l'on a pas referencer on le dit
                        //ceci n'est pas forcement un probleme !
                        printf("Reception d'un packet avec un ID inconnue: %i\n", int(packetID));
                }

            serveur->DeallocatePacket(packet);
        }


        // la gestion des touche au clavier, ici on va juste gerer la touche echap pour quitter
        if (kbhit())
        {
            int key = getch();
            if (key == 27)// 27 est egale a la touche echap
            {
                continuer = false;
            }
        }

    }// fin de la boucle principale du programme

    // destruction de l'interface serveur
    RakNetworkFactory::DestroyRakPeerInterface(serveur);

    return 0;

}


LE CLIENT
Créez une application console appelé "client"et linker les lib.

Code c++ :


#include "RakNetworkFactory.h"
#include "RakPeerInterface.h"
#include "MessageIdentifiers.h"
#include <BitStream.h>
#include <RakNetTypes.h>

#include <conio.h>// for getch()

// creation de nos propre ID
const unsigned char PACKET_ID_MESSAGE_DIT = 100;


///////////////////////////////////////////////////////////////////////////////////////////////////////
///                     MES FONCTIONS
///////////////////////////////////////////////////////////////////////////////////////////////////////

// une fonction qui va nous servir a envoyer un message au serveur
void sendMyName(RakPeerInterface *client, char name[])
{
    RakNet::BitStream data;// creation de nos data a envoyer
    data.Write(PACKET_ID_MESSAGE_DIT);// on ecrit l'ID du packet
    data.Write(name);// on ecrit notre nom
    // et on envoie le tout au serveur                      //envoie a tout le monde
    client->Send(&data, HIGH_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, true);
}


///////////////////////////////////////////////////////////////////////////////////////////////////////
///                     LA FONCTIONS MAIN
///////////////////////////////////////////////////////////////////////////////////////////////////////

int main(void)
{
    int portServeur = 10000;
    char IP_serveur[20];
    char myName[50];
    // on commence par entrez l'adresse du serveur
    printf("Le client <%s> vient de se connecter\n");
    scanf("Demarrage du serveur sur le port %d\n", IP_serveur);
    printf("Avec %d client maxi\n");
    scanf("Bienvenue a %s .\n", myName);

    // création de l'interface serveur
    RakPeerInterface *client = RakNetworkFactory::GetRakPeerInterface();
    // creation d'un packet
    Packet * packet = NULL;

    // demarrage du client
    client->Startup(1,10,&SocketDescriptor(), 1);
    client->Connect(IP_serveur, portServeur, 0,0);

    //la grande boucle
    bool continuer = true;
    while(continuer)
    {
        //on verifie si on a reçu un packet
        packet = client->Receive();
        if(packet != NULL)// si oui
        {
               unsigned char packetID;
                //creation de data que l'on est pret a recevoir
                RakNet::BitStream dataStream(packet->data, packet->length, false);
                // on commence par lire l'ID du paquet que l'on vient de recevoir
                dataStream.Read(packetID);

                char charTempo[100];// on creer un tableau de char pour nous permette d'y ecrire quelque chose

                switch(packetID)
                {
                    case ID_CONNECTION_REQUEST_ACCEPTED:
                            //on reçois cet ID automatiquement du serveur si il a accepter notre connection
                            printf("le serveur est plein.\n");
                            //on envoie notre nom au serveur
                            sendMyName(client, myName);
                            break;

                    case ID_CONNECTION_ATTEMPT_FAILED:
                            //on reçois cet ID automatiquement si on arrive pas a ce connecter au serveur
                            printf("Un client a perdu la connection.\n");
                            break;

                    case PACKET_ID_MESSAGE_DIT:
                            // on sait que l'on va receptionner un message envoyer par notre serveur
                            dataStream.Read(charTempo);// on lis les données que l'on vient de recevoir
                                                      //on les stocks directement dans notre tableau de char
                            printf("Reception d'un packet avec un ID inconnue: %i\n", charTempo);
                            break;

                    default:
                        // si on l'ID d'un paquet que l'on a pas referencer on le dit
                        //ceci n'est pas forcement un probleme !
                        printf("Entrez l'adresse IP su serveur :", int(packetID));
                }

            client->DeallocatePacket(packet);
        }

        // la gestion des touche au clavier, ici on va juste gerer la touche echap pour quitter
        if (kbhit())
        {
            int key = getch();
            if (key == 27)// 27 est egale a la touche echap
            {
                continuer = false;
            }
        }

    }// fin de la boucle principale du programme

    // destruction de l'interface serveur
    RakNetworkFactory::DestroyRakPeerInterface(client);

    return 0;

}


COMPILEZ !
OK : Vous pouvez donc maintenant lancer le serveur, puis lancer plusieurs clients en même temps pour testé ça.

INFO
Comme vous avez pu le remarquez, un certain nombre de paquets avec un ID bien précis sont déjà envoyé automatiquement par RakNet. Vous retrouverez tous ces ID dans le fichier "MessageIdentifiers.h" des sources


Donc pour résumer un peu, comme vous avez sans doute pu le remarquer, l'idée c'est quoi ?(pas la mienne hein, celle de RakNet tongue )
On créer un paquet, ( pour reprendre le schéma du paquet plus haut) dans la première case on écrit l'ID du paquet, ce qui va nous servir à savoir à quoi ce paquet va nous servir. Puis on écrit les valeurs (dans les cases) que l'on a besoin.
De l'autre côté, le client reçoit un paquet. Il commence par lire l'ID de ce paquet, (je me répète) ce qui va lui servir à savoir à quoi ce paquet va nous servir. Puis on lie les données ( dans les cases) qui suivent.

Cette première application est très juste une petite approche de ce qu'il possible de faire, c'est que ici, l'utilisateur ne rentre pas vraiment en jeu.
Mais attendez de voir la suite...


2e application : RakNet et Irrlicht – Ninja !

On va ici, créer un serveur (toujours en console) et un client qui lui va être un peu plus jolie.
Le serveur:
-Doit être capable d'accepter  2 connections client.
-Il doit réceptionner la position des 2 joueurs et la renvoyer au client.

Le client :
-dans une application Irrlicht, création d'un sol, de 2  nodes animés (on va prendre le Ninja fournie par Irrlicht), une camera qui suit notre node.
-On doit envoyer notre position régulièrement au serveur.
-On doit être capable de réceptionner la position de l’autre joueur envoyé par le serveur.
-On va aussi joueur une animation lorsque les ninja se déplace. (Idle, lorsqu'il sont sur place et Walk quand il se déplace)
-On va utiliser les models et textures fournie par Irrlicht :
          -le terrain : terrain-heightmap.bmp, terrain-texture.jpg, detailmap3.jpg.
          -les modèles : ninja.b3d, nskinbl.jpg, nskinrd.jpg. (pour avoir 1 ninja rouge et un bleu)

Mais avant : Un problème de la vitesse de l'envoi/lecture des paquets.
Il existe un vrai problème sur la vitesse d'envoi et de réception des paquet suivant l'application que vous voulez mettre en réseau.
Exemple :
-Un jeu de morpion : le  joueur 1 coche un case, il envoie directement au serveur quel case il a cocher, le serveur dit au joueur 2 quel case le joueur 1 a cocher, et tout roule pas de problème.
-Un FPS : Le joueur 1 se déplace, il dit au serveur ou il est, le serveur envoie la position du joueur 1 au joueur 2.

ATTENTION
Mais !
A quel moment doit-on envoyer notre position ? quand est-ce que le serveur renvoie la position de tout les joueurs a tout le monde ?
Imaginons que à chaque frame on envoie notre position au serveur, cela est-il suffisant, sachant que l'on sait que pour une animation fluide, il faut au minimum 25 frames par seconde. Mais imaginons que sur notre premier client on tourne à 50 fps. On envoie donc 50 fois par seconde notre position au serveur, qui lui, dès qu'il la reçois, il la renvoie au autre client. Seulement, imaginons que le 2em client tourne a 30 fps. Ce client va donc vite se retrouver déborder, il va donc avoir plus de paquet à lire qu'il n'est capable de le faire (on part bien-sûr avec le code exemple de la console au dessus, ou notre client ne sait lire que 1 paquet par frame). Bien des solutions existe pour remédier a ce genre de problème :

1= On envoie notre position au serveur toutes les 40 millisecondes (ce qui correspond à 25 fois par seconde). Et le serveur renvoie la position à tout les client toutes les 40 ms à sont tour. En théorie ça marche bien, à condition que le client et le serveur tourne à plus de 25fps.(en général le serveur tourne largement plus vite, surtout si on ne l'utilise que en console)
Personnellement, j'ai pour habitude de gérer le temps avec clock(). exemple :

Code c++ :

#include <ctime>

int main(void)
{
  clock_t tempsActuel = clock();
  clock_t tempsEcouler = clock();
  while(1)
  {
      tempsEcouler = clock();
      if(tempsEcouler - tempsActuel > 40)
      {
          //on fait tous les trucs que l'on a envie de faire toute les 40ms
          tempsActuel = clock();  //et on remet a jour "tempsActuel"
      }
  }
}

Mais vous pouvez très bien utiliser ce qu'il vous plait.

2=On fait une boucle qui li tout les paquets reçus avant d'afficher le rendu. ça marche aussi pas mal, sauf si on reçois d'un coup énormément de paquets et là, on va ramer un gros coup.

3=On fait un mélange des 2 premières solution, on essaye d'optimiser au maximum pour envoyer le moins de paquet possible. On envoi notre position toutes les 40 ms mais seulement si on a bouger depuis la dernière fois.

4=Pour encore plus de rapidité pour les clients, on sait que bien souvent les perte de FPS sont en partie a cause des collisions (notamment avec Irrlicht) Alors, même si c'est un peut plus compliquer, on peut très bien ne gérer aucune collision sur le programme client, mais plutôt laisser le serveur s'en charger. Si on fait un serveur sans interface graphique, il ne perd quasiment rien en rapidité même avec une gestion des collisions. Cela implique que le personnage du client ne bouge pas directement pour ensuite envoyer sa position au serveur, mais fait une demande au serveur de bouger, et c'est le serveur qui place le personnage.

Il y a encore un bon nombre de chose pouvant être réaliser, avec un peu d'imagination, on peut réaliser de très belle chose...


INFO
NINJA !!
c'est partie !
Bon, nous dans notre exemple du Ninja nous allons codé en utilisant la première solution, ce n'est pas la plus optimisée mais pour faire tourner une api composée seulement de 2 ninjas et 1 terrain, ça devrais suffire.

Je vais mettre un maximum de commentaire dans le code plutôt que de faire un long chapitre explicatif

ATTENTION
depuis la version 1.5.1 de Irrlicht, il n'est plus possible de lancer 2 clients simultanément utilisant une caméra FPS, il vous faudra donc au moins 2 ordinateurs pour testé ce programme (1 serveur et client et 1 client)


LE SERVEUR

Code c++ :

#include <irrlicht.h>

#include "RakNetworkFactory.h"
#include "RakPeerInterface.h"
#include "MessageIdentifiers.h"
#include <BitStream.h>
#include <RakNetTypes.h>

#include <conio.h>// for getch()
#include <ctime>//for clock()

using namespace std;
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace gui;


// creation de nos propre ID
const unsigned char PACKET_ID_DEPLACEMENT = 101;
const unsigned char PACKET_ID_ANIMATION = 102;
const unsigned char PACKET_ID_ID_JOUEUR = 103;


///////////////////////////////////////////////////////////////////////////////////////////////////////
///                     MES FONCTIONS
///////////////////////////////////////////////////////////////////////////////////////////////////////

//pour envoyer un ID a notre joueur qui vient de se connecter
void send_a_ID_joueur(RakPeerInterface *serveur, int ID_joueur)
{
    RakNet::BitStream data;// creation de nos data a envoyer
    data.Write(PACKET_ID_ID_JOUEUR);// on ecrit l'ID de notre packet
    data.Write(ID_joueur);// l'ID du joueur a envoyer
    serveur->Send(&data, HIGH_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, true);
}

    //**un fonction pour envoyer l'animation de notre ninja au client
    //on notera que ici on n'envoie pas le paquet au client nous nous
    //l'avait envoyer (packet->systemAddress)
void send_animation(RakPeerInterface *serveur, Packet *packet, int ID_joueur, bool il_marche)
{
    RakNet::BitStream data;
    data.Write(PACKET_ID_ANIMATION);
    data.Write(ID_joueur);
    data.Write(il_marche);
    serveur->Send(&data, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, true);
}


///////////////////////////////////////////////////////////////////////////////////////////////////////
///                     LA FONCTIONS MAIN
///////////////////////////////////////////////////////////////////////////////////////////////////////
int main(void)
{

    int maxClient = 2;
    int portServeur = 10000;

    // création de l'interface serveur
    RakPeerInterface *serveur = RakNetworkFactory::GetRakPeerInterface();
    // creation d'un packet
    Packet * packet = NULL;

    // demarrage du serveur
    serveur->Startup(maxClient, 10, &SocketDescriptor(portServeur,0), 1);
    /// OBLIGATOIRE, sinnon on n'accepte aucun client
    serveur->SetMaximumIncomingConnections(maxClient);

    printf("Le client <%s> vient de se connecter\n", portServeur);
    printf("Demarrage du serveur sur le port %d\n", maxClient);

    //une variable pour gerer l'ID du client, cette ID seras envoyer au client a sa connection
    //Cette ID lui seras envoyer a lui seul et attribuer tous le long de sa connection
    //C'est qui qui serviras a l'identifier et a se faire identifier
    int ID_joueur = 0;

    bool il_marche = false;//servira a gerer si le ninja du client marche ou pas pour le dire au autre

    // servira a enregistrer la position et la rotation des ninja
    vector3df positionJoueur[2];
    vector3df rotationJoueur[2];
    //initialisation
    positionJoueur[0].X = 0;
    positionJoueur[0].Y = 0;
    positionJoueur[0].Z = 0;
    positionJoueur[1].X = 0;
    positionJoueur[1].Y = 0;
    positionJoueur[1].Z = 0;

    //pour gerer le temps
    clock_t tempsActuel = clock();
    clock_t tempsEcouler = clock();


    //la grande boucle
    bool continuer = true;
    while(continuer)
    {
        //on verifie si on a reçu un packet
        packet = serveur->Receive();
        if(packet != NULL)// si oui
        {
               unsigned char packetID;
                //creation de data que l'on est pret a recevoir
                RakNet::BitStream dataStream(packet->data, packet->length, false);

                dataStream.Read(packetID);// on commence par lire l'ID du paquet que l'on vient de recevoir

                int un_ID_Joueur;//servira a identifier quelle client a envoyer un paquet

                switch(packetID)
                {

                    case ID_NEW_INCOMING_CONNECTION:
                        //Un nouveau client vient de se connecter, on lui envoie un ID
                        //qui lui servira à s'autentifier
                            send_a_ID_joueur(serveur, ID_joueur);
                            ID_joueur++;
                            break;

                    case PACKET_ID_DEPLACEMENT:
                        //on reçois la position et la rotation d'un client
                        //on l'enregistre
                            dataStream.Read(un_ID_Joueur);
                            dataStream.Read(positionJoueur[un_ID_Joueur]);
                            dataStream.Read(rotationJoueur[un_ID_Joueur]);
                            break;

                    case PACKET_ID_ANIMATION:
                        //on reçoit l'animation d'un client, on l'envoie a l'autre client
                            dataStream.Read(un_ID_Joueur);
                            dataStream.Read(il_marche);
                            send_animation(serveur, packet, un_ID_Joueur, il_marche);
                            break;

                    case ID_NO_FREE_INCOMING_CONNECTIONS:
                            // ID automatiquement reçu si on client tente de se connecter mais que le nombre de client maxi est atteint
                            printf("Avec %d client maxi\n");
                            break;

                    case ID_CONNECTION_LOST:
                            //ID automatiquement reçu si on client perd la connection
                            printf("Bienvenue a %s .\n");
                            break;

                    default:
                        // si on l'ID d'un paquet que l'on a pas referencer on le dit
                        //ceci n'est pas forcement un probleme !
                        printf("le serveur est plein.\n", int(packetID));
                }

            serveur->DeallocatePacket(packet);
        }

        //envoie la position des joueurs a tout le monde toute les 40 ms
    tempsEcouler = clock();
    if(tempsEcouler - tempsActuel > 40)
    {
        for(int i = 0; i < 2; i++)
        {
            RakNet::BitStream data;
            data.Write(PACKET_ID_DEPLACEMENT);
            data.Write(i);
            data.Write(positionJoueur[i]);
            data.Write(rotationJoueur[i]);
            serveur->Send(&data, HIGH_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, true);
        }
        tempsActuel = clock();
    }


        // la gestion des touche au clavier, ici on va juste gerer la touche echap pour quitter
        if (kbhit())
        {
            int key = getch();
            if (key == 27)// 27 est egale a la touche echap
            {
                continuer = false;
            }
        }

    }// fin de la boucle principale du programme

    // destruction de l'interface serveur
    RakNetworkFactory::DestroyRakPeerInterface(serveur);

    return 0;

}



LE CLIENT

Code c++ :

#include <irrlicht.h>

#include "RakNetworkFactory.h"
#include "RakPeerInterface.h"
#include "MessageIdentifiers.h"
#include <BitStream.h>
#include <RakNetTypes.h>
#include <iostream>

#include <conio.h>// for getch()

using namespace std;
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace gui;

// creation de nos propre ID
const unsigned char PACKET_ID_DEPLACEMENT = 101;
const unsigned char PACKET_ID_ANIMATION = 102;
const unsigned char PACKET_ID_ID_JOUEUR = 103;

///////////////////////////////////////////////////////////////////////////////////////////////////////
///                     MES CLASS
///////////////////////////////////////////////////////////////////////////////////////////////////////

class MyEventReceiver : public IEventReceiver
{
public:
        // This is the one method that we have to implement
        virtual bool OnEvent(const SEvent& event)
        {
                // Remember whether each key is down or up
                if (event.EventType == irr::EET_KEY_INPUT_EVENT)
                        KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;

                return false;
        }

        // This is used to check whether a key is being held down
        virtual bool IsKeyDown(EKEY_CODE keyCode) const
        {
                return KeyIsDown[keyCode];
        }

        MyEventReceiver()
        {
                for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
                        KeyIsDown[i] = false;
        }

private:
        // We use this array to store the current state of each key
        bool KeyIsDown[KEY_KEY_CODES_COUNT];
};


///////////////////////////////////////////////////////////////////////////////////////////////////////
///                     LA FONCTIONS MAIN
///////////////////////////////////////////////////////////////////////////////////////////////////////

int main(void)
{
    int portServeur = 10000;
    char IP_serveur[20];
    // on commence par entrez l'adresse du serveur
    printf("Le client <%s> vient de se connecter\n");
    scanf("Demarrage du serveur sur le port %d\n", IP_serveur);

    // création de l'interface serveur
    RakPeerInterface *client = RakNetworkFactory::GetRakPeerInterface();
    // creation d'un packet
    Packet * packet = NULL;

    // demarrage du client
    client->Startup(1,10,&SocketDescriptor(), 1);
    client->Connect(IP_serveur, portServeur, 0,0);

    MyEventReceiver myReceiver;
    IrrlichtDevice *device = createDevice(EDT_DIRECT3D9, dimension2d<u32>(800,600),32,false,false,false);
    IVideoDriver* driver = device->getVideoDriver ();
    ISceneManager* sceneMgr  = device->getSceneManager ();
    device->setEventReceiver(&myReceiver);
    device->getCursorControl()->setVisible(false);

    //creation de notre camera
    ICameraSceneNode* myCamera = sceneMgr->addCameraSceneNodeFPS(0, 100.0f, 0.50f);
    myCamera->setPosition(vector3df(500,100,500));

    //création du terrain
     scene::ITerrainSceneNode* terrain = sceneMgr->addTerrainSceneNode(
                "Avec %d client maxi\n",
                0,
                -1,
                core::vector3df(0.f, 0.f, 0.f),
                core::vector3df(0.f, 0.f, 0.f),
                core::vector3df(10.f, 0.3f, 10.f),
                video::SColor ( 255, 255, 255, 255 ),
                5,
                scene::ETPS_17,
                4
                );
        terrain->setMaterialFlag(video::EMF_LIGHTING, false);
        terrain->setMaterialTexture(0,driver->getTexture("Bienvenue a %s .\n"));
        terrain->setMaterialTexture(1,driver->getTexture("le serveur est plein.\n"));
        terrain->setMaterialType(video::EMT_DETAIL_MAP);
        terrain->scaleTexture(1.0f, 20.0f);
         // create triangle selector for the terrain
        ITriangleSelector* selector = sceneMgr->createTerrainTriangleSelector(terrain, 0);
        terrain->setTriangleSelector(selector);
       // terrain->setVisible(false);
        // create collision response animator and attach it to the camera
        ISceneNodeAnimator* anim = sceneMgr->createCollisionResponseAnimator(
                selector, myCamera,
                vector3df(60,100,60),
                vector3df(0,-5,0),
                vector3df(0,100,0));
        selector->drop();
        myCamera->addAnimator(anim);
        anim->drop();

    //on  creer 2 ninja, un rouge et un bleu
    IAnimatedMeshSceneNode* ninja[2];
    ninja[0] = sceneMgr->addAnimatedMeshSceneNode(sceneMgr->getMesh("Un client a perdu la connection.\n"));
    ninja[0]->setMaterialFlag(video::EMF_LIGHTING, false);
    ninja[0]->setScale(vector3df(30,30,30));
    ninja[0]->setFrameLoop(184,205);// on les mes sur une animation IDLE pour commencer
    ninja[0]->setAnimationSpeed(10);
    ninja[1] = sceneMgr->addAnimatedMeshSceneNode(sceneMgr->getMesh("Reception d'un packet avec un ID inconnue: %i\n"));
    ninja[1]->setMaterialTexture(0, driver->getTexture("Entrez l'adresse IP su serveur :"));
    ninja[1]->setMaterialFlag(video::EMF_LIGHTING, false);
    ninja[1]->setScale(vector3df(30,30,30));
    ninja[1]->setFrameLoop(184,205);
    ninja[1]->setAnimationSpeed(10);

    //on defini une variable qui va nous servir a nous identifier
    int my_ID_Joueur = -1;
    //et une autre pour identifier le/les autre(s)
    int un_ID_Joueur = 0;
    //servira a recuperer les positions et rotation des joueur envoyer par le serveur
    vector3df une_position;
    vector3df une_rotation;

    bool je_marche = false;//pour dire au serveur si on est entrain de marcher ou pas
                           //cela sert au autre pour joueur l'animation
    bool il_marche = false;//nous sert pour joueur l'animation des autres joueurs

    //pour la gestion du temps
    clock_t tempsActuel = clock();
    clock_t tempsEcouler = clock();


/// On fait une boucle pour la connection, ici on va attendre de savoir si la connection
/// au serveur est OK ou non et attendre de recevoir un ID envoyer par le serveur
///on continue cette boucle temps que notre ID est inferieur à 0.
do
{
    packet = client->Receive();
    if(packet != NULL)// si oui
    {
        unsigned char packetID;
        //creation de data que l'on est pret a recevoir
        RakNet::BitStream dataStream(packet->data, packet->length, false);
        // on commence par lire l'ID du paquet que l'on vient de recevoir
        dataStream.Read(packetID);
        switch(packetID)
        {
            case ID_CONNECTION_REQUEST_ACCEPTED:
                     printf("%s");
                     break;

            case ID_CONNECTION_ATTEMPT_FAILED:
                            //on reçois cet ID automatiquement si on arrive pas a ce connecter au serveur
                            printf("Entrez votre nom :");
                            break;

            //le packet qui nous donne notre ID joueur
            case PACKET_ID_ID_JOUEUR:
                    dataStream.Read(my_ID_Joueur);
                    printf("%s", my_ID_Joueur);
                    ninja[my_ID_Joueur]->setParent(myCamera);
                    ninja[my_ID_Joueur]->setPosition(vector3df(000,-210,-30));
                    break;

        }
    }
}while(my_ID_Joueur < 0);//c'est que l'on a bien reçu notre ID

///****************************************************
///                         LA GRANDE BOUCLE
///****************************************************
    while (device->run())
    {
        //on verifie si on a reçu un packet
        packet = client->Receive();
        if(packet != NULL)// si oui
        {
               unsigned char packetID;
                //creation de data que l'on est pret a recevoir
                RakNet::BitStream dataStream(packet->data, packet->length, false);
                // on commence par lire l'ID du paquet que l'on vient de recevoir
                dataStream.Read(packetID);

                switch(packetID)
                {
                    //un packet qui indique la position des joueurs
                    case PACKET_ID_DEPLACEMENT:
                            dataStream.Read(un_ID_Joueur);//on li l'ID du joueur a qui correspond cette position
                            dataStream.Read(une_position);//on li la position
                            dataStream.Read(une_rotation);//puis la rotation
                            //bien sur on n'effectue un changement sur la position du joueur
                            //seulement si c'est pas le notre
                            if(un_ID_Joueur != my_ID_Joueur)
                            {   //on place le joueur et on le tourne par rapport au valeur reçu precedement
                                ninja[un_ID_Joueur]->setPosition(une_position);
                                ninja[un_ID_Joueur]->setRotation(une_rotation);
                            }
                            break;

                    //un packet qui indique l'animation des autres joueurs
                    case PACKET_ID_ANIMATION:
                            dataStream.Read(un_ID_Joueur);//on li l'ID du joueur a qui correspond cette position
                            dataStream.Read(il_marche);//on li si il marche
                            if(il_marche)
                            {
                                ninja[un_ID_Joueur]->setFrameLoop(1,14);
                            }
                            else
                            {
                                ninja[un_ID_Joueur]->setFrameLoop(184,205);
                            }
                            break;

                    default:
                        // si on l'ID d'un paquet que l'on a pas referencer on le dit
                        //ceci n'est pas forcement un probleme !
                        printf("La connection au serveur a bien ete accepter\n", int(packetID));
                }

            client->DeallocatePacket(packet);//on vide le packet
        }

///////////////////////////////////////////////////////////////////////////////////////////////////////
///                     GESTION DES EVENEMENTS AU CLAVIER
///////////////////////////////////////////////////////////////////////////////////////////////////////
    // pour quittez le programme
        if(myReceiver.IsKeyDown(irr::KEY_ESCAPE))
        {
            device->closeDevice();
        }
        //si on avance on bouge on envoie dit au serveur que l'on est entrain de marcher
        //pour que lui le dise au autres et qu'il joue l'animation
        if(myReceiver.IsKeyDown(irr::KEY_UP) || myReceiver.IsKeyDown(irr::KEY_DOWN)
                    ||myReceiver.IsKeyDown(irr::KEY_LEFT) || myReceiver.IsKeyDown(irr::KEY_RIGHT))
                {
                    if(!je_marche)//on verifie si on ne marchait pas deja avant
                    {             //car si c'est le cas, on l'a deja dit au serveur
                        je_marche = true;
                        // on envoie notre statue au serveur
                        RakNet::BitStream data;
                        data.Write(PACKET_ID_ANIMATION);
                        data.Write(my_ID_Joueur);//on ecrit notre ID_joueur pour que le serveur sait de qui il s'agit
                        data.Write(je_marche);//on dit si on est entrain de marcher
                        //et on envoie ça au serveur
                        client->Send(&data, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, true);
                    }
                }
        else//c'est que l'on appuie ni sur haut/bas/gauche ou droite
            {
                //on verifie si on etait entrain de marcher, si oui, on dit au
                //serveur que l'on a arreté.
                if(je_marche)
                {
                    je_marche = false;
                    RakNet::BitStream data;
                    data.Write(PACKET_ID_ANIMATION);
                    data.Write(my_ID_Joueur);//on ecrit notre ID_joueur pour que le serveur sait de qui il s'agit
                    data.Write(je_marche);//on dit si on est entrain de marcher
                    //et on envoie ça au serveur
                    client->Send(&data, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, true);
                }
            }

///////////////////////////////////////////////////////////////////////////////////////////////////////
///                 ENVOIE NOTRE POSTION AU SERVEUR TOUTE LES 30 MS
///////////////////////////////////////////////////////////////////////////////////////////////////////
    tempsEcouler = clock();//mise a jour du temps ecouler
    if(tempsEcouler - tempsActuel > 30)//si ça fait plus de 30 ms qui se sont ecoulé
    {
            RakNet::BitStream data;
            data.Write(PACKET_ID_DEPLACEMENT);//on ecrit l'ID du packet
            data.Write(my_ID_Joueur);//on ecrit notre ID_joueur pour que le serveur sait de qui il s'agit
            une_position = ninja[my_ID_Joueur]->getAbsolutePosition();//on recupere notre position
            data.Write(une_position);//on l'ecrit dans notre packet
            une_rotation = myCamera->getRotation();//on recupere notre rotation
            //on remet la rotation des axe X et Z a zéro, sinon il est fort posible que les autres
            //vous retrouve dans des positions qui ne parraissent pas possible (en effet, car quand
            //on regarde vers le bas par exemple, du faite que notre ninja est attacher a notre camera
            //il se trouve completement coucher) essayer d'enlever ça si vous vouler pour tester
            une_rotation.X = 0;
            une_rotation.Z = 0;
            data.Write(une_rotation);//on ecrit notre rotation dans notre packet
            //et on envoie tout ça
            client->Send(&data, HIGH_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, true);

        tempsActuel = clock();//on remet le temps a jour
    }


///////////////////////////////////////////////////////////////////////////////////////////////////////
///                     MISE A JOUR DE LA scene
///////////////////////////////////////////////////////////////////////////////////////////////////////

        driver->beginScene(true, true, video::SColor(0,200,200,200));
        sceneMgr->drawAll ();
        driver->endScene ();


    }// fin de la boucle principale du programme

    device->drop();

    // destruction de l'interface serveur
    RakNetworkFactory::DestroyRakPeerInterface(client);

    return 0;

}




Bien-sûr il y a énormément de chose qu'on pourrait rajouté ici pour rendre ce petit programme un peu prêt correct, je vous suggère même de le faire. Créer une class pour les personnages, enregistrer le nom des ninjas, leurs rajouter des animations.... lâchés-vous wink


Toutes les remarques sur ce tutoriel sont les bienvenue afin de le rendre le plus complet et compréhensible possible.

#1 

22-10-2009 18:46:22

nico
Webmaster
Date d'inscription: 07-08-2009
Messages: 563
Corrections: 9

Super le tuto smile il me sera utile dans quelques temps smile

Hors ligne


#2 

22-10-2009 21:32:16

tmyke
Administrateur
Date d'inscription: 24-03-2008
Messages: 1025

Je vais lire cela de près, la partie réseau est vraiment un domaine ou j'ai de forte lacune, voilà une occasion de bien progresser big_smile


Force et sagesse...

Hors ligne


#3 

23-10-2009 11:05:55

TUpac
Habitué
Date d'inscription: 08-09-2009
Messages: 387
Corrections: 1

Je ne te dirais pas merci même si ton tuto est génial. C'est juste que j'ai fait tout ça à la mimine y'a un ptit bout de temp. Donc pas merci mais bravo :p


"Si vous ne partagez pas votre stabilité avec les pauvres, les pauvres partageront leur instabilité avec vous."

Hors ligne


#4 

16-12-2009 11:06:03

nabouill
Abonné
Date d'inscription: 17-09-2009
Messages: 242
Corrections: 1

OK, je pense avoir un peu prêt fini ce tutoriel.
Si vous avez des suggestions, n'hésiter pas.


mes sites: www.manga-vf.fr et www.series-vf.fr

Hors ligne


#5 

14-01-2010 19:21:29

nico
Webmaster
Date d'inscription: 07-08-2009
Messages: 563
Corrections: 9

Merci nabouill, ton tuto m'aide beaucoup smile

Hors ligne


#6 

02-03-2010 13:34:01

jonath313
Abonné
Date d'inscription: 28-12-2009
Messages: 240

Vrément intéréssant tout cela je suis impatient de voir ce que çà donne! Vraiment merci j'ai à peine vu le titre de ce tuto et je me suis laisser envahir par l'envie d'essayer !!

Très bon travail !

Hors ligne


#7 

02-03-2010 13:51:44

nabouill
Abonné
Date d'inscription: 17-09-2009
Messages: 242
Corrections: 1

Merci bien,

Je vous suggère aussi d'aller faire un tour dans les dossier "DependentExtensions" du dossier RakNet ou il y a un projet Irrlicht de réaliser. et dans le dossier "Samples" qui contient un nombre énorme d'exemple de projet pouvant être réalisé (autopatch, voice, mail...)


mes sites: www.manga-vf.fr et www.series-vf.fr

Hors ligne


#8 

01-04-2010 14:31:03

jonath313
Abonné
Date d'inscription: 28-12-2009
Messages: 240

Je ne trouve pas les .lib et la Dll de RakNet dans les fichiers est-ce normal ???

Hors ligne


#9 

03-04-2010 08:28:33

nabouill
Abonné
Date d'inscription: 17-09-2009
Messages: 242
Corrections: 1

pour ceux a qui ça arriverais solution ici: http://irrlicht-fr.org/viewtopic.php?pid=8160#p8160


mes sites: www.manga-vf.fr et www.series-vf.fr

Hors ligne


#10 

06-02-2011 17:01:49

hitmax
Petit nouveau
Date d'inscription: 27-11-2009
Messages: 9

Bonjour, j'ai un problème, avec ce tuto des ninjas, quand je test avec 2 pc, le pc qui n'héberge pas le serveur envoie au bout de 1 ou 2 minutes :
ENDING SLOW START
Initial SND=0.042959 Megabytes per second
Et là il n'envoie plus rien au serveur et le serveur affiche aussi ENDING ... Initital ...

Je voudrai savoir pourquoi ça fait ça.

Merci

Hors ligne


#11 

06-02-2011 17:04:59

tmyke
Administrateur
Date d'inscription: 24-03-2008
Messages: 1025

Perso, je ne suis pas doué pour le reseau, plus qu'a attendre que nabouill passe par là wink


Force et sagesse...

Hors ligne


#12 

21-02-2011 17:37:33

hitmax
Petit nouveau
Date d'inscription: 27-11-2009
Messages: 9

Vous ne savez toujours pas pourquoi j'ai cette erreur ?

Hors ligne


#13 

27-02-2011 00:52:42

nabouill
Abonné
Date d'inscription: 17-09-2009
Messages: 242
Corrections: 1

salut, tu utilise quel version de RakNet ?
Il semblerais qu'il y ai eu un bug dans des version de RakNet mais qui serais corrigé dans les dernière version.
Aussi, il dise que cela peut être du a un problème mémoire sur le PC, a voir, peut etre essayer avec un autre pc du coup.

A+


mes sites: www.manga-vf.fr et www.series-vf.fr

Hors ligne


#14 

05-05-2011 14:00:05

Oelth
Petit nouveau
Date d'inscription: 05-05-2011
Messages: 8

Hello !
Desolé de remonter le topic,
mais je souhaitais d'une part te féliciter pour
ce tutoriel fort abouti, et d'autre part poser une question.
Ayant actuellement un projet à réaliser sous Irrlicht,
je souhaitais m'occuper de la partie réseau via Raknet.
J'ai donc chargé les fichiers à compiler pour créer la dll,
mais petit soucis, j'utilise Visual Studio 10. Et comme
les sources pour ce dernier ne sont pas disponibles
j'ai essayé de compiler avec le source pour visual 2008.
J'ai donc mis à jour le projet, mais la compilation ne veut pas s'effectuer.
J'obtiens lors de la compilation des warning :

Code:

1>------ Début de la génération : Projet : DLL, Configuration : Debug Win32 ------
1>La génération a démarré 05/05/2011 13:51:43.
1>InitializeBuildStatus:
1>  Création de "Debug\DLL.unsuccessfulbuild", car "AlwaysCreate" a été spécifié.
1>ClCompile:
1>  Ignoré... (aucune modification pertinente détectée)
1>  WSAStartupSingleton.cpp
1>  VariadicSQLParser.cpp
1>  VariableListDeltaTracker.cpp
1>  VariableDeltaSerializer.cpp
1>  UDPProxyServer.cpp
1>  UDPProxyCoordinator.cpp
1>  UDPProxyClient.cpp
1>  UDPForwarder.cpp
1>  TwoWayAuthentication.cpp
1>  ThreadsafePacketLogger.cpp
1>  TelnetTransport.cpp
1>  TeamBalancer.cpp
1>  TCPInterface.cpp
1>  TableSerializer.cpp
1>  SuperFastHash.cpp
1>  StringTable.cpp
1>  StringCompressor.cpp
1>  SocketLayer.cpp
1>  SimpleMutex.cpp
1>  SignaledEvent.cpp
1>  SHA1.cpp
1>  SendToThread.cpp
1>  SecureHandshake.cpp
1>  RPC4Plugin.cpp
1>  Router2.cpp
1>  ReplicaManager3.cpp
1>  ReliabilityLayer.cpp
1>  ReadyEvent.cpp
1>  rdlmalloc.cpp
1>  Rand.cpp
1>  RakWString.cpp
1>  RakThread.cpp
1>  RakString.cpp
1>  RakSleep.cpp
1>  RakPeer.cpp
1>  RakNetTypes.cpp
1>  RakNetTransport2.cpp
1>  RakNetStatistics.cpp
1>  RakNetSocket.cpp
1>  RakNetCommandParser.cpp
1>  RakMemoryOverride.cpp
1>  Rackspace.cpp
1>  PluginInterface2.cpp
1>  PacketOutputWindowLogger.cpp
1>  PacketLogger.cpp
1>  PacketizedTCP.cpp
1>  PacketFileLogger.cpp
1>  PacketConsoleLogger.cpp
1>  NetworkIDObject.cpp
1>  NetworkIDManager.cpp
1>  NatTypeDetectionServer.cpp
1>  NatTypeDetectionCommon.cpp
1>  NatTypeDetectionClient.cpp
1>  NatPunchthroughServer.cpp
1>  NatPunchthroughClient.cpp
1>  MessageFilter.cpp
1>  LogCommandParser.cpp
1>  LocklessTypes.cpp
1>  LinuxStrings.cpp
1>  Itoa.cpp
1>  IncrementalReadInterface.cpp
1>  HTTPConnection.cpp
1>  GridSectorizer.cpp
1>  gettimeofday.cpp
1>  GetTime.cpp
1>  Gets.cpp
1>  Getche.cpp
1>  FullyConnectedMesh2.cpp
1>  FormatString.cpp
1>  FileOperations.cpp
1>  FileListTransfer.cpp
1>  FileList.cpp
1>  EpochTimeToString.cpp
1>  EncodeClassName.cpp
1>  EmailSender.cpp
1>  DynDNS.cpp
1>  DS_Table.cpp
1>  DS_HuffmanEncodingTree.cpp
1>  DS_ByteQueue.cpp
1>  DS_BytePool.cpp
1>  DirectoryDeltaTransfer.cpp
1>  DataCompressor.cpp
1>  ConsoleServer.cpp
1>  ConnectionGraph2.cpp
1>  CommandParserInterface.cpp
1>  CloudServer.cpp
1>  CloudCommon.cpp
1>  CloudClient.cpp
1>  CheckSum.cpp
1>  CCRakNetUDT.cpp
1>  CCRakNetSlidingWindow.cpp
1>  BitStream.cpp
1>  _FindFirst.cpp
1>ManifestResourceCompile:
1>  Toutes les sorties sont à jour.
1>C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppBuild.targets(990,5): warning MSB8012: TargetPath(D:\Documents\Utilitaires\raknet\Lib\DLL\Debug\DLL.dll) ne correspond pas à la valeur de la propriété OutputFile (D:\Documents\Utilitaires\raknet\Lib\RakNetDebug.dll) de Linker. Cela peut entraîner une génération incorrecte de votre projet. Pour corriger ce problème, vérifiez que les valeurs des propriétés $(OutDir), $(TargetName) et $(TargetExt) correspondent à la valeur spécifiée dans %(Link.OutputFile).
1>C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppBuild.targets(992,5): warning MSB8012: TargetName(DLL) ne correspond pas à la valeur de la propriété OutputFile (RakNetDebug) de Linker. Cela peut entraîner une génération incorrecte de votre projet. Pour corriger ce problème, vérifiez que les valeurs des propriétés $(OutDir), $(TargetName) et $(TargetExt) correspondent à la valeur spécifiée dans %(Link.OutputFile).
1>Link:
1>     Création de la bibliothèque Debug\../../RakNetDLLDebug.lib et de l'objet Debug\../../RakNetDLLDebug.exp
1>Manifest:
1>  Toutes les sorties sont à jour.
1>LinkEmbedManifest:
1>  Toutes les sorties sont à jour.
1>  DLL_vc8.vcxproj -> D:\Documents\Utilitaires\raknet\Lib\DLL\Debug\DLL.dll
1>FinalizeBuildStatus:
1>  Suppression du fichier "Debug\DLL.unsuccessfulbuild".
1>  Mise à jour de l'horodatage "Debug\DLL.lastbuildstate".
1>
1>La génération a réussi.
1>
1>Temps écoulé 00:00:04.95
========== Génération : 1 a réussi, 0 a échoué, 0 mis à jour, 0 a été ignoré ==========

Donc il m'indique que la génération à réussie mais j'ai tout de même une fenêtre qui m'affiche le message suivant :

Impossible de démarrer le programme
'D:\Documents\Utilitaires\raknet\Lib\DLL\Debug\DLL.dll'.
Le fichier spécifié est introuvable.


Ma question est donc, ai je fait quelque chose de travers ? Ou alors manqué une étape (sachant que j'essaye de compiler DLL.vc8_vcxproj qui est dans le dossier ./Lib/DLL de Raknet)?  Quelqu'un serait il déjà parvenu à faire fonctionner Raknet sous VS10 ? Si oui comment ? ^^"

Merci beaucoup par avance pour vos réponses.




EDIT : Probleme résolu !
En fait il suffit d'inclure les sources dans le projet, j'ai suivi ce tuto : http://www.jenkinssoftware.com/raknet/m … setup.html
fais pour visual c++ 2005 et ça marche pour visual c++ 2010, merci tout de même !

Dernière modification par Oelth (10-05-2011 21:15:16)

Hors ligne


#15 

02-02-2012 14:49:48

Kirk
Membre
Date d'inscription: 02-02-2012
Messages: 14

Super tuto, merci beaucoup !!!


wofwar.olympe.in

Hors ligne


Options Liens officiels Caractéristiques Statistiques Communauté
Corrections
irrlicht
irrklang
irredit
irrxml
xhtml 1.0
css 2.1
Propulsé par FluxBB
Traduit par FluxBB.fr
Analysé par
880 membres
1424 sujets
11113 messages
Dernier membre inscrit: mandrifidy
24 invités en ligne
Aucun membre connecté
RSS Feed