RMIGame est programmé entièrement en JAVA, il utilise la technologie RMI. Il dispose d'une architecture 3-tiers, composée d'une partie client, une partie serveur et une dernière base de données. Nous allons décrire l'architecture du système distribué que forme ce logiciel, ci-dessous. Nous n'entrerons pas dans les détails, nous ne décrirons que l'architecture permettant les communications entre les différents tiers de l'application. Une description un peu plus précise de chaque tiers se trouve dans leur description respective.
Architecture des jeux
La description des jeux est effectuée dans la section leur
étant destinée. Ici, nous allons parler de l'architecture mise en oeuvre
lors de l'exécution d'une partie d'un jeu. Les jeux fonctionnent en mode
client-serveur, la particularité vient du fait que le client ne dispose
pas du jeu. Le tiers serveur de RMI Game dispose du client et du
serveur des jeux. La partie client, est envoyée dynamiquement sous forme
sérialisée au client désireux de l'utiliser.
Les jeux de RMI Game sont composés de deux parties:
- la partie Controller exécutée par le serveur
- la partie Client destinée au client
La partie Controller contient une classe qui implémente l'interface GameController.
Cette classe est instanciée par le serveur pour créer une partie (demandée par un client).
L'interface GameController permet d'obtenir les caractéristiques du jeu, d'y ajouter des joueurs
et de le démarrer.
La partie Client contient une classe qui implémente l'interface GameClient (connue par le serveur le client).
Cette classe est instanciée par le Controller du jeu (côté serveur) pour être envoyée au client par
un appel RMI. Cette classe et tous ses attributs doivent donc être sérializables. Comme le client n'a pas
les fichiers de cette partie Client, le bytecode de cette classe et de celles qui y sont référencées
est téléchargé par le serveur de fichiers HTTP (ClassFileServer).
L'interface GameClient permet au client qui a reçu ce jeu de lui donner une instance de javax.swing.JPanel
pour que le jeu puisse s'y afficher, elle permet aussi de signaler un événement clavier et de quitter le jeu.
Communications
Client-Controller
La communication entre le Controller et les clients se fait
par appels RMI, donc les parties Controller
et Client doivent chacun posséder une classe héritant de java.rmi.server.UnicastRemoteObject et implémentant
l'interface java.rmi.Remote. Ces deux classes instanciées permettent ainsi de faire des appels distants
spécifiques au jeu entre la partie Controller et les parties
Client.
Nous allons étudier plus en détail ces mécanismes en
prenant l'exemple du fonctionnement de JPong, en n'oubliant pas
que tous les jeux supportés par le serveur (maintenant ou dans le futur)
suivent le même schéma de fonctionnement.
Fonctionnement de JPong
Dans un premier temps voici un récapitulatif des classes
utilisées par JPong, elles se situent toutes dans le paquetage
fr.unice.RMIGame.games.jpong:
Côté controleur (serveur):
JPongController - controleur du jeu, implémente GameController
RemoteJPongController - hérite de
java.rmi.Remote, partie visible par le client
RemoteJPongControllerImpl - hérite de UnicastRemoteObject, implemente RemoteJPongController
Ball - la balle du ping-pong
Player - représente les joueurs
Calculation - calcul les rebonds de la balle
Shuffle - détermine des trajectoire et
des nombres aléatoires
Côté client:
JPongClient - partie Client du jeu
(implémente GameClient, Serializable), contient les classes internes
Player, Ball, JPongTable.
RemoteJPongClient - hérite de
java.rmi.Remote, partie visible par le serveur
RemoteJPongClientImpl - hérite de UnicastRemoteObject, implemente RemoteJPongClient
Lorsqu'un client choisit de créer une partie de JPong, le
serveur instancie la classe JPongController et ajoute ce client comme
joueur "maître". Son constructeur instancie
RemoteJPongControllerImpl pour les communications du client vers le
controleur, puis crée la table (classes interne JPongTable) et la balle.
Lorsqu'un client est ajouté, le controleur instancie JPongClient en y intégrant l'instance de
RemoteJPongController et l'envoie au client avec la fonction receiveGame() de RemoteRMIGClient.
Le client qui reçoit le jeu l'affiche avec la fonction setDisplay(JPanel) de GameClient et demande au jeu
de créer un objet remote (RemoteJPongClient) et de l'envoyer au controleur avec la fonction join() de
RemoteJPongController.
Lorsque le controleur reçoit le remote du client, il lui crée un joueur et renvoie ses caractéristiques à
tous les clients inscrits à cette partie.
Lorsque le jeu a démarré les clients peuvent déplacer leur joueur par les touches du clavier, c'est le
controleur qui calcul la position des joueurs. Par exemple, si un client veut aller à droite, JPongClient
appelle la fonction goRIGHT() sur RemoteJPongController qui avertit le controleur, celui-ci calcule la nouvelle
position (en testant s'il y a collision avec les bords de la table) et renvoie cette position à tous
les clients. La position de la balle est calculée par le serveur à
intervalles réguliers et envoyée aux clients.
Cette architecture et son fonctionnement sont représentés,
en résumé, sur le schéma ci-dessous: