PHP-MySQL - Temps réel (ou simili)
#1
Bonjour,
Alors voilà je m'attaque au multijoueur sur mon jeu.
J'aimerais faire une actualisation très régulière pour :
- la présence des joueurs dans un lieu
- la présence des combats dans un lieu
- l'actualisation du tchat
- la réception de demande d'échange / de combat

Déjà, je veux pas surcharger, même par exemple pour des actualisations de toutes les 3/4 secondes, j'aimerais faire au mieux. (Les bases qui me viennent sont du sleep côté serveur ou du settimeinterval côté client).

Mais il y a des éléments qui nécessitent un ping régulier un peu plus dynamique que du 3/4 secondes :
- la présence des joueurs dans les lieux, car on peut interagir avec eux, donc si on clique pour un combat et que le joueur est parti depuis 4 secondes, j'aurais aimé qu'on ait l'information avant de cliquer (cliquer sur 5 joueurs qui sont déjà partis ça peut être frustrant).
- la réception des demandes d'échanges et de combat

Alors, je peux un peu tricher, c'est à dire que si un joueur a changé de lieu dans les 3 dernières secondes, on peut quand même recevoir la demande de combat / d'échange et l'accepter. Ca nécessite d'ajouter l'heure du déplacement pour vérifier côté serveur, mais c'est pas forcément dérangeant.

Donc ma question, selon vous, est-il possible d'avoir un quasi temps réel, ce qui serait idéal ?

Ou est-ce que vous avez des stratégie autre que du ping de serveur toutes les 3 secondes pour tout récupérer ? (ce qui peut être lourd non ?)

Qu'est-ce qui vous paraît idéal ?

On avait déjà parlé des websockets, j'ai pas encore réussi à bien saisir comment ça fonctionnait, si fallait des librairies comment les installer etc. Si vous pouvez me redonner quelques conseils là dessus.

Avant de me lancer là dessus j'ai plein de chapeaux à dessiner donc j'ai quelques jours 1 Je veux profiter de ce temps pour préparer au mieux le fonctionnement de tout ça 34

Merci !
Répondre
#2
J'ai essayé d’illustrer ci-dessous (en gros) comment moi je vois les choses.

J'ai pris l'exemple du problème de savoir qui est dans un lieu, en prenant le cas suivant :
- joueurA commence le jeu à 12:00:00 (avec un joueurB déjà connecté)
- joueurB entre dans le lieu à 12:20:00
- joueurB ressort du lieu à 12:25:00
- joueurA arrête le jeu à 13:00:00

Avec XHR classique (1 requête = 1 réponse).

Il y a la solution de l'attente active (exemple d'une communication client/serveur pour 1 joueur) :
Code :
12:00:00 - Client : Est-ce qu'il y a du nouveau ? (HttpRequest)
12:00:00 - Serveur : Non. (HttpResponse)
12:00:01 - Client : Est-ce qu'il y a du nouveau ? (HttpRequest)
12:00:01 - Serveur : Non. (HttpResponse)
12:00:02 - Client : Est-ce qu'il y a du nouveau ? (HttpRequest)
12:00:02 - Serveur : Non. (HttpResponse)
12:00:03 - Client : Est-ce qu'il y a du nouveau ? (HttpRequest)
12:00:03 - Serveur : Non. (HttpResponse)
... [plein de XHR]
12:19:58 - Client : Est-ce qu'il y a du nouveau ? (HttpRequest)
12:19:58 - Serveur : Non. (HttpResponse)
12:19:59 - Client : Est-ce qu'il y a du nouveau ? (HttpRequest)
12:19:59 - Serveur : Non. (HttpResponse)
12:20:00 - Client : Est-ce qu'il y a du nouveau ? (HttpRequest)
12:20:00- Serveur : Oui ! Il y a joueurB qui est rentré dans le lieu ! (HttpResponse)
12:20:01 - Client : Est-ce qu'il y a du nouveau ? (HttpRequest)
12:20:01 - Serveur : Non. (HttpResponse)
... [plein de XHR]
12:24:58 - Client : Est-ce qu'il y a du nouveau ? (HttpRequest)
12:24:58 - Serveur : Non. (HttpResponse)
12:24:59 - Client : Est-ce qu'il y a du nouveau ? (HttpRequest)
12:24:59 - Serveur : Non. (HttpResponse)
12:25:00 - Client : Est-ce qu'il y a du nouveau ? (HttpRequest)
12:25:00- Serveur : Oui ! Il y a joueurB qui a quitté le lieu ! (HttpResponse)
12:25:01 - Client : Est-ce qu'il y a du nouveau ? (HttpRequest)
12:25:01 - Serveur : Non. (HttpResponse)
... [plein de XHR]
12:59:58 - Client : Est-ce qu'il y a du nouveau ? (HttpRequest)
12:59:58 - Serveur : Non. (HttpResponse)
12:59:59 - Client : Est-ce qu'il y a du nouveau ? (HttpRequest)
12:59:59 - Serveur : Non. (HttpResponse)
13:00:00 - Client : Je me casse ; c'est nul ce jeu !

C'est un peu une solution en mode colocataire ultra relou, avec plein de requêtes qui ne servent à rien.


Il y a la solution du long-polling (exemple d'une communication client/serveur pour 1 joueur) :

Code :
12:00:00 - Client : OK ! Dis-moi quand il y a du nouveau (HttpRequest)
12:20:00 - Serveur : Il y a l'omniscient qui est rentré dans le lieu  ! (HttpResponse)
12:20:01 - Client : OK ! Dis-moi quand il y a du nouveau (HttpRequest)
12:25:00 - Serveur : Il y a l'omniscient qui a quitté le lieu ! (HttpResponse)
12:25:01 - Client : OK ! Dis-moi quand il y a du nouveau (HttpRequest)
13:00:00 - Client : Je me casse ; c'est nul ce jeu ! (Mais au moins je fais pas le relou.)

C'est une solution moins coûteuse que la précédente (en nb d'échanges client/serveur) mais qui implique :
- pour le serveur de savoir garder la requête XHR ouverte et à ne faire la réponse qu'au moment opportun (quand une action est effectuée par un autre joueur, le serveur doit notifier les joueurs pour lesquels il a des XHR en mémoire et qui sont concernés par l'action)
- pour le client de bien renvoyer une requête à chaque fois qu'il reçoit une réponse

Avec des tunnels de communication bidirectionnels où client & serveur peuvent s'envoyer des messages quand ils le veulent.

