IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C++ Discussion :

Template, classes, héritage et gros problème


Sujet :

C++

  1. #1
    Membre régulier
    Avatar de alpha_one_x86
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2006
    Messages
    411
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2006
    Messages : 411
    Points : 113
    Points
    113
    Par défaut Template, classes, héritage et gros problème
    Bonjour, je vais essayer d'étre claire, mais c'est déjà pas bien claire dans ma tête.
    J'ai vu le topic http://www.developpez.net/forums/d12...pecialisation/, je ne sais pas si ça as un lien avec mon sujet ou pas. (Pas le niveau en template).
    J'ai une énorme map divisé en chunk. Cela est dans un contexte jeux 2D, jeu solo et jeu multi + serveur.

    • Chaque chunk contiens le chunk d'as coté, la taille un chunk, couche de colision, ...
    • Sur la partie serveur j'ai des méta-données qui sont: liste de joueurs sur chaque chunk, ...
    • Sur la partie client j'ai des méta-données qui sont: image pour les tiles, ...


    J'ai des classes qui vont avoir besoin des méta-donnée spécifique, et d'autre non.
    Je m'explique:
    • Pour les déplacement générique j'ai besion juste des info des chunks (générique), utilisé pour les bot, qui sont des clients sans besoin de méta-données, car il n'utilise pas l'affichage
    • Utilisation du point 1) + Sur le client je fait la même chose, mais je doit toujours avoir les méta-données (pour afficher map courrante et proche)
    • Utilisation du point 1) + Sur le serveur je doit avoir les méta-données, pour envoyé les déplacements du joueurs courrant aux autre joueurs

    Et les bots, sont coté serveur, donc je leur passe les chunks avec méta-données serveur.

    Et donc voila, je maitrise un minimum l'héritage, pas du tout les templates. Et la j'ai besoin d'un joyeux bordel pour faire proprement tout ça.
    Faire 2x structure de données, m'obligae à faire 2x la classe, non?

    J'ai pensais faire 2 strucutre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Map_server
    {
    Map_server *map_left;
    ...
    }
    Map_client
    {
    Map_client *map_left;
    ...
    }
    Et les méthodes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    void moveBasic(Map_server * baseMap);
    void moveClient(Map_client * baseMap);//moveClient hériterai de Map_server et ou Map_server serai caster en Map_client
    Bref, je sens qu'il me manque des connaissances pour évité la duplication de code.
    Merci d'avance de votre aide.

  2. #2
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    Peut-être la solution serait-elle de créer trois classes, et non deux.
    Une classe Map, les données d'une map communes à clients et serveurs.
    Une classe Map_client, qui ajoute les données spécifiques aux clients (et qui hérite de Map).
    Une classe Map_server... tu devines !

    Tu compilerais Map_server uniquement pour la construction de l'exécution côté serveur, et Map_client pour celle de l'exécution côté client.

    Qu'en penses-tu ?

  3. #3
    Membre régulier
    Avatar de alpha_one_x86
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2006
    Messages
    411
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2006
    Messages : 411
    Points : 113
    Points
    113
    Par défaut
    Le problémes, c'est que je passe d'une map à une autre, dans un cas je fait:
    Map * map=(quelque chose en Map *);
    Et donc je le fait dans la classe map, lors d'une sortie map.
    Hors quand je suis en Map_server, je doit avoir Map_server.
    En gros l'objet private, doit étre de type Map * pour la classe Map, et de type Map_server * pour la classe Map_server...

    EDIT: je suis en train justement de coder pour matérialisé le probléme.

    Voila l'exemple:
    https://github.com/alphaonex86/Pokec...ntStructures.h
    https://github.com/alphaonex86/Pokec...erStructures.h
    Ou j'ai mes objects pour les maps.

    La duplication de code (même code à 100%):
    https://github.com/alphaonex86/Pokec...Map_Client.cpp
    https://github.com/alphaonex86/Pokec...Map_Server.cpp

    Et dans la def juste un type de variable qui change:
    https://github.com/alphaonex86/Pokec...heMap_Client.h
    https://github.com/alphaonex86/Pokec...heMap_Server.h
    MoveOnTheMap_Client *map; <-> Map_server *map;

    Et c'est pas la 1ére fois que je suis bloquer comme ça.

  4. #4
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    Tu fusionnes MoveOnTheMap_* ; et tu leur donne un pointeur sur Map.
    Tu fais hériter Map_Client et Map_Server de Map.
    Map contient toutes les données indépendantes de si c'est un client ou un serveur, les fonctions qui travaillent uniquement dessus, et potentiellement des fonctions virtuelles, si nécessaire.

    Et c'est bon !

  5. #5
    Membre régulier
    Avatar de alpha_one_x86
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2006
    Messages
    411
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2006
    Messages : 411
    Points : 113
    Points
    113
    Par défaut
    Ca fait que dans ma classe qui hérite de MoveOnTheMap_Server je doit avoir:
    Map_client map_spec;
    Et j'hérite:
    Map map;
    Soit 2 pointeur sur la même variables. Ou je doit caster comme un porc...
    Non?

    Si j'hérite d'une classe avec une template...?

  6. #6
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    Quelle classe qui hérite de MoveOnTheMap_server ?
    As-tu bien compris ce que je te conseillais ?

  7. #7
    Membre régulier
    Avatar de alpha_one_x86
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2006
    Messages
    411
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2006
    Messages : 411
    Points : 113
    Points
    113
    Par défaut
    assigning to 'Map_server *' from incompatible type 'Map *'
    Donc au final je cast comme un porc...

    https://github.com/alphaonex86/Pokec...pBasicMove.cpp -> plein de cast, car:
    Coté server, pour la classe représant le client, j'ai besoin de Map_server, hors:
    https://github.com/alphaonex86/Pokec...alStructures.h
    Je garde des Map * pour les pointeurs sur les map proche.

    Encore pire:
    https://github.com/alphaonex86/Pokec...Map_Server.cpp
    Je cast comme un porc sans moyen de grouper le code pour qu'il soit applicable de maniére généric sur Map * (faudrai que je retourne un pointeur que je cast dans la foulé)

  8. #8
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    "assigning to 'Map_server *' from incompatible type 'Map *'"

    Mais pourquoi essaies-tu de mettre un Map* dans un Map_server* ?
    Normalement, tu n'utilises dans MoveOnTheMap qu'une Map* ; et il est parfaitement autorisé d'upcaster implicitement un Map_server* en un Map*.

    Je récapitule :
    • Map -> Classe de base, contient les données et fonctions d'une map, mais pas celles spécifiques au serveur ni au client. Les données et fonctions communes, quoi.
    • Map_server -> Hérite de Map, ajoute les données et fonctions spécifiques au client.
    • Map_client -> idem.
    • MoveOnTheMap -> Prend en paramètre un Map& (mieux qu'un pointeur), déplace sur cette Map& en utilisant uniquement les fonctions de Map. En effet, pourquoi le déplacement serait-il différent sur le serveur ou le client ? Si il l'est, il faudra mettre une fonction virtuelle pure dans Map implémentée dans Map_[client|server] qui se charge de faire les actions supplémentaires.


    En tout cas, les templates n'ont pas grand chose à voir dans le problème : en général (ne me faites pas dire ce que je n'ai pas dit), elles vont avec une sémantique de valeur (cf. FAQ) ; alors que ta Map semble avoir une sémantique d'entité (il n'y en a qu'une).

  9. #9
    Membre régulier
    Avatar de alpha_one_x86
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2006
    Messages
    411
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2006
    Messages : 411
    Points : 113
    Points
    113
    Par défaut
    https://github.com/alphaonex86/Pokec...MoveOnTheMap.h
    Tout est la comme tu as dit.
    Hors:
    https://github.com/alphaonex86/Pokec.../Bot/FakeBot.h
    Qui est spécifique au serveur, et qui doit avoir les infos server des map, héritant de MoveOnTheMap ce retrouve avec un Map *. Je fait quoi, le Map* hérité + un Map_Server *? Ou du cast à ralonge?

  10. #10
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    Je pense qu'il y a une erreur de conception, là.

    Pourquoi un bot hériterait-il de MoveOnTheMap ? Ne devrait-il pas plutôt utiliser les services de MoveOnTheMap ? Ou bien MoveOnTheMap devrait-elle plutôt s'appeler ThingThatMovesOnTheMap ?

    Précision : Un FakeBot EST-IL un MoveOnTheMap ?

  11. #11
    Membre régulier
    Avatar de alpha_one_x86
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2006
    Messages
    411
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2006
    Messages : 411
    Points : 113
    Points
    113
    Par défaut
    Peu être que les nom sont très mal choisi (je sais jamais les choisis). Mais:
    MoveOnTheMap fourni les coordonnées (en gros, un joueur générique), la map courante, ... tout les info qui caractérise un bot ou un client (Et le FakeBot ou le vrai client, à les mêmes info, mais des info/méthode spécifique).

    J'ai le même problème dans un autre endroit du code, où la je pense avoir bien utilisé l'héritage (classe générale avec héritage pour spécialisation):
    https://github.com/alphaonex86/Pokec...thm_Simple.cpp

  12. #12
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    ... ?
    J'avoue avoir du mal à comprendre pourquoi tu veux faire hériter FakeBot de MoveOnTheMap.

    Peut-être pourrais-tu faire plutôt quelque chose comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class FakeBot : public MoveOnTheMap {
       // ...
    }; // Ancien code
    class FakeBot {
       MoveOnTheMap mover_;
       // ...
    }; // Remplacement
    Comme ça, ça te permet d'éviter de faire exposer les méthodes de MoveOnTheMap par FakeBot, qui devrait plutôt avoir des méthodes réservées à son usage. (goTo(position), par exemple).

    Avec ça, le constructeur de FakeBot peut prendre un pointeur vers une Map_server (logique, il ne peut être utilisé que par le serveur). Et il le passe au constructeur de mover_, avec l'upcast automatique et raisonnable.

    D'ailleurs... Comment un MoveOnTheMap obtient-il son pointeur vers la Map ? Je n'en vois pas mention dans son constructeur, ni nulle part... ?

    EDIT: Juste une question : es-tu certain de devoir partager suffisamment de code entre le client et le serveur pour justifier d'utiliser toute une machinerie lourde de virtualité qui ne servira jamais en pratique ? A moins que serveur et client soient dans le même exécutable ?

  13. #13
    Membre régulier
    Avatar de alpha_one_x86
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2006
    Messages
    411
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2006
    Messages : 411
    Points : 113
    Points
    113
    Par défaut
    Car aprés, les infos de map et xy sont utilisé tout le temps par les classes héritant de MoveOnTheMap.
    Ca veux qui faire dans plein de méthode avec ce nouveau code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    map_server_tp_other_player.map=static_cast<Map_server>(mover_.map);
    map_server_tp_other_player.x=mover_.x;
    map_server_tp_other_player.y=mover_.y;
    Je fait une héritage en gros car, c'est les propriétés des l'object, ce n'est pas une utilisation.

    Il obtiens sont pointer dans le constructeur de FakeBot, ça cast automatiquement. J'aurai du pour faire proprement:
    Avoir un attribut Map* dans MoveOnTheMap et Map_server* dans FakeBot. Mais ça me fait chier d'avoir 2x le même pointeur, avec juste le type qui diffère, c'est source d'erreur.

    Voila tu as compris avant que je réponse. Si c'est mutualisé, l'une des raisons, c'est que le client solo, est bêtement mettre le client multi et le serveur dans le même exécutable.
    En plus le dev précédent été un noob, il y même pas été foutu de faire correctement la classe MoveOnTheMap. Donc la je lui fourni, et si je veux faire évoluer par exemple ce qui rentre en colision, je modifie qu'une classe, et ça le modifie sur le client et sur le serveur.
    La même chose pour le calcule des combats, et plein d'autre chose, modif client et serveur c'est pas top, et source de problème. La, j'ai pas de duplication de code, c'est mieux. +50% du code est le même entre le client multi et le server. Car la plus par des calcules sont répété coté client et coté serveur pour minimisé les communications.

    En gros je devrai dans l'idée avoir l'attribut dans MoveOnTheMap:
    virtual Map* map;
    et dans FakeBot:
    Map_server* map;
    Comme ça quand je parle de map dans MoveOnTheMap, c'est de type Map. Et quand j'en parle dans FakeBot c'est de type Map_server. Et bien sur c'est qu'un seul pointeur qui pointe sur un même objet.

    C'est comme la:
    https://github.com/alphaonex86/Pokec...thm_Simple.cpp
    Si je doit mettre chaque membres en publique ou en freinds, car une classe s'en sert tout le temps. Autant en hérité.

  14. #14
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    Citation Envoyé par alpha_one_x86 Voir le message
    [...]
    Je fait une héritage en gros car, c'est les propriétés des l'object, ce n'est pas une utilisation.
    Même si ce sont les propriétés de l'objet, il vaut mieux les coller dans un autre objet, et éviter l'héritage.
    En effet, FakeBot N'EST PAS un MoveOnTheMap.
    Parce que, déjà, MoveOnTheMap propose une fonction newDirection, et il n'y a aucune raison qu'un FakeBot ait une méthode newDirection. Non ?

    Citation Envoyé par alpha_one_x86
    Il obtiens sont pointer dans le constructeur de FakeBot, ça cast automatiquement. J'aurai du pour faire proprement:
    Avoir un attribut Map* dans MoveOnTheMap et Map_server* dans FakeBot. Mais ça me fait chier d'avoir 2x le même pointeur, avec juste le type qui diffère, c'est source d'erreur.
    Il ne faut pas !
    En fait, je n'arrive déjà pas à voir l'utilisé de MoveOnTheMap...
    Pourquoi n'en fais-tu pas une fonction, qui prenne en paramètre une Entity (qui, elle, possède des coordonnées et une fonction virtuelle pure map() qui retourne un Map*, et dont hérite FakeBot), et une direction / une position d'arrivée ; et qui agit comme le fait actuellement MoveOnTheMap ?

    Citation Envoyé par alphé_one_x86
    Voila tu as compris avant que je réponse. Si c'est mutualisé, l'une des raisons, c'est que le client solo, est bêtement mettre le client multi et le serveur dans le même exécutable.
    En plus le dev précédent été un noob, il y même pas été foutu de faire correctement la classe MoveOnTheMap. Donc la je lui fourni, et si je veux faire évoluer par exemple ce qui rentre en colision, je modifie qu'une classe, et ça le modifie sur le client et sur le serveur.
    OK...
    Alors, une solution alternative pour conserver un découplage entre client et serveur, et un découpage propre du code.
    Tu fais deux exécutables, un client et un serveur. Le serveur s'occupe d'écouter sur le port 12345 ; et, selon les paramètres de lancement, écoute soit uniquement sur 127.0.0.1, soit sur 0.0.0.0/32.
    Ensuite, le client communique avec le serveur en passant par 127.0.0.1:12345.
    Lorsque le client est lancé en mode single player, il lance simplement le serveur avec l'option boucle-locale-uniquement, puis se connecte au serveur 127.0.0.1:12345. (std::system() pourra aider)
    En multiplayer, le client demande à quel serveur se connecter (ou pas), et va juste agir exactement pareil. Et le serveur est juste lancé avec l'option pas-uniquement-boucle-locale.

    Ca permet de garder un bon découplage entre client et serveur, et permet de n'avoir pas une seule ligne de code de plus pour le single player (hors appel à system).

    Citation Envoyé par alpha_one_x86
    La même chose pour le calcule des combats, et plein d'autre chose, modif client et serveur c'est pas top, et source de problème. La, j'ai pas de duplication de code, c'est mieux. +50% du code est le même entre le client multi et le server. Car la plus par des calcules sont répété coté client et coté serveur pour minimisé les communications.
    ... ?
    Répéter les calculs des deux côtés, ce n'est pas une super idée...
    Et puis, plutôt que de faire un mix du code des deux, il vaudrait mieux faire une troisième partie, qui contiendrait le code partagé entre client et serveur, et l'utiliser des deux côtés. Comme ça, on garde une séparation claire et nette des parties du programme.
    Cette troisième partie serait très bien en bibliothèque dynamique (DLL/SO/dylib), par exemple.

    Citation Envoyé par alpha_one_x86
    En gros je devrai dans l'idée avoir l'attribut dans MoveOnTheMap:
    virtual Map* map;
    et dans FakeBot:
    Map_server* map;
    Non, pas du tout !

    En fait, je me demande déjà pourquoi tu as une classe MoveOnTheMap. (cf. plus haut) Donc...

    Citation Envoyé par alpha_one_x86
    Comme ça quand je parle de map dans MoveOnTheMap, c'est de type Map. Et quand j'en parle dans FakeBot c'est de type Map_server. Et bien sur c'est qu'un seul pointeur qui pointe sur un même objet.

    C'est comme la:
    https://github.com/alphaonex86/Pokec...thm_Simple.cpp
    Si je doit mettre chaque membres en publique ou en freinds, car une classe s'en sert tout le temps. Autant en hérité.
    Non. Mieux vaut mettre public qu'hériter, dans ce cas. Enfin, je pense, il faut voir la réelle utilité de MoveOnTheMap (et surtout si elle en a une).

    En tout cas, si tu comptes vraiment conserver MoveOnTheMap, il reste une solution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template <typename TMap = Map>
    class MoveOnTheMap {
       TMap * map_;
       // ...
    };
    Ainsi, tu as un unique pointeur vers la map. Et FakeBot hériterait de MoveOnTheMap<MapServer>. Mais ça continue à me sembler horrible...

  15. #15
    Membre régulier
    Avatar de alpha_one_x86
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2006
    Messages
    411
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2006
    Messages : 411
    Points : 113
    Points
    113
    Par défaut
    Comme dit plus haut, les noms sont surment mal choisi.
    En gros newDirection c'est pour dire que mon perso, fait un pas à gauche, un autre à droite, et pour grouper les pas similaires.
    Quand le pas courant est différent alors je flush les pas similaire précédent. Avec une héritage je peu juste appeler une fonction virtuel pur, pour passer à FakeBot l'info et qu'il l'envoie sur sont socket.
    Erreur de conception?

    Car si je fait un fonction, entrée map*, x, y, direction, en sortie, map * (que je doit re-caster), x, y.

    Pour 2 raison non pour ce découpage:
    Les FakeBots servent aussi aux benchmark, c'est 270 000 messages envoyé contre 16 000 en tcp. Donc en tcp, je vais être ralenti par cette couche tcp, et les résultats, ou tentative de charge de mon serveur vont foirer. Et ce sont des bots sur le serveur, donc c'est un faux client, qui fait pour l'instant des pas aléatoire, mais qui est dans le code du serveur).
    Ensuite, il reste 50% du code qui est exactement le même, et que je vais devoir faire des 2 cotés. En gros, dans un modèle MVC, le serveur à le modèle et le contrôleur. Et le client à en plus la vue.
    Exemple combat Client/server:
    - Puise dans la random liste pour choisir le monstre/Puise dans la random liste pour choisir le monstre
    - choix d'une action/rien
    - application de l'action attaque sur les données du monstre choisi en 1/application de l'action attaque sur les données du monstre choisi en 1
    - Fin du combat, puise dans la random liste pour choisir la quantité d'argent gagné/Fin du combat, puise dans la random liste pour choisir la quantité d'argent gagné
    ...

    Répéter les calculs des deux côtés, coté client c'est pour ne pas attendre le serveur, coté serveur c'est pour vérifié la triche, et entre les 2 c'est pour minimisé l’influence des latences, et minimisé la bande passant (très utile pour l'hébergé sur une connexion adsl).
    Comme tu veux le voir ici, le code est déjà séparé:
    https://github.com/alphaonex86/Pokecraft
    Code commun aux 2, code spécifique au server/client, et datapack.
    J'ai aussi dans l'idée de le faire en bibliothèque dynamique, Qt me permet de le faire simplement, et en classes. Par contre vu que le format change en Qt4 et Qt5, j'attends la nouvelle version.

    Après en public que veux bien, mais ça fait plein de cast, avec des écritures à ralonge, et un code pas claire.

    Pour résumer, MoveOnTheMap est une classe utilisé par les bots, et par le client normaux, je l'ai mit en générale car pas tellement spécifique à l'un ou à l'autre. Elle gére:
    - Groupage des pas dans la même direction (donc mémoire du pas précédent + nombre de pas dans cette direction faite)
    - Vérification de la possibilité d'aller dans une direction (pour que les bot et les joueurs n'essaye pas de passer au travers des mure, donc besoin de la map, x, y du joueurs)
    - Pas dans une direction (soit juste changement des coordonnées, soit carrément changement de map, par sorti d'un des bords) -> je viens de noté que j'ai oublié de faire la gestion des téléporteurs

    Je pense prendre la solution de la template, c'est comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    template <typename TMap = Map>
    class MoveOnTheMap {
       TMap * map_;
    et:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    template <typename TMap = Map_Server>
    class FakeBot {
       TMap * map_;
    C'est le seul moyen de resté propre, si non soit je cast comme un porc, soit je met tout en public et je cast et ça me fait des lignes de code à rallonge.

  16. #16
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    Citation Envoyé par alpha_one_x86 Voir le message
    Comme dit plus haut, les noms sont surment mal choisi.
    En gros newDirection c'est pour dire que mon perso, fait un pas à gauche, un autre à droite, et pour grouper les pas similaires.
    Quand le pas courant est différent alors je flush les pas similaire précédent. Avec une héritage je peu juste appeler une fonction virtuel pur, pour passer à FakeBot l'info et qu'il l'envoie sur sont socket.
    Erreur de conception?
    Là, je comprends mal... ?
    En fait, je te conseilles surtout de séparer clairement le jeu en 3 parties : la partie client, la partie serveur, et la partie calcul.

    Car si je fait un fonction, entrée map*, x, y, direction, en sortie, map * (que je doit re-caster), x, y.
    Pourquoi devrais-tu re-caster la map ?
    Tu utilises des fonctions qui ne sont pas communes aux Map_server et Map_client dans MoveOnTheMap ?

    Pour 2 raison non pour ce découpage:
    Les FakeBots servent aussi aux benchmark, c'est 270 000 messages envoyé contre 16 000 en tcp. Donc en tcp, je vais être ralenti par cette couche tcp, et les résultats, ou tentative de charge de mon serveur vont foirer. Et ce sont des bots sur le serveur, donc c'est un faux client, qui fait pour l'instant des pas aléatoire, mais qui est dans le code du serveur).
    Donc, en fait, tes tentatives de charge du serveur, et tes benchmarks, sont truqués, non ?
    Parce que, généralement, c'est la connexion internet qui sera le facteur limitant, pour tout jeu amateur.
    Et un message TCP envoyé en local doit équivaloir à du 15Gbps, quoi.
    Donc tout test de charge qui ne prend pas en compte le surcoût de TCP sera totalement irréaliste.
    C'est donc une raison de plus pour la découpe.

    Ensuite, il reste 50% du code qui est exactement le même, et que je vais devoir faire des 2 cotés. En gros, dans un modèle MVC, le serveur à le modèle et le contrôleur. Et le client à en plus la vue.
    Exemple combat Client/server:
    - Puise dans la random liste pour choisir le monstre/Puise dans la random liste pour choisir le monstre
    - choix d'une action/rien
    - application de l'action attaque sur les données du monstre choisi en 1/application de l'action attaque sur les données du monstre choisi en 1
    - Fin du combat, puise dans la random liste pour choisir la quantité d'argent gagné/Fin du combat, puise dans la random liste pour choisir la quantité d'argent gagné
    ...
    Et donc tu devrais utiliser une biblio qui regroupe le M et le C ; pour ensuite éviter tout souci.

    D'ailleurs, "Puise dans la random liste pour choisir le monstre/Puise dans la random liste pour choisir le monstre" => fail ? Si tu tires au hasard sur le serveur et sur le client, il y a bien peu de chance que tu tombes sur le même monstre... Ce qui amènera probablement à un fail.
    Et si tu tentes de synchroniser une liste des prochains monstres sur lesquels on va tomber, tu vas avoir un big souci : si deux personnes lancent un combat en même temps ? L'une des deux va se voir refuser le combat par le serveur, parce qu'il aura reçu la requête de l'autre en même temps, et ça fera tout planter.
    Et, si jamais tu re-pioches un autre monstre dans ces cas, tu peux être certain d'avoir d'énormes latences. Parce que les race conditions arrivent beaucoup plus souvent qu'on ne le pense, et que mieux vaut centraliser tout traitement indéterministe.
    Et puis, 1 octet à transmettre, c'est trop ? (Ca fait déjà 2³² monstres possibles, hein.)

    Idem pour le fait de puiser l'argent gagné. De toute façon, le coût de la synchronisation des listes dépassera très très très probablement le coût de le traitement centralisé par le serveur.
    Sauf quand il n'y a qu'un seul joueur, bien sûr.

    Répéter les calculs des deux côtés, coté client c'est pour ne pas attendre le serveur, coté serveur c'est pour vérifié la triche, et entre les 2 c'est pour minimisé l’influence des latences, et minimisé la bande passant (très utile pour l'hébergé sur une connexion adsl).
    Non. cf. au-dessus.

    Comme tu veux le voir ici, le code est déjà séparé:
    https://github.com/alphaonex86/Pokecraft
    Code commun aux 2, code spécifique au server/client, et datapack.
    J'ai aussi dans l'idée de le faire en bibliothèque dynamique, Qt me permet de le faire simplement, et en classes. Par contre vu que le format change en Qt4 et Qt5, j'attends la nouvelle version.[/quote]
    Alors, mieux vaudrait compiler en 3 éléments séparés : datapack en une lib, client et serveur en des exécutables.
    Après, ça simplifiera énormément la gestion du single-player / multiplayer.

    Après en public que veux bien, mais ça fait plein de cast, avec des écritures à ralonge, et un code pas claire.
    => ? (Citer la partie de mon message précédent auquel tu réponds me permettrait de comprendre... Et [quo te]...[/quo te] sert justement à ça -- sans les espaces.)

    Pour résumer, MoveOnTheMap est une classe utilisé par les bots, et par le client normaux, je l'ai mit en générale car pas tellement spécifique à l'un ou à l'autre. Elle gére:
    - Groupage des pas dans la même direction (donc mémoire du pas précédent + nombre de pas dans cette direction faite)
    - Vérification de la possibilité d'aller dans une direction (pour que les bot et les joueurs n'essaye pas de passer au travers des mure, donc besoin de la map, x, y du joueurs)
    - Pas dans une direction (soit juste changement des coordonnées, soit carrément changement de map, par sorti d'un des bords) -> je viens de noté que j'ai oublié de faire la gestion des téléporteurs
    Il y a encore moyen de faire mieux.
    Mais d'abord... Pourquoi est-ce que tu conserves un pointeur vers la map dans le MoveOnTheMap ?

    Je pense prendre la solution de la template, c'est comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    template <typename TMap = Map>
    class MoveOnTheMap {
       TMap * map_;
    et:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    template <typename TMap = Map_Server>
    class FakeBot {
       TMap * map_;
    C'est le seul moyen de resté propre, si non soit je cast comme un porc, soit je met tout en public et je cast et ça me fait des lignes de code à rallonge.
    Soit tu cherches un bon design, comme ce que j'essaie de t'amener à faire. Peut-être devrais-tu lire le blog d'Emmanuel Deloget, pour avoir une meilleure idée par toi-même ? Tu n'en sortiras pas pareil. (C'est avec son blog que j'ai commencé à comprendre la programmation. Après quelques années de C++ qui me semblent désormais vaines.)
    D'ailleurs, pourquoi est-ce que tu mets FakeBot template ? o_O

  17. #17
    Membre régulier
    Avatar de alpha_one_x86
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2006
    Messages
    411
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2006
    Messages : 411
    Points : 113
    Points
    113
    Par défaut
    Citation Envoyé par Ekleog Voir le message
    Là, je comprends mal... ?
    En fait, je te conseilles surtout de séparer clairement le jeu en 3 parties : la partie client, la partie serveur, et la partie calcul.
    Déjà fait.

    Citation Envoyé par Ekleog Voir le message
    Pourquoi devrais-tu re-caster la map ?
    Tu utilises des fonctions qui ne sont pas communes aux Map_server et Map_client dans MoveOnTheMap ?
    C'est vrai que il y a l'auto cast, donc même pas besoin. Mais reste que ça reste lourd, 4 paramètres en entrée, 3 en sortie...


    Citation Envoyé par Ekleog Voir le message
    Donc, en fait, tes tentatives de charge du serveur, et tes benchmarks, sont truqués, non ?
    Parce que, généralement, c'est la connexion internet qui sera le facteur limitant, pour tout jeu amateur.
    Et un message TCP envoyé en local doit équivaloir à du 15Gbps, quoi.
    Donc tout test de charge qui ne prend pas en compte le surcoût de TCP sera totalement irréaliste.
    C'est donc une raison de plus pour la découpe.
    Pour avoir administrer un certain nombre de serveurs, dons certain dans le mmorpg.
    1) Sur un serveur en 100MBps (les plus pourri dédié dispo actuellement),
    surtout dans le low-cost, le facteur limitant est TOUJOURS les performance.
    Je ne connait personne qui est limité par ça bande passante.
    Je pense à l2jfree, prestashop, wordpress, ... quand tu touche les limites de ta bande passante, c'est que tu as les moyens de passé sur un plus gros serveur. Surtout qu'ici j'ai soigné l'utilisation de la bande passante, et mit des compressions içi et la.
    2) En 2ème c'est le cout, en amateur, 50€/mois (même 15€/mois), c'est énorme. Seul 1€/mois ou l'hébergé chez soit, semble quelque chose de raisonnable pour commencer.
    3) Bizarrement, les testes que j'avais fait avec Qt, montrais la mauvaise exploitation des socket TCP, et je ne dépassais pas 16 000 packet tcp sur de petit volume, soit <100Mo/s. Surement une limitation de la lib Qt.
    4) Le protocole n'est pas sensible aux latences, et voir point 1. Je surveille donc juste de prêt la bande passante. Je monitor les temps de réponse via d'autre moyen.

    Citation Envoyé par Ekleog Voir le message
    Et donc tu devrais utiliser une biblio qui regroupe le M et le C ; pour ensuite éviter tout souci.
    +1

    Citation Envoyé par Ekleog Voir le message
    D'ailleurs, "Puise dans la random liste pour choisir le monstre/Puise dans la random liste pour choisir le monstre" => fail ? Si tu tires au hasard sur le serveur et sur le client, il y a bien peu de chance que tu tombes sur le même monstre... Ce qui amènera probablement à un fail.
    Et si tu tentes de synchroniser une liste des prochains monstres sur lesquels on va tomber, tu vas avoir un big souci : si deux personnes lancent un combat en même temps ? L'une des deux va se voir refuser le combat par le serveur, parce qu'il aura reçu la requête de l'autre en même temps, et ça fera tout planter.
    Et, si jamais tu re-pioches un autre monstre dans ces cas, tu peux être certain d'avoir d'énormes latences. Parce que les race conditions arrivent beaucoup plus souvent qu'on ne le pense, et que mieux vaut centraliser tout traitement indéterministe.[/QUOTE]
    C'est une liste de nombre aléatoire synchronisé entre le client et le serveur. En gros, le serveur envoie 1024 8bits de nombre aléatoire au client, qu'il retiens de son coté. Donc client et serveur puise dans leur liste ayant le même contenu.
    Cette liste est locale à chaque utilisateur, et donc est exclusif pour les évènements uniquement pour l'utilisateur.

    Citation Envoyé par Ekleog Voir le message
    Et puis, 1 octet à transmettre, c'est trop ? (Ca fait déjà 2³² monstres possibles, hein.)
    Ca fait 256, pas 4 millard.... comme 4 octect, 32Bits.
    Mais si tu fait ça, le combat deviens synchrone sur l'envoie/réception de cette info. Et donc les latences internet influe. (Si tu as une connexion de merde, comme ici, le combat ne s'affiche pas avant quelque secondes, idem pour les internet mobile qui capte mal).
    En plus tu te prendre la surcharge de l'entête ip/tcp, et le packet doit partir le plus vite possible (donc pas de regroupement avec un autre, et tu flush l'interface).

    Les éléments qui font intervenir plusieurs joueurs doivent avoir une synchronisation. Donc la, c'est mieux de gérer directement (qui à ramassé l'objet sur le sol en 1er... qui été visible sur les 2 client).

    Citation Envoyé par Ekleog Voir le message
    Il y a encore moyen de faire mieux.
    Mais d'abord... Pourquoi est-ce que tu conserves un pointeur vers la map dans le MoveOnTheMap ?
    Pour le cas de mon héritage, pour conservé la map courrant, et comme dit + haut, pour ne pas passer 4 paramètres, et en recevoir 3 (écriture assez lourde)

    Citation Envoyé par Ekleog Voir le message
    D'ailleurs, pourquoi est-ce que tu mets FakeBot template ? o_O
    Car je croyais que ça s'utilisais comme ça. Je suis une merde en template...

    Je lit http://blog.emmanueldeloget.com/, instructif... je viens de commencer. Après je ne garantie pas d’être d'accords sur tout.

  18. #18
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    Citation Envoyé par alpha_one_x86 Voir le message
    C'est vrai que il y a l'auto cast, donc même pas besoin. Mais reste que ça reste lourd, 4 paramètres en entrée, 3 en sortie...
    N'empêche que, àmha, FakeBot n'a aucune raison d'hériter de MoveOnTheMap.
    A la limite, tu pourrais faire un héritage privé, mais même là ça reste limite, la justification, quoi... :/


    Pour avoir administrer un certain nombre de serveurs, dons certain dans le mmorpg.
    1) Sur un serveur en 100MBps (les plus pourri dédié dispo actuellement),
    surtout dans le low-cost, le facteur limitant est TOUJOURS les performance.
    Je ne connait personne qui est limité par ça bande passante.
    Je pense à l2jfree, prestashop, wordpress, ... quand tu touche les limites de ta bande passante, c'est que tu as les moyens de passé sur un plus gros serveur. Surtout qu'ici j'ai soigné l'utilisation de la bande passante, et mit des compressions içi et la.
    Si tu as soigné l'utilisation de la bande passante, pourquoi l'utilisation d'un serveur TCP local te ferait-il peut pour tes tests ? Après tout, un test de charge qui ne prend pas en compte le décodage des paquets TCP est inutile. Si tu voulais un test de charge réaliste, il faudrait même coller un switch éthernet relié à ton serveur de tests par une liaison éthernet 100Mbps (bien inférieur à la boucle locale), puis relier 2/3 ordinateurs à ce switch et lancer N clients dessus.
    Parce qu'un jeu en singleplayer arrivera très peu probablement à atteindre les tests de charge, et qu'un jeu en multiplayer à plus de 100Mbps pour le serveur n'arrivera probablement pas avant longtemps.
    Bref, tu truques tes tests de charge (le routage des paquets TCP et tout étant quand même un facteur à prendre en compte), et ça va te retomber dessus à la fin... enfin, je pense.

    2) En 2ème c'est le cout, en amateur, 50€/mois (même 15€/mois), c'est énorme. Seul 1€/mois ou l'hébergé chez soit, semble quelque chose de raisonnable pour commencer.
    Raison de plus pour tester sur une boucle locale. Et puis, hébergé chez soi, ça impliquerait même de trouver un cable éthernet de 1Mbps, et là tu auras un test réaliste, avec les embouteillages de paquets, les délais de traitement, et tous les calculs gérés par l'OS pour se débrouiller avec une pile TCP (ou UDP) bourrée de réémissions.

    Et, hébergé en local, il me semblerait étonnant que le facteur limitant soit les performances du serveur...

    3) Bizarrement, les testes que j'avais fait avec Qt, montrais la mauvaise exploitation des socket TCP, et je ne dépassais pas 16 000 packet tcp sur de petit volume, soit <100Mo/s. Surement une limitation de la lib Qt.
    16000 paquets par quoi ?
    Et puis, boost.asio, quoi.

    4) Le protocole n'est pas sensible aux latences, et voir point 1. Je surveille donc juste de prêt la bande passante. Je monitor les temps de réponse via d'autre moyen.
    Je voudrais bien avoir une description du protocole. Parce qu'une insensibilité totale aux latences... Voilà, quoi.

    C'est une liste de nombre aléatoire synchronisé entre le client et le serveur. En gros, le serveur envoie 1024 8bits de nombre aléatoire au client, qu'il retiens de son coté. Donc client et serveur puise dans leur liste ayant le même contenu.
    Cette liste est locale à chaque utilisateur, et donc est exclusif pour les évènements uniquement pour l'utilisateur.
    OK... Donc deux joueurs ne font jamais de combat ensemble ? (désolé, je ne connais pas le jeu)
    Parce que si non, ce n'est pas un mmo.
    Si oui, alors la gestion des multi-joueurs va être complexe : il va falloir envoyer la liste des combats joignables à tous les autres joueurs. Et là, bonjour les latences !

    Ca fait 256, pas 4 millard.... comme 4 octect, 32Bits.
    Mais si tu fait ça, le combat deviens synchrone sur l'envoie/réception de cette info. Et donc les latences internet influe. (Si tu as une connexion de merde, comme ici, le combat ne s'affiche pas avant quelque secondes, idem pour les internet mobile qui capte mal).
    En plus tu te prendre la surcharge de l'entête ip/tcp, et le packet doit partir le plus vite possible (donc pas de regroupement avec un autre, et tu flush l'interface).
    (Mea culpa, j'étais légèrement fatigué... M'enfin, un paquet TCP étant bourré de padding, 4 octets font exactement comme 1 octet pour la BP, alors...)
    Du coup... As-tu bien pensé à la quantité de mémoire qui va être impliquée pour le stockage de *toutes* ces listes aléatoires pour *tous* ces clients ? Avec 1ko rien que pour la liste de monstres d'un joueur (et les monstres ne dépendent pas de la zone dans laquelle on se trouve), plus 1ko pour celle de drop, plus 1ko pour celle de chance, plus 1ko pour celle de chaque attaque,...
    On va dire que ça arrive à facilement 10ko par joueur.
    Multiplié par le nombre de joueurs. Disons... 60000 (nombre proche de celui affirmé par le site, iirc).
    Ca fait 60000*10ko = 600000ko = 600Mo. (Omettons les détails de ko/kio, OK ?)
    600Mo toujours en mémoire. Ca va pourrir le cache, ça.
    Et là, les performances vont *vraiment* en souffrir.

    Et encore, je ne parle pas de la génération de 10ko de données aléatoires à chaque connexion d'un joueur...

    Bonne idée de protocole, mais qui mérite encore un peu de réflexion, je crois.

    Pour le cas de mon héritage, pour conservé la map courrant, et comme dit + haut, pour ne pas passer 4 paramètres, et en recevoir 3 (écriture assez lourde)
    Ah, d'accord, Map n'est pas la map complète de jeu mais une sous-map sur laquelle on se trouve, c'est ça ?

    Et puis, des fois, mieux vaut une écriture un peu plus lourde qu'un truc inmaintenable.


    Car je croyais que ça s'utilisais comme ça. Je suis une merde en template...
    Si tu veux vraiment utiliser cette solution, alors :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class FakeBot : private MoveOnTheMap<Map_server> { // Parce que FakeBot n'existe que sur le serveur
       // ...
    };
    Mais, alors, utilises l'héritage privé !
    Hériter d'une classe template, pour autant que je sache, fait souvent (pas toujours) partie des détails d'implémentation.
    Ici, ce me semble être le cas.
    Donc il faudrait faire de l'héritage privé, puis faire exporter l'interface de MoveOnTheMap que l'on souhaite conserver (sous une forme dérivée, en général) par FakeBot.

    Je lit http://blog.emmanueldeloget.com/, instructif... je viens de commencer. Après je ne garantie pas d’être d'accords sur tout.
    lis*
    Sinon, je ne suis pas non plus d'accord sur tout. Sinon, ça n'aurait aucun intérêt.
    Mais, en gros, de mémoire j'étais d'accord sur la grande majorité de ce qu'il dit.
    N'hésites pas à laisser un commentaire sur son blog, si jamais tu n'es pas d'accord !

  19. #19
    Membre régulier
    Avatar de alpha_one_x86
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2006
    Messages
    411
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2006
    Messages : 411
    Points : 113
    Points
    113
    Par défaut
    Citation Envoyé par Ekleog Voir le message
    Si tu as soigné l'utilisation de la bande passante, pourquoi l'utilisation d'un serveur TCP local te ferait-il peut pour tes tests ? Après tout, un test de charge qui ne prend pas en compte le décodage des paquets TCP est inutile. Si tu voulais un test de charge réaliste, il faudrait même coller un switch éthernet relié à ton serveur de tests par une liaison éthernet 100Mbps (bien inférieur à la boucle locale), puis relier 2/3 ordinateurs à ce switch et lancer N clients dessus.
    Parce qu'un jeu en singleplayer arrivera très peu probablement à atteindre les tests de charge, et qu'un jeu en multiplayer à plus de 100Mbps pour le serveur n'arrivera probablement pas avant longtemps.
    Bref, tu truques tes tests de charge (le routage des paquets TCP et tout étant quand même un facteur à prendre en compte), et ça va te retomber dessus à la fin... enfin, je pense.
    C'est prévu, mais le gros point noir, c'est la complexité carré de la répartition des mouvements des joueurs sur les autres joueurs. Le faite de quitter la couche tcp, me permet de ne pas dépendre des performances de l'OS. Pour bien faire les testes, je doit induire une latence virtuelle comme pour les vrais client/serveur (liaison adsl des clients). Utilisé un switch, avec plusieurs client, codé une application de benchmark tcp (qui benchmark en parallèle -> comme pour les benchmark http). Après ce pose le problème du login... C'est prévu, mais pas encore fait, je suis qu'au début de ma conception. (J'ai personne pour faire la partie 2D du client que je ne sais pas faire).



    Citation Envoyé par Ekleog Voir le message
    Raison de plus pour tester sur une boucle locale. Et puis, hébergé chez soi, ça impliquerait même de trouver un cable éthernet de 1Mbps, et là tu auras un test réaliste, avec les embouteillages de paquets, les délais de traitement, et tous les calculs gérés par l'OS pour se débrouiller avec une pile TCP (ou UDP) bourrée de réémissions.

    Et, hébergé en local, il me semblerait étonnant que le facteur limitant soit les performances du serveur...
    Linux permet de faire une limitation de bande passante, c'est 10Mbps le minimum... bref, une implémentation logiciel de cette limitation sera plus facile et moins couteux. (Coté linux ou serveur). Il reste que je reste largement limité par le cpu (cpu à 100% avant d'utilisé 10Ko/s).
    Après il y as le cryptage, le compression, ... une fois le benchmark tcp fait, le mieux serai que j'utilise mon dédié qui est en prod pour faire des benchmarks, ça serai réaliste, sauf qu'il me faudrai une armé de client sur différente co adsl, donc autant benchmark sur un serveur en prod...

    Citation Envoyé par Ekleog Voir le message
    16000 paquets par quoi ?
    Et puis, boost.asio, quoi.
    16000 packet de 1o à 1Mo envoyé par tcp avec Qt.


    Citation Envoyé par Ekleog Voir le message
    Je voudrais bien avoir une description du protocole. Parce qu'une insensibilité totale aux latences... Voilà, quoi.
    http://pokecraft.first-world.info/wiki/General_protocol -> idem ébauche, ont peu même pas considéré que c'est une base.
    Mais bon, ici c'est le jeu qui s'y prette, 99% des données sont spécifique à l'utilisateur, en gros les communication inter-joueurs sont le chat, les déplacements.

    Citation Envoyé par Ekleog Voir le message
    OK... Donc deux joueurs ne font jamais de combat ensemble ? (désolé, je ne connais pas le jeu)
    Parce que si non, ce n'est pas un mmo.
    Si oui, alors la gestion des multi-joueurs va être complexe : il va falloir envoyer la liste des combats joignables à tous les autres joueurs. Et là, bonjour les latences !
    Si, il vont faire des combats ensembles. Les modes de combat (les mettre dans un lieu spécifique, surtout pour réduire les glitch potentiel), fait que une requête de combat est envoyé, si accepté de l'autre coté, alors ont transmet les info entres ces 2 joueurs.


    Citation Envoyé par Ekleog Voir le message
    (Mea culpa, j'étais légèrement fatigué... M'enfin, un paquet TCP étant bourré de padding, 4 octets font exactement comme 1 octet pour la BP, alors...)
    Du coup... As-tu bien pensé à la quantité de mémoire qui va être impliquée pour le stockage de *toutes* ces listes aléatoires pour *tous* ces clients ? Avec 1ko rien que pour la liste de monstres d'un joueur (et les monstres ne dépendent pas de la zone dans laquelle on se trouve), plus 1ko pour celle de drop, plus 1ko pour celle de chance, plus 1ko pour celle de chaque attaque,...
    On va dire que ça arrive à facilement 10ko par joueur.
    Multiplié par le nombre de joueurs. Disons... 60000 (nombre proche de celui affirmé par le site, iirc).
    Ca fait 60000*10ko = 600000ko = 600Mo. (Omettons les détails de ko/kio, OK ?)
    600Mo toujours en mémoire. Ca va pourrir le cache, ça.
    Et là, les performances vont *vraiment* en souffrir.
    1Ko pour tout, avec 16Bits de joueurs supportés, ça fait 655350o, 640Ko... ça reste raisonnable.

    Citation Envoyé par Ekleog Voir le message
    Et encore, je ne parle pas de la génération de 10ko de données aléatoires à chaque connexion d'un joueur...
    C'est pas ce qui est gênant, c'est asynchrone, et avec le nouveau moteur de génération de nombre aléatoire d'intel, c'est instantané. La qualité des nombres aléatoires peuvent être merdique...


    Citation Envoyé par Ekleog Voir le message
    Ah, d'accord, Map n'est pas la map complète de jeu mais une sous-map sur laquelle on se trouve, c'est ça ?
    Voila, divisé en map du style:
    http://images.wikia.com/pwo/images/f...ret_Area_1.JPG

    Citation Envoyé par Ekleog Voir le message
    Et puis, des fois, mieux vaut une écriture un peu plus lourde qu'un truc inmaintenable.
    Cette argument m'as convaincu.

    Citation Envoyé par Ekleog Voir le message
    Si tu veux vraiment utiliser cette solution, alors :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class FakeBot : private MoveOnTheMap<Map_server> { // Parce que FakeBot n'existe que sur le serveur
       // ...
    };
    Mais, alors, utilises l'héritage privé !
    Hériter d'une classe template, pour autant que je sache, fait souvent (pas toujours) partie des détails d'implémentation.
    Ici, ce me semble être le cas.
    Donc il faudrait faire de l'héritage privé, puis faire exporter l'interface de MoveOnTheMap que l'on souhaite conserver (sous une forme dérivée, en général) par FakeBot.
    Au final l'utilisation d'une autre classe deviens + simple.


    lis*
    Citation Envoyé par Ekleog Voir le message
    Sinon, je ne suis pas non plus d'accord sur tout. Sinon, ça n'aurait aucun intérêt.
    Mais, en gros, de mémoire j'étais d'accord sur la grande majorité de ce qu'il dit.
    N'hésites pas à laisser un commentaire sur son blog, si jamais tu n'es pas d'accord !
    Pour l'instant assez d'accords, et j'ai encore appris plein de chose.


    Pour clarifié des choses sur le projet:
    - C'est mon 2éme projet majeur. Le 1er (ultracopier), impliqué fortement les latences, les histoires de synchronisation, multi-thread, blockage, localité des données, gestion de cache et buffer, ...
    - Ce qui est nouveau: multiple client, couche tcp, latence internet et gestion de bande passante, db ... par contre, étant donné que je suis admin systéme, que je touche au noyau, que j'ai fait une paire de site haute performance sur le web francais, ça compense.
    - Le projet viens de commencer doucement. J'ai pas fait les doc, l'organisation/classe ne sont pas définitive, j'ai qu'une partie des outils pour le dev du jeu, certaine licence ne sont pas choisi. Pour l'instant c'est même pas un jeu (ont peu ce déplacer, faire les commandes de base, ...), pas de bench en tcp, ... je suis loin d'en être encore la. Cerise sur le gateau, je maîtrise pas Qt 2D et je sais pas le faire, donc j'ai 1000€ de budget pour embaucher un gas.

    Donc je le reconnais volontiers, j'ai du mal à voir certaines choses, j'ai peu d'expérience en dev de mmorpg. Mais je ne part pas de 0, je ne réinvente pas la roue, j'ai l'éditeur de map, je peu sans problème faire serveur + protocole + client (sans le 2D) + graphisme + packaging... mais le projet à un graphiste, et les ressources qui vont bien.
    Je pense faire un peu de doc pour compléter le wiki:
    http://pokecraft.first-world.info/
    Dans quelques heures. Histoire d’être plus claire.

  20. #20
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    Citation Envoyé par alpha_one_x86 Voir le message
    C'est prévu, mais le gros point noir, c'est la complexité carré de la répartition des mouvements des joueurs sur les autres joueurs.
    Donc, en fait, tu envoies tous les mouvements de tous les joueurs à tous les autres joueurs ? Tous tes joueurs peuvent vraiment se voir ?

    Le faite de quitter la couche tcp, me permet de ne pas dépendre des performances de l'OS. Pour bien faire les testes, je doit induire une latence virtuelle comme pour les vrais client/serveur (liaison adsl des clients). Utilisé un switch, avec plusieurs client, codé une application de benchmark tcp (qui benchmark en parallèle -> comme pour les benchmark http). Après ce pose le problème du login... C'est prévu, mais pas encore fait, je suis qu'au début de ma conception. (J'ai personne pour faire la partie 2D du client que je ne sais pas faire).
    Donc tu es au courant que tes benchmarks sont optimistes. Donc tout va bien. Même si, en général, on considère qu'il vaut mieux être pessimiste, mais bon...


    Linux permet de faire une limitation de bande passante, c'est 10Mbps le minimum... bref, une implémentation logiciel de cette limitation sera plus facile et moins couteux. (Coté linux ou serveur). Il reste que je reste largement limité par le cpu (cpu à 100% avant d'utilisé 10Ko/s).
    Euh... ?
    Là, j'ai du mal à comprendre... Tu fais tant de calculs ?
    Es-tu sûr qu'il n'y a pas un problème quelque part ? (N'as-tu pas un nice de 20, ou truc du genre ?)
    Sinon, une limitation logicielle va encore introduire un biais dans le bench, parce qu'il y aura encore des calculs effectués pour vérifier si la limitation n'est pas dépassée. La seule bonne solution de test grandeur nature reste un test grandeur nature, donc bon, peut-être que j'en demande trop. Mais bon, la meilleure solution pour les tests de charge seraient àmha de lancer le serveur chez soi et d'aller chez quelqu'un d'autre pour lancer les bots (idéal : lancer les bots depuis plusieurs personnes). M'enfin, ce niveau de précision n'est probablement pas nécessaire, hein.

    Après il y as le cryptage, le compression, ... une fois le benchmark tcp fait, le mieux serai que j'utilise mon dédié qui est en prod pour faire des benchmarks, ça serai réaliste, sauf qu'il me faudrai une armé de client sur différente co adsl, donc autant benchmark sur un serveur en prod...
    chiffrement*
    Sinon... Pourquoi chiffrer la connexion ? Et puis, vu que le cpu semble le facteur limitant (et de loin), es-tu sûr qu'il est une bonne idée de compresser ?

    16000 packet de 1o à 1Mo envoyé par tcp avec Qt.
    16000 paquets avant de crasher ? 16000 paquets par seconde maximum ? Autre ?

    http://pokecraft.first-world.info/wiki/General_protocol -> idem ébauche, ont peu même pas considéré que c'est une base.
    Mais bon, ici c'est le jeu qui s'y prette, 99% des données sont spécifique à l'utilisateur, en gros les communication inter-joueurs sont le chat, les déplacements.
    Bon... Je ne vais pas dire, mais certaines choses me font peur :
    The used encoding is the unicode (utf16), where each char is encoded into 16Bits in big endian.
    -> Tout le protocole est encodé en UTF-16 ? Ne faudrait-il pas plutôt appliquer ça aux messages entre joueurs seulement ?
    Sub code type (16Bits, optional)
    -> 16 bits pour le sous-code ? Tu as un main code qui a plus de 256 sous-codes ?
    [packet size]
    -> Utiliser un octet pour stocker la valeur d'un bit (seulement deux valeurs possibles), c'est du gâchis, hein.
    [tout]
    -> Que se passe-t-il si la vérification serveur ne colle pas avec les calculs du client ? (i.e. overclocking trop poussé et erreur dans les calculs du client)
    -> L'anglais nécessiterait bien une vérification.

    1Ko pour tout, avec 16Bits de joueurs supportés, ça fait 655350o, 640Ko... ça reste raisonnable.
    D'accord, j'avais compris qu'il y avait une liste de monstres, une de drops, une de pas, etc.

    C'est pas ce qui est gênant, c'est asynchrone, et avec le nouveau moteur de génération de nombre aléatoire d'intel, c'est instantané. La qualité des nombres aléatoires peuvent être merdique...
    Pas plus qu'avant, pour autant que je sache.
    Et puis, selon le manuel intel, RDRAND génère un nombre cryptographiquement sécurisé, donc "plus aléatoire" que rand().
    Il est donc forcément plus long.

    [...]
    Cerise sur le gateau, je maîtrise pas Qt 2D et je sais pas le faire
    [...]
    Hum... Pour autant que je sache, Qt 2D est assez peu apprécié.
    SFML pourrait probablement être un meilleur choix.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Gros problème Template framework Gantry
    Par redaben dans le forum Bibliothèques et frameworks
    Réponses: 0
    Dernier message: 03/06/2014, 00h31
  2. Fonction Template dans une classe & Héritage
    Par Drannor dans le forum Langage
    Réponses: 1
    Dernier message: 15/09/2011, 17h20
  3. Gros problème de classe inexistante
    Par mrrenard dans le forum C#
    Réponses: 6
    Dernier message: 01/02/2008, 15h07
  4. Héritage classe template->classe template
    Par zabibof dans le forum Langage
    Réponses: 5
    Dernier message: 11/08/2007, 11h05
  5. Foncteur, classes templates et héritage
    Par Floréal dans le forum C++
    Réponses: 8
    Dernier message: 17/06/2007, 21h56

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo