Affichage des articles dont le libellé est mmorpg. Afficher tous les articles
Affichage des articles dont le libellé est mmorpg. Afficher tous les articles

samedi 22 janvier 2011

Des nouvelles d'Infinity

Comme mentionné dans un post précédent, je surveille de près le projet Infinity, l'ambitieux projet de MMORPG spatial amateur (ou plutôt semi-pro, comme on le verra dans la suite du post). Hier, son concepteur a publié sa rétrospective pour 2010, et a notamment annoncé un changement majeur sur la conduite du projet: maintenant secondé par un développeur pro, il a monté une entreprise, I-novae studios, et se concentre sur la vente du moteur de jeu.

Ceci a bien entendu causé quelques changements dans ses priorités, et il semble que beaucoup de temps ait été passé sur les bug fix, le port vers d'autres architectures, l'intégration à .NET, et bien évidemment l'effort marketing. Le jeu Infinity en lui-même n'est pas abandonné, mais mis de côté en attendant que la vente du moteur permette au studio de recruter une véritable équipe de développement.

La communauté est très divisée par ces nouvelles. Tout en admettant que la vente du moteur est la chose à faire pour lever des fonds, l'inévitable recul de la date de publication du jeu Infinity est difficilement vécue par ceux qui espéraient que le silence de ces derniers mois débouche sur une béta jouable.

Tous les fans d'Infinity (et j'en suis!) devront donc continuer de prendre leur mal en patience, et d'espérer un rapide succès commercial du moteur. Plus personnellement, j'espère tout de même que nous aurons au moins quelques vidéos à se mettre sous la dent.

mardi 27 juillet 2010

Développer son MMORPG - Threads

6ème partie (enfin! s'écrie mon public en délire), où j'évoque les tentations du multithreading, et laisse entendre qu'il faut mieux les laisser aux grands garçons (et aux grandes filles).

Ceux qui, comme votre serviteur, auront passé trop de temps sur les forums de développement de jeux vidéos (même stack overflow s'y met: regardez!) auront pu découvrir un certain nombre de questions qui peuvent se résumer ainsi: où est-ce que je met mes threads?

Le jeune scarabée s'empresse de lister alors une série de composants, et leur assigne unilatéralement un thread, histoire de dire que. L'on se retrouve avec un thread par zone, un thread pour la physique, un thread pour les communications, un thread pour le commerce, un thread pour le pathfinding, etc. Côté client, on imagine un thread pour le rendu, un thread pour la GUI, un thread pour la physique, un thread pour la musique, un thread pour les communications avec le serveur, und so weiter.

Arrêtez là, malheureux! Écoutez les paroles de celui qui s'est lamentablement planté avant vous sur exactement le même chemin.

Pas de threads. Nope. N'essayez pas, ce n'est même pas la peine. Non seulement ce n'est pas la peine, mais je soutiens qu'un effort non négligeable est nécessaire pour supprimer, ou du moins abstraire, tout ce qui pourrait avoir besoin d'un thread (mettons, le réseau).

La raison est tout simplement qu'il est horriblement compliqué de gérer la synchronisation des threads. Et qu'en plus, les bibliothèques externes sont rarement thread safe, et qu'il faut donc coder nombre de couches d'abstractions pour garantir que l'on ne va pas exploser en vol. Je ne parle même pas des test unitaires et du débuggage.

Du côté serveur, prévoyez également une simple boucle, éventuellement pilotée par les événements réseau. La bibliothèque boost::asio est particulièrement pratique pour ce cas de figure: elle autorise à faire tourner des routines basées sur un chronomètre d'une part, et sur les messages réseau d'autre part, mais toujours dans le même thread.

Enfin, pour ceux qui s'inquiètent de voir les trois quarts de leur puissance de calcul inutilisés, voici ce que vous pouvez en faire:


  • Faire tourner plusieurs instances du serveur

  • Calculer des statistiques à partir de la base de données

  • Compiler du code pour ajouter des fonctionalités!



Quant à ceux qui se laissent tenter par le chant des sirènes, j'attends avec impatience vos retours d'expérience, statistiques à l'appui. Bon courage!

jeudi 13 mai 2010

Les nouveautés dans le monde merveilleux du meuporg

Notons tout d'abord une nouvelle vidéo chez le projet Infinity, présentant les dernières avancées du moteur graphique. L'on observera donc le passage auprès d'une gigantesque station spatiale, la traversée d'un anneau, puis l'arrivée sur la planète, avant de remonter vers l'espace. Comme d'habitude, c'est absolument magnifique, et l'effet d'échelle est très impressionnant. Les sons ont été améliorés, notamment le bruit du vent en vue extérieure lors du passage dans l'atmosphère.

Le seul regret, c'est bien que la vidéo n'en montre pas plus! L'on verra un cockpit (inactif) et des reflets sur la verrière, mais pas plus d'informations en terme de gameplay. À quoi ressemblera donc une session?


La deuxième nouvelle d'importance est la libération de Ryzom! Non seulement le code, mais également toutes les données graphiques, sont maintenant open source. Le jeu en lui-même reste payant, mais rien d'empêche en théorie quiconque de créer son propre serveur.

Bien entendu, la différence pour le quidam moyen reste minime: faire tourner un serveur de MMORPG un peu serieux n'est pas possible sans sérieusement cracher au bassinet. De même, je ne suis pas sûr que beaucoup de gens iront se précipiter sur le code, lequel est probablement sacrément touffu. Néanmoins, c'est un grand pas dans la philosophie du libre, et je souhaite à l'équipe de Ryzom de démontrer qu'il est possible d'être à la fois ouvert et rentable!

dimanche 14 février 2010

Accès concurrent aux listes de propriétés

Je n'allais quand même pas laisser de côté un tel sujet! Récapitulons. Nous avons:



- Une base de données contenant les listes
- Un serveur de listes (unique), qui fournit l'interface vers la base
- Les serveurs, qui communiquent avec le serveur de listes pour récupérer et sauver les listes
- Les clients
- L'interface d'administration Web, qui cause directement à la base de données.

Les clients ne doivent pas modifier les listes directement, mais indiquer leurs actions aux serveurs, qui modifient les listes en fonction. Les serveurs possèdent un cache des listes, et récupèrent auprès du serveur de listes celles dont ils ont besoin. Tentons de dérouler un exemple pour voir comment tout ceci peut fonctionner.

Le Roi Minablos se connecte sur un serveur. Le serveur récupère auprès du serveur de listes l'ensemble des listes dont il aura besoin, c'est à dire la liste du personnage, les listes parentes, les sous-listes référencées dans la liste (par exemple l'inventaire), et ainsi de suite (encore un diagramme, je suis chaud sur Dia, là!).



Les premières fois, l'on aura probablement une bonne partie du monde à télécharger depuis le serveur de liste, mais, le cache aidant, les serveurs seront rapidement à jour. Pour chaque liste, le serveur détermine s'il a besoin d'un accès en lecture seule, ou d'un accès en écriture, en différenciant les listes correspondant à des objets réels, qu'il gère (le Roi Minablos, une bouteille d'huile d'olive), et les objets virtuels, qui correspondent à des attributs et des propriétés générales du monde (ainsi, la liste "huile d'olive", dont dérive la bouteille, contient les propriétés générale de l'huile d'olive, et n'est accessible qu'en lecture seule).

Le Roi Minablos se saisit d'une bouteille d'huile d'olive, et envoie la requête correspondante au serveur. Le serveur modifie la liste du Roi Minablos, en y référençant la bouteille, et sauve les nouvelles listes auprès du serveur de liste.

Plus compliqué: le Roi Minablos fait pousser un olivier. C'est un cas à part, puisque le serveur doit créer une nouvelle liste. Plutôt que de gérer un long appel au serveur de listes, l'idée est pour le serveur de demander au démarrage un grand nombre de listes vides, dont il peut user comme bon lui semble, et d'en demander d'autres, de manière asynchrone, quand sa réserve s'épuise. Dans le cas de notre olivier, le serveur assigne une de ses listes vides, la fait dériver de l'objet olivier, lui met le Roi Minablos comme propriétaire, puis la référence auprès du serveur de liste.

Encore plus compliqué! Le maître de jeu gère une malédiction lancée par un sorcier maléfique, qui a rendu toutes les pommes empoisonnées. Il modifie dans son interface d'administration les propriétés des pommes. L'interface modifie la base, qui réveille le serveur de listes, lequel rafraîchit ses listes, et envoie des notifications à tous les serveurs qui avaient dans leur cache la liste des pommes. La prochaine fois qu'un joueur voudra croquer dedans, ça fera mal aux gencives!

dimanche 31 janvier 2010

Développer son MMORPG - Architecture

5ème partie, où je soutiens que faire "comme les grands" peut avoir des avantages inattendus.

Je ne dirais pas que le plus grand risque du développeur de fond est d'abandonner son projet, mais plutôt de se laisser perdre dans l'exploration de solutions techniques. Ainsi, l'on se retrouve à démarrer bille en tête sur de la 3D, tout jeter pour passer à la 2D quand les difficultés deviennent insurmontables, puis revenir en 3D lorsque l'on vient juste de découvrir un nouveau moteur graphique, puis décider de passer à un moteur de jeu complet, puis se rendre compte de ses faiblesses et revenir à la 2D...

Il est malheureusement difficile d'échapper à ce genre de cycles, et c'est pour cela qu'il faut s'y préparer et développer en gardant en tête que l'on aura sûrement à changer quelques fondamentaux dans un futur proche. Et avoir de bonnes bibliothèques bien génériques est un pas dans la bonne direction.

Il est très peu probable qu'une refonte, même massive, change beaucoup le code de sérialisation, ou l'authentification, ou les logs, ou les utilitaires de bases de données, etc. Mettre ce code dans des bibliothèques bien séparées (et si possible bien testées), c'est l'assurance d'avoir déjà beaucoup de bon code lorsque l'on sonde de nouvelles possibilités.

Mais l'on peut pousser plus loin: l'on peut séparer de grands ensembles du tronc commun, et construire des services entiers qui soient réutilisables partout. Autant les MMORPGs commerciaux distribuent l'authentification, les logs, les données statiques du monde pour des raisons de performance, autant l'amateur peut construire ces mêmes services comme étant des blocs solides dans une architecture instable, lesquels tourneront d'ailleurs gentiment sur la même machine. Et si le succès est au rendez-vous, il sera d'autant plus simple de distribuer.

Un serveur de logs - C'est pas comme si écrire dans un fichier ou une base de données était très dépendant des fonctionnalités du jeu. Une application indépendante qui tourne en tâche de fond, une API, et basta, voilà une belle brique sur laquelle se poser.

Un serveur d'authentification - Encore un service on ne peut plus générique. Un compte, des permissions sur des applications, des permissions plus précises au sein de ces applications... Au fur et à mesure que l'on développe son jeu, l'on peut enrichir le serveur d'authentification avec des fonctionnalités de type rôles, création de compte via un serveur Web, accumulation de statistiques... qui pourront rester stables au fur et à mesure que l'on travaille sur les modules plus proches du gameplay.

Et autres - Peut-être un serveur qui fournit des données statiques? Peut-être des éléments de GUI?

A vrai dire, l'on pourra sans doute changer de langage en cours de route, ces services resteront (pour peu que les communications soient raisonnablement portables).

Bien sûr, il faut éviter de perdre son temps à généraliser du code, mais si un effort mesuré augmente ses chances d'être encore là après deux ou trois itérations, ça vaut le coup.

vendredi 31 juillet 2009

Développer son MMORPG - Les bibliothèques

4éme opus, où l'on parlera de tout ce qu'il ne faut surtout pas coder soi-même. Moins on écrit de code, et plus on peut utiliser celui des autres (à condition que cela soit de la qualité!), et mieux on se porte.

Combien de lignes de code, pour un MMORPG? Des dizaines de milliers? Des centaines de milliers? Il est hors de question de tout écrire soi-même. Si l'on veut avoir la moindre chance de sortir quelque chose un jour, il va falloir lourdement utiliser toutes les bibliothèques possibles, et se servir au maximum de tout ce code écrit par d'autres. Vu que choisir ses bibliothèques est à peine aussi cornélien que de choisir son langage, voici quelques pointeurs (C++! Hein, pointeurs, C++! Bon, heu, je prends mon manteau, hein?).

À travers le spectre
Pourquoi donc ne pas avoir une seule bibliothèque (on parlerait d'ailleurs plutôt de plate-forme, d'ailleurs) qui soit spécialisée dans le MMO? Ça tombe bien, cela existe, mais il faudra alors entrer dans le moule: ces plate-formes proposent en fait la modification et l'extension d'un jeu de base, fonctionnant sur certains principes immuables, et il sera probablement impossible, par exemple, de transformer une plate-forme fantasy en un space opera. d

D'un autre côté, l'on peut s'orienter vers des petites bibliothèques très spécialisées, donnant une grande liberté, mais ajoutant autant au travail d'intégration.

Enfin, au milieu, il y a les bibliothèques de jeux intégrées (comme par exemple Ogre) qui proposent un moteur graphique complet, un support des sons et des entrées utilisateurs, avec en général une bonne portabilité sur de nombreux systèmes d'exploitations.

Pour AdH, l'on a beaucoup tergiversé entre les deux dernières options, pour au final s'orienter vers des bibliothèques spécialisées, les moteurs de jeux complètement intégrés s'étant avérés trop contraignants. Point bonus, il est plus facile de changer une bibliothèque qui ne convient pas que d'avoir à remplacer tout un framework.

Qu'est-ce qu'il ne faut surtout pas faire soi-même

  • Les couches bas-niveau de portabilité - Le genre de code qui vous permet d'afficher une fenêtre graphique et de lire le clavier à la fois sous Linux et sous Windows est généralement ennuyeux au possible à coder, en plus d'être difficile. Et puis, ce n'est pas cela qui va limiter votre imagination. Regardez la bonne vielle SDL, qui a des bindings dans à peu près tous les langages.

  • La bibliothèque graphique - N'écrivez pas votre graphe de scène, malheureux! Ni les routines de chargement de ressources (images, modèles 3D). Du peu que je connais de DirectX, c'est probablement utilisable directement, mais pour OpenGl, trouvez-vous un bon moteur graphique. AdH utilise OpenSceneGraph, mais il en existe des tonnes dans tous les langages.

  • La couche réseau - Il va falloir pouvoir compter dessus, donc inutile de se fatiguer avec les sockets. Utilisez la couche de haut niveau de votre plate-forme, voire une bibliothèque client-serveur complète

  • Le XML - Si vous en mettez, n'écrivez surtout pas votre parseur! Aujourd'hui, il y a pléthore de générateurs de code, ou encore de sérialiseurs qui peuvent par exemple utiliser la réflexion


Pour bien choisir

Car en plus, il y a du choix! Voici les critères, par ordre de priorité, que nous retenons pour faire notre choix:

  • La licence - Si vous ne pouvez pas légalement utiliser la bibliothèque, inutile d'aller plus loin! En fonction de vos choix, vous pourrez utiliser du GPL, du LGPL, du BSD, ou encore sortir votre porte-monnaie pour acheter une licence commerciale.

  • Portable - Puisque nous voulons tourner sur le maximum de plate-formes, il est hors de question de choisir une bibliothèque qui ne tourne que sous un système d'exploitation

  • Mature - Vous n'allez pas attendre l'année prochaine que la fonctionnalité dont vous avez absolument besoin sorte enfin. Un tiens vaut mieux que deux tu l'auras, choisissez donc une bibliothèque qui fait déjà tout ce dont vous avez besoin

  • Simple - Inutile d'essayer d'intégrer une usine à gaz. Les meilleures bibliothèques sont celles qui peuvent se marier très facilement à votre système, sans forcer une architecture. La bibliothèque doit faire exactement ce qu'on lui demande, avec le minimum d'intégration

  • Maintenue - Rien de plus ennuyeux que d'utiliser des vieilles versions de bibliothèques, utilisant des compilateurs antédiluviens, et présentant des bugs qui ne seront jamais résolus. Au contraire, une bibliothèque bien maintenue va évoluer avec les outils du jour, et les petits problèmes rencontrés ont une plus grande chance de se voir résolus un jour. N'hésitez pas à contribuer si vous avez trouvé un défaut!


L'équipe AdH utilise une règle simple et qui marche la plupart du temps: n'utiliser que les bibliothèques se trouvant dans les dépôts Debian testing. Ansi, c'est l'assurance que la bibliothèque est suffisamment mature, qu'elle est maintenue, qu'elle est libre, et qu'elle sera facile à installer! Il ne reste plus qu'à vérifier l'existence d'une version pour Windows, et roule ma poule.

lundi 29 juin 2009

Génération automatique de terrain - Des îles!

J'ai commencé à bidouiller la génération d'îles, et les résultats sont encourageants. J'ai ressorti du placard mon système de collines, en y ajoutant la génération des normales par calcul du gradient de mon exponentielle, ce qui devrait donner de meilleures ombres.

La génération se contente donc d'ajouter plusieurs collines en même temps, et est basée sur un unique nombre qui est la racine de mon générateur aléatoire. L'on donne son entier, et hop, l'archipel surgit des flots!

Un avantage supplémentaire est la séparation de la définition de l'île, comme étant une liste de collines, et de sa représentation graphique, qui est une grille. En faisant jouer la résolution, l'on peut très facilement créer des niveaux de détail différents, et les changer de manière dynamique, permettant d'afficher efficacement les îles lointaines, et de réserver les détails aux îles plus proches.

Voici quelques exemples d'îles générées:


L'île n°5. Les petites bosses correspondent aux toutes petites collines qui ajoutent au relief général.



L'île n°17. Remarquez le petit étang! Certaines collines sont générées inversées, ce qui peut créer des lacs.



L'île n°190. Vue de plus bas, pour le reflet dans la mer.



L'île n°2009. Sacrément biscornue!


Le relief n'est pas la seule chose à générer: je veux pouvoir créer des textures afin d'avoir des couleurs et des aspects différents selon les îles. Ensuite, il faudra ajouter quelques outils au client afin que le maître du jeu puisse créer une île à un endroit donné, juste à partir de son numéro. En essayant plusieurs numéros, il tombera bien sur une île qui lui plaît, laquelle sera alors ajoutée à la carte du monde au niveau du serveur, et envoyée chez tout le monde.

dimanche 21 juin 2009

Développer son MMORPG - Persistance!

3ème opus de la série, où l'on parlera de la partie "persistance" dans "univers persistants". Que ce soit pour définir le monde ou pour récupérer l'état du serveur après une panne ou une séance de maintenance, pouvoir compter sur sa couche de persistance est indispensable.

Base de données relationnelle? Listes de clés-valeurs? XML? Gros fichiers binaires? Une chose est sûre, il faudra bien d'une manière ou d'une autre sauver ses précieuses données. AdH a fait très tôt le choix de la base de données relationnelle (Postgresql, pour être précis, mais cela aurait pu être Mysql, ou encore Oracle si on avait les sous).

Voici quelques avantages des bases de données relationnelles:

  • Les données sont accessibles directement à partir des outils fournis avec le système. Changer une position ou réparer un inventaire, c'est juste quelques lignes de SQL.

  • Les données sont en sécurité! Ces systèmes sont stables, utilisés dans d'innombrables projets à travers le monde. Les données sont centralisées, et les outils sont fournis pour sauvegarder et restaurer la base.

  • Il existe probablement déjà une bibliothèque pour accéder à la base depuis votre langage de programmation préféré.

  • Les données sont accessibles pour d'autres applications. Il est très aisé d'extraire des statistiques pour les afficher sur une page Web, ou encore de générer des rapports sur l'activité des joueurs.

Et quelques inconvénients:
    Ecrire le schéma prend du temps, et écrire la couche relationnelle dans le code en prend également.
  • Les changements de schéma peuvent être lourds: une colonne qui change dans une table, et il faut potentiellement changer ses index, ses procédures stockées, son SQL dans le code, et enfin le code lui-même.

  • Il faut installer une base pour faire tourner le serveur, en s'assurant que les binaires sont bien à la même version que le SQL.

Ces derniers temps, l'on a beaucoup parlé des bases de données de type clé-valeur, souvent utilisées dans le Web. Très dynamiques, elles permettent d'étendre le modèle de données très simplement, et sont d'une extensibilité sans pareille. Rajouter des paramètres à ses objets devient un jeu d'enfant. Par contre, être aussi dynamique a un coût: la base peut vite devenir bordélique, et les clés et les valeurs de plus en plus complexes et difficiles à interpréter. Sauver du XML en place des valeurs peut être une bonne manière de permettre de sauver simplement des données complexes, mais on se retrouve alors à définir un schéma et donc perdre tous les avantages du dynamisme.

Enfin, reste la solution du bon vieux fichier. Facile à lire, un peu plus difficile à modifier si l'on veut juste changer un petit quelque chose au milieu, il a l'avantage de ne nécessiter l'installation d'aucun logiciel supplémentaire. Par contre, la protection des données, la définition du schéma, leur accès en dehors de l'application, tout cela est entre vos mains. Ça fait un peu beaucoup, non?

Une fois que l'on est content de sa couche de persistance, encore faut-il décider de quand y accéder. D'un côté, il est possible de tout charger en mémoire au démarrage, et de tout sauver de temps en temps (mettons toutes les 10 minutes, dans un thread séparé pour un maximum de performances). C'est rapide. Mais cela veut dire qu'il faut mapper strictement toutes les données de la couche de persistance vers les objets du code. C'est du boulot! Enfin, il faut trouver le bon équilibre pour les sauvegardes: trop souvent, et les performances souffrent. Trop rarement, et un crash inopiné zappe une bonne partie de l'avancement des joueurs, à leur grande colère. Et enfin, arrive un moment où tout ne tient plus en mémoire... De l'autre côté, l'on peut accéder la couche de persistance uniquement quand on a besoin d'une donnée, et l'écrire à chaque fois qu'elle change. On ne perd rien en cas de crash, par contre, le système peut devenir très lent.

Il s'agit de trouver le bon équilibre entre les deux: quelles données peuvent être chargées à la volée? Peut-on les cacher en mémoire? Quelles donnés ont besoin d'être écrites immédiatement, quelles autres peuvent attendre? Comment s'assurer que tout est synchronisé? Typiquement, on fera la distinction entre les données importantes (une transaction entre deux joueurs, un avancement de quête) et celles qui le sont moins (monstre tué, ressources prises). Personne ne se plaindra si après un crash, une créature n'est pas exactement à la même position, ou si la mine contient encore les minerais que l'on a extrait (mais attention quand même, si un joueur découvre comment faire crasher le serveur, il pourrait se fabriquer une mine infinie?).

Enfin, quand il s'agit de coder tout ça, rappelez vous que moins on en écrit, mieux on se porte. Profitez au maximum des bibliothèques, écrivez du code générique pour binder vos données le plus efficacement possible, ou, encore mieux, utilisez des couches de persistance toutes faites (Hibernate?). Et sauvegardez. Tout. Tout le temps.

samedi 13 juin 2009

Développer son MMORPG - Choisir un language

Premier épisode d'une petite série qui durera ce qu'elle durera! A travers ces années à essayer un peu tout et n'importe quoi, voilà quelques idées sur le sujet des langages de programmation pour les MMO.

Les forums de développement de jeu regorgent de questions relatives aux langages qui sont les mieux adaptés à tel ou tel type de jeu. Lorsque l'on rajoute par dessus les besoins de performance et la complexité du développement d'un MMO, la question du langage devient particulièrement épineuse.

Avec AdH, on a un peu tout essayé: serveur en ocaml et c++, client en ocaml et c++, outils en ocaml, c++, java. Rajoutez quelques essais web avec PHP et .NET, une couche de SQL d'une épaisseur plus que changeante. Voilà donc ce qui a donné l'impression de marcher:


  • Il n'y a pas de langage parfait, et entre deux choix raisonnables, le mieux est de choisir quelque chose qui soit bien connu par les membres de l'équipe, et qui soit suffisamment utilisé par ailleurs pour trouver tout un tas de ressources sur le sujet. Développer son Tetris ou son Pacman pour apprendre un nouveau langage, c'est une excellente idée. Démarrer un WOW-killer à cloche pied avec l'idée d'apprendre en route, beaucoup moins! Également, il est préférable d'éviter les langages trop ésotériques, et choisir des technologies stables, matures et pour lesquels il sera facile de trouver de l'aide.


  • Choisir un langage, c'est aussi choisir un écosystème. Pour cette raison, il est important d'identifier les bibliothèques disponibles. Pour les graphismes, une implémentation OpenGL bas niveau ne suffit généralement pas: avez vous vraiment envie de développer un graphe de scène, d'écrire le code de chargement pour les objets 3D, ou de devoir convertir toutes vos images dans un seul format? Vous aurez suffisamment à coder comme ça pour vous embêter à écrire une couche de base de données, un moteur graphique, une couche réseau haut niveau, un bon support des threads, des bibliothèques pour charger et jouer les sons, charger les images, et j'en oublie.


  • Un même langage pour le client et le serveur. C'est un point très discuté, et pour cause. Avec un serveur et un client qui ont fondamentalement des buts très différents (graphismes et sons, portabilité, performances brutes pour le client - réseaux, bases de données, montée en charge pour le serveur), il est tentant de choisir deux langages. Notre expérience est qu'avec deux langages et une petite équipe, on se heurte à tout une série de problèmes:

    • Souvent, les membres de l'équipe se spécialisent, et il est difficile de faire bouger des gens du serveur au client et vice-versa

    • Tous les utilitaires bas-niveau doivent être ré-écrits deux fois

    • La communication entre le client et le serveur devient plus complexe, il y a d'avantages de risques liés à la sérialisation des données

    • De manière générale, une perte de temps bien supérieure aux gains potentiels


  • Un langage plus agile pour les outils. L'émergence de nouveaux langages de script tels Python, Ruby, Perl et autres peuvent fournir des opportunités pour développer rapidement des outils. La difficulté est de bien s'assurer qu'ils seront peu couplés avec l'application principale: par exemple, un éditeur de monde avancé aura probablement besoin des mêmes structures que le client et le serveur, et le choix d'un langage différent pourrait au final causer une perte de temps. En revanche, la création rapide de donnés, d'un panneau administratif, ou encore la génération de code, peuvent bénéficier des langages de script. Par exemple, dans AdH, le langage Ocaml est utilisé pour générer le code C++ de sérialisation des messages, ce qui a sauvé beaucoup de temps de développement.


Allez hop, maintenant on s'y met!

mardi 8 juillet 2008

Actions longues

Enfin, c'est implémenté! Ce système permet maintenant à une action de s'effectuer sur la durée. Le joueur démarre donc une recherche, et en reçoit le résultat 30 secondes plus tard. S'il démarre une autre recherche, ou change de lieu, la recherche courante est annulée.



Tout est dans la base de données, il est donc possible pour chaque lieu d'y ajouter la possibilité d'y rechercher des choses. Chaque recherche est définie par le temps passé à chercher, et d'une liste d'objets potentiellement trouvables avec leurs probabilités respectives. Il est ainsi possible de donner 1 chance sur 1000 de trouver une perle naturelle sur la plage!

jeudi 10 avril 2008

A bas les enchères!

Je reproduis un post que j'ai écrit sur le forum de jeuxonline.info.


- Le commerce de la main à la main nécessite soit d'avoir un système d'affichage de ses prix pour des marchands qui "campent" (à la Guild Wars), ou de submerger le chat avec ses prix (à la Project Entropia). Dans les deux cas, c'est une zone où l'on ne vient que pour commercer, parce que tout autre occupation devient assommante. Pourquoi donc ne pas fournir des outils qui institutionnalisent ce système, le rendant plus simple à utiliser?
- Toujours dans Project Entropia, on découvre que les joueurs, en plus des annoncent de vente, font aussi des annonces d'achat, ce qui n'est pas possible dans un système d'enchères. Ceci est tout bêtement une criée, ou un "pit" (voir http://en.wikipedia.org/wiki/Open_outcry, en anglais seulement malheureusement). Pourquoi donc ne pas s'inspirer des systèmes d'échanges électroniques qui ont remplacé ces "criées"? Voilà ce que cela donne:

Dans le marché du métal, joueur 1 veut acheter 10 unités à 17€ l'une. C'est son ordre, qu'il rentre dans le système. Tous les joueurs qui regardent le marché du métal dans la zone voient apparaître:




AchatVente
10 @ 17€


Un peu plus tard, d'autres joueurs ajoutent leurs ordres. J2 veut vendre ses unités à 20€, J3 veut acheter ses unités à 18 €.




AchatVente
10 @ 18€30 @ 20€
10 @ 17€


J4 veut absolument vendre ses 15 unités de métal à n'importe quel prix, il ajoute donc un ordre pour 15 unités à 1 €. Le système apparie les prix, créant donc un échange pour 10 unités à 18 € entre J2 et J4, et 5 unités à 17 € entre J1 et J4 (la priorité est aux "meilleurs" prix, c'est à dire les achats les plus hauts, ou les ventes les plus basses). Les marchandises sont échangés, et le système ressemble alors à cela:




AchatVente
5 @ 17€30 @ 20€
Dernier échange à 17 €


Avec ce système, les acheteurs et les vendeurs sont sur un pied d'égalité. Dans des marchés très liquides (avec beaucoup d'échanges), il est possible de commercer très efficacement.

Peut-être est-ce justement parce que la plupart des MMOs ont des systèmes de commerce trop peu liquide qu'ils n'implémentent pas ce système. En tous cas, mon jeu utilisera cela, et on verra bien si c'est utilisable!


L'on me fait très justement remarquer qu'Eve Online utilise un système similaire, ce qui n'est pas étonnant au vu de la richesse de son économie et des nombreux articles écrits à ce sujet. Il va falloir que je ressuscite mon compte à l'essai.

dimanche 24 février 2008

Presque Bérénice

Avec l'ajout du support pour les messages "whois" (identification des joueurs, qui permet l'affichage des noms dans le chat), la nouvelle mouture d'AdH a rattrapé l'ancienne, ce qui veut dire que l'on va enfin commencer à attaquer de nouvelles fonctionnalités (après un bon coup de nettoyage dans le code, quand même). Il ne reste qu'un seul bug ennuyeux, qui est que l'on ne peut voir les autres avatars qu'a partir du moment où ils commencent à bouger, et il faut que je trouve une manière élégante de corriger cela.

Pour la prochaine fonctionnalité, je me voyais bien m'attaquer à la création du monde. L'idée est de permettre à certains avatars de créer et de développer des zones, le tout depuis le jeu. Ces avatars pourraient à partir d'une bibliothèque d'objets et de quelques outils architecturaux créer des mondes entiers. La première raison pour une telle fonctionnalité est de n'avoir pas de génération de carte séparée: après tout, la représentation la plus proche de ce que verrons les joueurs est le jeu lui même! La deuxième raison est qu'une telle fonctionnalité, utilisée avec discernement, peut être formidable pour le gameplay, en proposant par exemple un niveau à partir duquel les joueurs, élevés au rang des dieux, peuvent créer de nouveaux mondes.

jeudi 21 février 2008

Un écosystème

Plus qu'un serveur causant à une base de données, c'est un écosystème entier qui peut se greffer sur l'architecture d'Adh. Maintenant que le système est au point (je viens de rajouter dans la base le support pour le déplacement des avatars), il est possible de connecter à peu près n'importe quel module additionnel sur la base pour aller y faire tout un tas de choses intéressantes. Il suffit de savoir causer le SQL.

On peut commencer simple, avec des systèmes de feed vers la base: par exemple, en envoyant la météo, afin de modifier l'environnement du jeu en temps réel. Ou encore, en permettant aux joueurs de recevoir des nouvelles depuis le forum d'un site web.

Après, on peut installer des feeds en sens inverse: faire remonter vers le site tout un tas de statistiques sur le monde, les derniers prix de marchandises, les actes de bravoure des joueurs...

Poussons plus loin, et ayons un système qui cause dans les deux sens! Pourquoi ne pas permettre aux joueurs d'accéder à leur personnage et d'effectuer des actions simples sans avoir à se connecter via le client lourd? Ainsi, le joueur pourrait aller enguirlander ses fermiers, commercer, ou encore préparer une autre conspiration, tout cela depuis le boulot / l'université / la salle info de l'école maternelle, à la pause déjeuner (et seulement à la pause déjeuner, n'est-ce pas, bande de petits canaillous?).

Mais ce n'est pas fini! Modifions la base pour permettre l'ajout de modules spécifiques qui iront modifier l'expérience de jeu. Il serait possible de développer un module d'artisanat, de combat, de sorts, de gestion de ses troupes, et beaucoup d'autres choses, de manière totalement indépendante. Par exemple, il suffit d'ajouter une simple table des ordres, et l'on peut avoir un module d'artisanat qui lit les ordres, et transforme les objets contenus dans l'inventaire de l'avatar. Une autre table d'ordres liée à un module de jeux de hasard, et voilà un casino!

Au final, ce code "hors serveur" doit surtout être utilisé pour les actions un peu particulières et qui n'arrivent pas trop souvent (l'on pourrait faire un module qui gère les déplacements, mais bonjour les performances!), mais permettrait d'ajouter assez facilement des tonnes de fonctionnalités pour un gameplay poussé.

Il n'y a plus qu'à s'y mettre!

vendredi 15 février 2008

Des requêtes, et des requêtes

Je suis en train de rapidement rattraper le niveau de fonctionnalités de Bérénice, rajoutant les requêtes faites par le client. Ce soir, c'était la description des objets du monde. Très sommaire pour l'instant (id, nom, description), mais ça sera simple à enrichir.

Un problème intéressant que celui de ces requêtes est la synchronisation. A la connexion, le client envoie en effet un lot de requêtes au serveur pour récupérer les informations importantes sur l'avatar incarné, la liste des types d'objets, l'inventaire... Mais si par exemple l'inventaire est reçu avant la liste d'objets, les noms ne pourront pas être affichés. De même, si la requête de mon inventaire est traitée par le serveur plus rapidement que la demande d'incarnation de mon avatar, le serveur va trouver que je ne suis pour l'instant lié à aucun avatar, et va refuser ma demande.

Dans certains cas, il existe une solution élégante au problème Pour l'inventaire, par exemple, utiliser le numéro d'identification tant que l'on a pas d'informations sur le nom de l'objet. Quand la liste des noms d'objets arrive, renommer tous les objets de l'inventaire avec la nouvelle liste. Le message arrivera de toutes façons si vite que le joueur ne s'apercevra même pas que les noms étaient faux au départ! Cela améliore la robustesse de l'application, qui devient capable de gérer les messages dans un ordre moins strict.

Dans d'autres cas, il n'y a pas de solution miracle, et il va falloir synchroniser à la main... Et le client attendra donc qu'une requête ait été confirmée pour envoyer la suivante. Il n'y a plus qu'à trouver un design à peu près propre pour supporter cela.

lundi 10 décembre 2007

Pensées asynchrones

Avoir un système pleinement distribué, voilà le rêve de tout architecte de MMORPG. Pour l'instant, AdH est mono-processus et mono-thread (mono-processus léger, que me dit mon encyclopédie communautaire préférée). Cela n'empêche heureusement pas d'y réfléchir.

Faisons le tour de quelques composants génériques et de la manière de les distribuer:

La gestion de compte
Autant l'authentification et le chargement des données personnelles peuvent être totalement distribués, autant il va quand même falloir éviter de permettre à un joueur de se connecter sur deux serveurs simultanément, sauf si le don d'ubiquité est partie intégrante du jeu. Si l'on veut un système centralisé, il faut que le composant ne fasse effectivement que ça. Même dans le cas de Wow et ses 9 millions de comptes (allez, arrondissons à 10 millions), on arrive si chacun des comptes se connecte une fois par jour (et on en est loin!) à 115 transactions par seconde, ce qui est parfaitement supportable pour une base de données digne de ce nom (quand on a 10 millions de comptes, on ne fait pas tourner sa gestion des comptes sur un vieux Pentium au fond du garage, de toutes manières). Mais, imaginons un succès fou (ou que le vieux Pentium au fond du garage batte de l'aile), on peut imaginer une partition simple, basée par exemple sur la première lettre du compte. Une base de données pour les joueurs de a à d, une deuxième pour le joueurs de e à j, et ainsi de suite. On diminue ainsi la charge pour chacune des machines (avec pourquoi pas un transfer de compte des lettres les plus utilisées vers les moins utilisées, et une propagation vers les serveurs principaux des adresses des serveurs correspondant aux lettres), par contre on augmente la complexité du réseau (chacun des serveurs principaux doit pouvoir se connecter à chacun des serveurs de comptes).

L'inventaire
Même problème: afin de s'assurer que le joueur ne profite pas d'une gestion de l'inventaire décentralisée pour échanger le même objet plusieurs fois, il faut s'assurer qu'il n'existe qu'un endroit où la transaction se fait. L'on peut imaginer un système de roaming, où l'inventaire du joueur le "suit" de serveur en serveur. Efficace, mais complexe, et surtout ennuyeux dès qu'un échange se fait entre des joueurs qui ne sont pas sur le même serveur (quand on a un univers pleinement distribué, c'est quand même dommage d'en faire des petits mondes indépendants!). Le même système à base d'inventaires distribués sur la première lettre du nom (ou les 2 premières lettres, ou plus, d'ailleurs) devrait être suffisamment efficace et relativement simple pour de grosses charges. C'est d'ailleurs fondamentalement une table de hachage!

Le monde
C'est là que ça se complique! Le monde peut être découpé en zones, façon Eve Online, qui gère ainsi un seul immense univers cohérent. Dans les mondes continus, un serveur peut gérer une surface donnée, et recevoir des données des autres serveurs pour afficher les joueurs "fantômes", c'est à dire gérés par d'autres serveurs mais visibles des joueurs locaux, parce que suffisamment proches de la frontière virtuelle entre deux serveurs. Lorsque le joueur franchit cette frontière, le serveur le passe à un autre serveur.
Ces deux techniques, déjà complexes, souffrent cependant lorsque trop de joueurs se dirigent vers le même endroit: le même serveur se retrouve à gérer énormément de joueurs, alors que d'autres serveurs sont presque totalement déserts. Et faire des zones plus petites, ou qui changent de taille en fonction du nombre de joueurs, devient extraordinairement compliqué, et les communications inter-serveurs explosent.

Le flux
La plus grande difficulté, en architecturant ce type de système distribué est de maintenir la cohérence. Par exemple, un serveur recevant une demande de connexion va envoyer une demande d'authentification à un serveur de compte, mais quand la réponse lui revient, le client s'est déjà déconnecté, ou s'est authentifié sous une autre identité.

Et toute faiblesse du système sera impitoyablement exploitée par les joueurs!

Et c'est pour cela qu'on se contentera pour l'instant d'un AdH mono-processus et mono-thread!

mercredi 3 octobre 2007

Une caractéristique des mmorpgs, et probablement une bonne partie de leur attrait pour nous autres développeurs, est l'étendue des domaines qu'il est nécéssaire de maîtriser pour les concevoir. Bases de données, architectures n-tiers et/ou distribuées, réseaux, haute performance, robustesse, graphismes, et, entre autres, interface utilisateur.

Dans beaucoup de jeux amateurs, l'interface utilisateur est la dernière roue du carosse, et AdH ne fait pas exception: il est tellement plus simple de passer ses identifiants de connection par la ligne de commande! Cependant, arrive un moment où il n'est plus possible de dire au joueur d'apprendre par coeur toutes les commandes clavier, façon "Aller regarder votre inventaire dans la console, lorsque vous appuyez sur i". Il faut donc faire quelque chose, et c'est là que ça se corse.

Nous avons passé beaucoup de temps à essayer les diverses solutions d'affichage de GUI dans AdH, et n'avons rien trouvé de très probant. Il y a bien ceGUI, mais les contrôles sont limités, l'ensemble paraît plutôt lent, et l'intégration à Open Scene Graph plutôt compliquée. Sans compter la tonne de fichiers de skin et autres qu'il faut placer au bon endroit, sous peine d'être noyé dans un flot de messages cryptiques.

Nous avons également contemplé la possibilité de créer nous même notre GUI. Mais au vu des interactions complexes dont nous avons besoin (inventaires, commerce, chat, configuration, et j'en passe), un tel développement aurait été un projet à plein temps pour les quelques années qui viennent. En cherchant un peu, l'on découvre tonnes de projets inaboutis de GUIs pour SDL et autres: d'autres ont essayé et on failli avant nous.

Restait la dernière solution: utiliser une GUI qui ne soit pas intégrée à notre environnement 3D, c'est à dire par exemple GTK, Win32, ou plus particulièrement et pour être portable, QT ou wxWidgets.



Je connaissais déjà wxWidgets et avais été favorablement impressionné par ses qualités. Certes, la bibliothèque gagnerait à être plus intégrée à la STL et à utiliser du code plus idiomatique, mais l'on arrive à un résultat de qualité sans trop se battre (la documentation, plutôt complète, aide beaucoup).



Comme vous pouvez le voir sur les captures d'écran, l'intégration à wxWidgets donne à l'application un cachet "éditeur de terrain", qui n'est pas forcément le mieux pour l'immersion dans le jeu. Les contrôles wxWidgets ne sont pas skinnables, et il faudra donc compter sur le thème du gestionnaire de fenêtres pour rendre l'ensemble un peu plus symathique (tiens, c'est une idée, ça! Un thème Windows / Gnome / KDE / autres pour AdH!). Mais le plus important, c'est que nous soyons maintenant efficaces dans l'élaboration d'une bonne GUI qui donne envie de jouer!

lundi 1 octobre 2007

Ocaml

Probablement la particularité technique principale de l'Aube des Héros, comparé à d'autres mmorpgs, est l'utilisation du language ocaml du côté serveur.

Au final, il y a assez peu d'experimentation (publique du moins) dans l'utilisation de languages un peu ésotériques , et encore moins dans les mmo mainstream. Notons toutefois Vendetta Online, qui utilise Lisp et Erlang. L'architecture distribuée d'Erlang semble effectivement particulièrement adaptée aux besoins de montée en charge d'applications de type mmo. De plus, la plupart des mmorpgs (voire tous les mmorpgs serieux?) utilisent des languages de haut niveau (lua, python, perl et une myriade de languages internes) pour coder la logique, comme par exemple l'intelligence artificielle, les interractions complexes avec l'environnement ou le système d'artisanat, en se basant sur des composants écrits dans des languages de plus bas niveau mais plus efficaces (dans la grande majorité du C++).

Pourquoi avoir choisi ocaml, alors?

Ocaml a beaucoup de qualités, les plus importantes à mes yeux étant l'expressivité, la sûreté du language, les bibliothèques disponibles, et enfin, ce qui ne gache rien, des performances tout à fait raisonnables.

Les trois premiers points sont liés, puisqu'ils influent directement sur la vitesse à laquelle il va être possible de fournir des fonctionnalités. Et pour nous autres amateurs qui n'ont pas d'équipes de 120 programmeurs travaillant 12 heures par jour, la vitesse de développement est fondamentale.

Ayant programmé plusieurs petites applications avec ocaml, j'étais curieux de voir comment le language se comporterait face à un programme plus gros, accédant à une base de données, et servant des données à de multiples clients connectés simultanément.

Avec la sortie d'Ajax, je peux le confirmer: ocaml pour le serveur valait vraiment l'effort fourni. Le serveur s'est avéré avoir au final très peu de bugs, et les quelques uns qui ont surgi ont été faciles à résoudre. L'avenir dira si l'architecture du serveur est suffisemment extensible, mais pour l'instant le language a beaucoup aidé à maintenir un ensemble cohérent et propre.

Dans un prochain post, je passerai en revue quelques constructions du language qui ont été particulièrement importantes et utiles lors du développement du serveur pour la version Ajax.