Il y a la notification sur évènement côté serveur (exemple d'une communication client/serveur pour 2 joueurs) :

Code :
12:00:00 - Client (JoueurA) : Je me connecte (message client => serveur)
12:00:00 - Serveur (au JoueurA) : Ok, voici les infos dont tu as besoin (message serveur => client)
12:20:00 - Client (JoueurB) : Je vais dans le lieu (message client => serveur)
12:20:00 - Serveur (au JoueurB) : Ok, j'ai bien pris en compte ton action (message serveur => client)
12:20:00 - Serveur (au JoueurA) : Hey, il y joueur B qui se ramène (message serveur => client)
12:25:00 - Client (JoueurB) : Je quitte le lieu (message client => serveur)
12:25:00 - Serveur (au JoueurB) : Ok, j'ai bien pris en compte ton action (message serveur => client)
12:25:00 - Serveur (au JoueurA) : Hey, il y joueur B qui s'en va (message serveur => client)
13:00:00 - Client (JoueurA) : Je me casse ; c'est nul ce jeu ! (message client => serveur)

C'est une solution qui implique pour le serveur de bien notifier toutes les personnes qu'il faut.


Il y a les push réguliers côté serveur sur le tunnel de communication (exemple d'un push toutes les 10 secondes, pour 2 joueurs) :


Code :
12:00:00 - Client (JoueurA) je me connecte (message client => serveur)
12:00:05 - Serveur (au JoueurA) Sur le lieu 1 il y a que toi (message serveur => client)
12:00:05 - Serveur (au JoueurB) Sur le lieu 2 il y a que toi (message serveur => client)
12:00:15 - Serveur (au JoueurA) Sur le lieu 1 il y a que toi (message serveur => client)
12:00:15 - Serveur (au JoueurB) Sur le lieu 2 il y a que toi (message serveur => client)
12:00:25 - Serveur (au JoueurA) Sur le lieu 1 il y a que toi (message serveur => client)
12:00:25 - Serveur (au JoueurB) Sur le lieu 2 il y a que toi (message serveur => client)
... [plein de messages]
12:19:55 - Serveur (au JoueurA) Sur le lieu 1 il y a que toi (message serveur => client)
12:19:55 - Serveur (au joueurB) Sur le lieu 2 il y a que toi (message serveur => client)
12:20:00 - Client (JoueurB) : Je pars du lieu 2 et je vais dans le lieu 1 (message client => serveur)
12:20:05 - Serveur (au JoueurA) Sur le lieu 1 vous êtes 2 ! (message serveur => client)
12:20:05 - Serveur (au JoueurB) Sur le lieu 1 vous êtes 2 ! (message serveur => client)
12:20:15 - Serveur (au JoueurA) Sur le lieu 1 vous êtes 2 ! (message serveur => client)
12:20:15 - Serveur (au JoueurB) Sur le lieu 1 vous êtes 2 ! (message serveur => client)
... [plein de messages]
12:24:55 - Serveur (au JoueurA) Sur le lieu 1 vous êtes 2 ! (message serveur => client)
12:24:55 - Serveur (au joueurB) Sur le lieu 1 vous êtes 2 ! (message serveur => client)
12:25:00 - Client (JoueurB) : Je pars du lieu 1 et je vais dans le lieu 3 (message client => serveur)
12:25:05 - Serveur (au JoueurA) Sur le lieu 1 il y a que toi ! (message serveur => client)
12:25:05 - Serveur (au JoueurB) Sur le lieu 3 il y a que toi ! (message serveur => client)
12:25:15 - Serveur (au JoueurA) Sur le lieu 1 il y a que toi ! (message serveur => client)
12:25:15 - Serveur (au JoueurB) Sur le lieu 3 il y a que toi ! (message serveur => client)
... [plein de messages]
13:00:00 - Client (JoueurA) : Je me casse ; c'est nul ce jeu ! (message client => serveur)

C'est un peu une solution en mode distribution de pub centralisée avec des prospectus à distribuer aux clients connectés pour les tenir informés de l'actualité.

____

Voilà : en gros il vaut mieux éviter les solutions avec des boucles et travailler par captation d'évènement côté serveur si on peut.
Répondre
#3
Il y a aussi la solution (outre de réorienter le gameplay pour ne pas faire de temps réel) de WebRTC. Sur le principe:
- Joueur A => Serveur: je suis arrivé au lieu dit ("trempé par un orage") et voici mon token RTC
-- Réponse du serveur: Ok, ben, y'a personne
- Joueur B => Serveur: je suis arrivé au lieu dit, et voici mon token RTC
-- Réponse du serveur: Ok, y'a déjà Joueur A, dont voici le token RTC
- Joueur B => Joueur A: Coucou, j'ai ton token, je suis dans le même lieu que toi!
- Joueur A => Joueur B: Salut! On s'fight?!

Dans l'idée, le serveur laisse les joueurs se démerder entre eux pour savoir qui est où, combattre, etc. Il sert éventuellement juste "d'arbitre", si besoin (genre, pour sauver les actions de combat).

Ca nécessite 0 spécificité côté serveur, mais cela implique d'avoir, d'une part, des navigateur à jour, et d'autre part, de réussir à gérer les connexions WebRTC entre les clients. C'est pas toujours gagné de ce point de vue là, à cause des NAT (les box quoi).
J'avais déjà essayé de faire une démo WebRTC https://xenos.reinom.com/webrtc/ (datartc te servirait dans ton cas), mais je crois n'avoir jamais pu la faire marcher en dehors de mon réseau local...

-----

Il y a sinon la Push API (cf démo https://serviceworke.rs/ ), qui devrait permettre de faire un mécanisme type :
- Joueur A va dans le lieu, il dit au serveur "envoie-moi une notif quand un autre arrive dans ce lieu", et le serveur le note dans sa DB
- Joueur B va dans le même lieu, le serveur voir que Joueur A y est, il envoie un push au joueur A à partir des infos dans la DB du serveur
- Le joueur A reçoit la notif, de là, 2 cas possibles:
-- Le joueur A ne joue plus: la notification va être reçue, mais le client va répondre au serveur "en fait, je m'en fous des notifs, je ne joue plus, ne m'en envoie plus" (histoire de ne pas envoyer des push inutiles au client, car c'est limité cf https://developer.mozilla.org/en-US/docs...I/Push_API ) => Quand joueur A reviendra dans le jeu, il renverra l'information au joueur qu'il accepte de nouveau de recevoir des Push
-- Le joueur A joue encore, il reçoit l'information et notifie l'humain derrière l'écran (notif classique, affichage in game, reload de page, qu'importe)

Ca doit pouvoir se jouer ce genre d'approche, mais je ne l'ai jamais testée. Dracca sera probablement une bonne occasion : ) Ca m'a l'air très agnostique vis-à-vis de la techno serveur, donc, applicable sur n'importe quel type de serveur potentiellement (bien que je n'ai pas encore assez de connaissances sur la façon d'envoyer le Push; de ce que j'ai compris, c'est simplement une URL à contacter, mais j'ai quelques doutes sur le fait d'avoir bien compris?!)
Répondre
#4
Le plus simple reste un serveur de WebSocket. Il te faut un serveur dédié.

http://c-mh.fr/posts/websockets-en-php-p...n-y-parait

Ça me fait penser qu’à un moment je voulais mettre à disposition un serveur de Push de type Pusher pour les membres de JeuWeb... histoire de les aider à démarrer dans le temps réel.
Répondre
#5
Citation :Ça me fait penser qu’à un moment je voulais mettre à disposition un serveur de Push de type Pusher pour les membres de JeuWeb... histoire de les aider à démarrer dans le temps réel.

J'ai eu la même idée ! Mais je me suis dit que les solutions existantes proposaient de quoi bien commencer en gratuit. Mais si t'es toujours chaud on se le fait, ça ira vite.
Répondre
#6
Wahou merci pour tout ce contenu de réponses 34
Alors ok pour l'attente active, j'oublie, et puis c'est vrai que c'est méga lourd.

Concernant le long-polling, est-ce que ça ça en est :
Code :
/* Fonction recherche de l'attaque de l'adversaire */
function search_attaque() {
    global $bdd;
    global $qui;
    $bdd->beginTransaction();
    if ($qui['IDCombattantActif'] == $_SESSION['ID']) {
        $attaque=$bdd->query('SELECT AttaquePassif FROM z_erentis_combats_jcj WHERE IDCombattantActif = "'.$_SESSION['ID'].'" ');
    } else if ($qui['IDCombattantPassif'] == $_SESSION['ID']) {
        $attaque=$bdd->query('SELECT AttaqueActif FROM z_erentis_combats_jcj WHERE IDCombattantPassif = "'.$_SESSION['ID'].'" ');
    }
    $bdd->commit();
    $attaque = $attaque->fetch();
    return $attaque[0];
}


/* Trop tard pour l'attaque de l'adversaire */
function cherche_et_toolate() {
    global $bdd;
    global $qui;    
    $time = 0;
    $attaque = search_attaque();
    /* On cherche l'attaque du joueur adverse jusqu'à ce qu'on la trouve */
    while ($attaque == "?" AND $time < 30) {
        $attaque = search_attaque();
        if ($attaque == "?") {
            sleep(2);
        }
        $time = $time + 2;
    }
    if ($time >= 30) {
        $attaque = "X";
        if ($qui['IDCombattantActif'] == $_SESSION['ID']) {
            $use = $bdd->prepare('UPDATE z_erentis_combats_jcj SET AttaquePassif = "X", AttaqueActif = "?", TooLatePassif = "Yes", Tour = Tour + 0.5 WHERE IDCombattantActif = ?');
        } else if ($qui['IDCombattantPassif'] == $_SESSION['ID']) {
            $use = $bdd->prepare('UPDATE z_erentis_combats_jcj SET AttaqueActif = "X", AttaquePassif = "?", TooLateActif = "Yes", Tour = Tour + 0.5 WHERE IDCombattantPassif = ?');
        }    
        $use->execute(array($_SESSION['ID']));
        $aten['Nom'] = "X";
    }
    return $attaque;

Si oui, je crois que ça peut provoquer des Race condition... En tous cas mon code ci-dessus semble en provoquer. J'ai l'impression, mais peut-être que je me trompe, que les connexions performantes empêchent les connexions plus faibles d'accéder aux données durant la boucle (dans le code ci-dessus, le joueur B n'arrive à rentrer dans la boucle que quand le joueur A en est sorti, mais ce problème n'a pas lieu pour tous les joueurs, par contre il a toujours lieu avec les mêmes duos de joueurs, et seul un joueur du duo est affecté, toujours le même, et toujours quand il attaque en deuxième. Quand il attaque en premier il n'a pas de soucis et l'autre joueur arrive à rentrer correctement dans la boucle).

Du coup je penche pour les tunnels bidirectionnels. Les tunnels bidirectionnels nécessitent l'installation de librairies ?
(D'ailleurs je lis ça pour les tunnels bidirectionnels : Ouvre un socket vers un hôte/port arbitraire via un serveur connecté SSH. C'est pas du websocket ?)

Xenos je préfère pas me risquer à tes expériences d'apprenti sorcier 45 Je ne suis pas assez compétent pour ça :p

Ah les websockets c'est pour ça que j'avais lâché l'idée, le serveur dédié. Je peux avoir une partie de mon jeu hébergé sur un mutualisé et l'autre sur un dédié ?
Si j'ai bien compris, le serveur dédié doit être en NodeJS. Ca me fait un peut chier de repayer un serveur 30 ou 40 euros. Par contre Sephi si on a un serveur commun Jeuweb je veux bien participer au prix si yen a pas de gratuits (divisé entre le nombre d'utilisateurs ?). Ca me dérange pas de payer 10, 15, voire aller 20€ sur l'année si ya vraiment un avantage à avoir un truc aussi cher 34 (Mais je vous fais toute confiance sur le choix).
En plus moi qui voulait me lancer sur NodeJS c'est parfait 34 (Bon par contre j'espère que je vais pas trop galérer pour faire mon multi parce que j'ai quand même un temps limité).
Par contre, si le serveur ne peut pas être dispo dimanche max, je vais peut-être pas pouvoir attendre (2 semaines ça va faire cours).
Par contre j'ai un autre soucis si ça passe par un second serveur, il faut que mes données de placement des joueurs soient sur ce serveur. Comment je relie les données de ma base de données avec la base de données de cet autre serveur ? Je pourrai faire une simili jointure entre une table dans mon serveur SQL et une table dans le serveur NodeJS ?

Voilà j'attends encore un peu vos réponses et d'en savoir un peu plus pour choisir la technologie appropriée (et pour spammer plein de forums pour récolter plein d'infos sur cette technologie 1 )
Répondre
#7
Salut,
Non, ce n'est pas du long polling, car tu ne boucle tout simplement pas. Il n'y a pas de notion de "les connexion rapide influent les connexion lentes": tu es côté serveur, donc, c'est ton algo qui dirige les choses, pas le client. De plus, il n'y a pas de "race condition": étant transactionné, t'as pas de soucis côté DB (mis à part qu'il faut paramétrer tes queries et non faire de la concaténation de string 2 )

Ca peut être sympa d'avoir un service "jeuweb" pour ça, oui, mais après, faudra le monitorer car si on se retrouve avec des mauvais codes ou des jeux à 10k joueurs, on va coincer :/ Il faudra aussi être capable de bien gérer le fait d'être sur 2 origines différentes (jeuweb.org & urldujeu.com) Le même soucis d'origine se pose si tu prends un dédié en plus de ton mutu (c'est con IMO, mieux vaut alors ne prendre qu'un dédié), même si la "casse" est limitée puisque tu peux faire pointer un sous domaine du jeu sur ce dédié.

Le serveur dédié peut être en ce que tu veux. Faut qu'il soit en revanche capable de gérer les websockets, et idéalement, de gérer les évent (de sorte que la connexion 2 puisse dire à la connexion 1 que le joueur de la connexion 2 est arrivé dans le lieu X), sinon, tu vas te retrouver avec de l'attente active côté serveur, ce qui n'amènera donc rien d'intéressant.

Hum, un dédié, à part les kimsuffi, je les voit plutôt à 10€ le mois : )

Y'a pas de "table" dans le serveur JS. Ton serveur JS aura juste à aller se connecter au SQL commun aux deux serveurs pour lire les données dont il a besoin (à toi derrière de gérer tes transactions proprement : ) Non, je dis ça "comme ça", juste parce que ce genre d'archi, c'est ce qu'on adore au boulot et qu'on se retrouve avec 10 serveurs Java pour la moindre requête entrante, qui se marchent tous dessus dans leurs appels de BDD ce qui fait qu'on n'a plus vraiment de transaction... je m'égare, pardon).

Tiens, d'ailleurs, pour ceux qui se sont servi de NodeJS, comment ça se passe quand la connexion 2 doit informer les autres d'un event (genre, le joueur de la connexion 2 est arrivé dans le lieu X)? La connexion dispatch un event sur un objet global genre "Server", et toutes les autres connexions avec un listener dessus peuvent réagir à l'event? Si oui, ça se passe comment quand on atteint 10,100,1000,10k connexions (parce que là, ça devient juste ingérable par un serveur?!)? Quelle "limite" pratique au nb de connexions dans ce cas?


Edit:
Eeeeeh, je ne m'en suis jamais servi, mais les mutualisés d'OVH semblent avoir le module Semaphore d'actif ( http://fpm7.3-check.cluster013.hosting.o...hpinfo.php sysvmsg) donc, il serait possible de l'utiliser pour faire de l'IPC (Inter Process Communication si j'ia bien tout suivi https://www.php.net/manual/en/ref.sem.php ) ce qui permettrait à un script PHP de "notifier" un autre script qu'un évènement a eu lieu... Cela pourrait faire un long polling intéressant ?!
Répondre
#8
L'omniscient a écrit :Si oui, je crois que ça peut provoquer des Race condition...

Peut être que tu as un verrou quelque part que tu n'as pas vu ? (c'est en auto-commit ? c'est des tables innoDB ?). Parfois aussi il y a un nombre de connexions limitées si on utilise un pool de connexions et du coup il faut attendre qu'un script libère la connexion pour qu'un autre puisse l'utiliser.

Honnêtement, je ne sais pas ; il faudrait peut être savoir à quel moment ça bloque exactement (si ça bloque), ou quelles erreurs ça renvoie (si ça abort). Là, de la façon dont tu le décris, ça me fait penser à un problème de famine en concurrence.

EDIT :
L'omniscient a écrit :Du coup je penche pour les tunnels bidirectionnels. Les tunnels bidirectionnels nécessitent l'installation de librairies ?
(D'ailleurs je lis ça pour les tunnels bidirectionnels : Ouvre un socket vers un hôte/port arbitraire via un serveur connecté SSH. C'est pas du websocket ?)

Oups, j'avais pas lu jusqu'au bout ! Oui voilà, quand je parle de ça je parle de websocket.
Répondre
#9
Citation :Tiens, d'ailleurs, pour ceux qui se sont servi de NodeJS, comment ça se passe quand la connexion 2 doit informer les autres d'un event (genre, le joueur de la connexion 2 est arrivé dans le lieu X)? La connexion dispatch un event sur un objet global genre "Server", et toutes les autres connexions avec un listener dessus peuvent réagir à l'event? Si oui, ça se passe comment quand on atteint 10,100,1000,10k connexions (parce que là, ça devient juste ingérable par un serveur?!)? Quelle "limite" pratique au nb de connexions dans ce cas?

J'ai jamais fait de websocket en node mais sur Phoenix c'est ce qu'il se passe, chaque connexion websocket écoute N canals, et quand on publie un message sur ce canal, chaque connexion l'envoie au navigateur (avec possibilité de l'intercepter avant envoi, par exemple tu publies l'état d'une partie et chaque connexion va masquer les données des autres joueurs avant de relayer).

Et ensuite bah plus tu as de joueurs plus il te faut de serveurs costauds. L'avantage avec Phoenix c'est que tu peux mettre plusieurs serveurs en parallèle assez simplement.

The Road to 2 Million Websocket Connections in Phoenix (sur un seul serveur).
Répondre


Sujets apparemment similaires...
Sujet Auteur Réponses Affichages Dernier message
  Quelle technologie pour un jeu de carte pseudo temps réel ? Soleo 12 4 314 03-17-2014, 12:20 AM
Dernier message: niahoo
  NodeJS - MVC + temps-réel - Structuration d'application Cawrotte 7 37 579 07-21-2013, 12:04 PM
Dernier message: Cawrotte
  Afficher des ressources en temps réel ... Lord-Gargoyle 11 9 341 11-26-2012, 01:17 PM
Dernier message: sclabet
  Déplacement temps réel jean-baptiste 17 9 513 06-12-2012, 08:48 PM
Dernier message: Astarion
  Temps Reel Java Aleskweb 38 15 142 02-18-2012, 04:00 PM
Dernier message: Hideaki



Utilisateur(s) parcourant ce sujet : 1 visiteur(s)