Commit bd014933 authored by Mamadou Diallo's avatar Mamadou Diallo
Browse files

Ajout du model

parent f3554732
......@@ -29,4 +29,38 @@ Vous n’êtes pas seul...
The current source code organization is based on the following article:
https://frakton.com/utilizing-maven-front-end-plugin-for-angular-spring-boot/
\ No newline at end of file
https://frakton.com/utilizing-maven-front-end-plugin-for-angular-spring-boot/
== Livrables attendus
=== Analyse du domaine
Objectif::
Description du jeu _Not Alone_ sous la forme d'un diagramme de classes conceptuelles et d'actions
Moyens::
Utilisez une approche itérative pour découvrir toutes les classes conceptuelles et les actions du jeu.
=== Conception préliminaire
Objectif::
Découpage de la solution en composants (ou sous-systèmes) et spécification des interfaces fournies et requises par ces composants
Moyens::
Utilisez des diagrammes d'interaction (séquence, communication) pour décrire l'échange de messages entre les composants pour en déduire leurs interfaces.
=== Conception détaillé
Objectif::
Spécification détaillée des composants: leur structure (diagramme de classes de conception), ainsi que le comportement de chaque opération fournie par le composants. Le comportement peut-être décrit en utilisant les diagrammes d'activité, d'interaction, les machines d'état, ainsi que OCL.
Moyens::
Appliquez les concepts vus en cours: design patterns, principes GRASP, bonnes pratiques, etc.
=== Code source
Objectif::
Code de mise en oeuvre et tests de l'application.
Moyens::
Appliquez les enseignements de l'UE "Construction et évolution de logiciels" pour produire un code source de qualité.
\ No newline at end of file
namespace java fr.univnantes.alma.core
namespace java fr.univnantes.alma.thrift
namespace js core
exception InvalidOperationException {
1: i32 code,
2: string description
}
exception GameNotFound {
1: i32 code,
2: string description
}
include "common.thrift"
namespace java fr.univnantes.alma.thrift
service GameClientService {
bool ping() throws (1:common.InvalidOperationException e)
}
include "common.thrift"
struct CrossPlatformResource {
1: i32 id,
2: string name,
3: optional string salutation
namespace java fr.univnantes.alma.thrift
struct JoinRequest {
1: string name
}
service GameServerService {
CrossPlatformResource get(1:i32 id) throws (1:common.InvalidOperationException e),
void save(1:CrossPlatformResource resource) throws (1:common.InvalidOperationException e),
list <CrossPlatformResource> getList() throws (1:common.InvalidOperationException e),
i32 createGame(i32 numberOfPlayers)
bool ping() throws (1:common.InvalidOperationException e)
i32 join(i32 gameId, JoinRequest request) throws (1:common.GameNotFound e)
}
= Conception détaillée
== Diagramme de Séquences
include::./diagrams/sequences.puml[]
== Diagramme de Séquences
== Diagramme de classes
include::./diagrams/classes.puml[]
== Diagramme de classes
= Conception détaillée
== Game Server
.GameSever
[plantuml]
....
interface GameServer {
createGame(numberOfPlayers : Integer): Integer
join(gameId : Integer): Integer
join(gameId : Integer, rang : String, port:Integer ): Integer
}
package game {
class "GameServerController" as controller {
createGame(numberOfPlayers : Integer): Integer
join(gameId : Integer): Integer
join(gameId : Integer, rang : String, port:Integer ): Integer
updateLocal(idPlayer: Integer, game: Game)
updateClients(players : Player [*] , game:Game)
giveTurn(idJoueur : Integer, idGame : Integer)
}
class "Game \n[Thread]" as game {
id : Integer {id}
numberOfPlayers : Integer
phase : Integer
Game(numberOfPlayers: Integer)
addPlayer(idGame: Integer, idPlayer :Integer)
getListPlayer() : Player[*]
getIdGame() : Integer
gameOver() : Boolean
}
class "Player" as player {
id : Integer {id}
player(Integer id)
getId() : Integer
}
class "Card" as Card {
id : Integer {id}
effect()
}
class "Jeton" as Jeton {
id : Integer {id}
effect()
}
class "CardCreature" as CardCreature {
}
class "CardTraque" as CardTraque {
}
class "Lieu" as Lieu {
}
GameServer <|-- controller
player <|-- Traqué
player <|-- Creature
controller *- "[*] games" game : \t\t\t
game *-- "[0..7] players" player
}
note right of game: Uncompleted!
....
Card *-- "1" player : Main
Card *-- "1" player : Defausse
Card <|-- CardTraque
Card <|-- CardCreature
CardCreature <|-- Survie
CardCreature <|-- Lieu
CardTraque <|-- CarteX
[plantuml]
....
state Game {
[*] --> Created
Created -> Started : start()
Started -> Phase1 : \t
Phase1 --> [*]
}
note right of Game : Uncompleted!
....
=== Opérations du GameServerController
.Create Game
[source,OCL]
----
GameServerController::createGame(numberOfPlayers : Integer): Integer
pre:
numberOfPlayers > 1 and numberOfPlayers <= 7
post:
self.games -> exists(each | each.isOclNew())and
game.oclinState(Created)
----
.Join Game
[source,OCL]
----
GameServerController::join(gameId : Integer): Integer
pre:
self.games -> exists(each | each.id = gameId)
post:
let game = self.games->select(id = gameId)->first() in
game.players->exists(each| each.isOclNew())
----
.Start Game
[plantuml]
----
partition Game::run() {
start
while (enough players?)
:JoinRequest<
:handleRequest();
endwhile
:Game Start>
stop
}
----
= Conception préliminaire
== Création d'une nouvelle partie
[plantuml]
....
participant "__one:Traqué__" as player1
participant "__two:Créature__" as player2
participant "__game:GameServer__" as game
player1 -> game : id := createGame(6)
par
player1 -> game : playerId := join(id, one, port)
player2 -> game : id := join(id, two)
end
....
== Joindre une partie existante
[plantuml]
....
participant "__one:Traqué__" as player1
participant "__two:Créature__" as player2
participant "__game:GameServer__" as game
player1 -> game : id := searchGame()
par
player1 -> game : playerId := join(id, one, port)
player2 -> game : id := join(id, two)
end
....
== Commencer la partie
[plantuml]
....
participant "__one:Traqué__" as player1
participant "__two:Créature__" as player2
participant "__game:GameServer__" as game
game -> player1 : beginGame()
game -> player2 : beginGame()
player1 -> player1 : initCards()
player2 -> player2 : initCards()
....
== Jouer tour
[plantuml]
....
participant "__one:Traqué__" as player1
participant "__two:Créature__" as player2
participant "__game:GameServer__" as game
game -> player1 : giveTurn(id_joueur )
player1 -> player1 : play()
player1 -> game : update(id_joueur, instanceGame)
game -> player2 : giveTurn(id_joueur)
player2 -> player2 : play()
player2 -> game : update(id_joueur, instanceGame)
....
== Fin du jeu
[plantuml]
....
participant "__one:Traqué__" as player1
participant "__two:Créature__" as player2
participant "__game:GameServer__" as game
game -> game : id_Gangant := getWinner()
game -> player1 : id_Gangant := gameOver(id_Gagnant)
game -> player2 : id_Gangant := gameOver(id_Gagnant)
....
......@@ -6,8 +6,10 @@ database Server
participant ClientWeb2
actor Traqué
Créature -> Server : idGame := CreateGame(6)
Créature -> Server : playerId := join(id, one)
Traqué -> Server : playerId := join(id, creature)
Créature -> Server : joindre()
Server -> Server : recherchePartie()
Server -> Server : creerPartie(List<Joueur>)
Server -> Créature : getIdPartie(partie)
......
......@@ -5,6 +5,6 @@
include::{includedir}/analyse.adoc[leveloffset=+1]
include::{includedir}/exigences.adoc[leveloffset=+1]
include::{includedir}/composants.adoc[leveloffset=+1]
include::{includedir}/conception.adoc[leveloffset=+1]
include::{includedir}/conceptionPreliminaire.adoc[leveloffset=+1]
include::{includedir}/conceptionDetaillee.adoc[leveloffset=+1]
include::{includedir}/termes.adoc[leveloffset=+1]
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath></relativePath>
<version>2.4.0</version>
<relativePath/>
</parent>
<groupId>fr.univnantes.alma</groupId>
......@@ -16,26 +16,33 @@
<name>Not Alone Server</name>
<description>Spring Boot Not Alone server</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>fr.univnantes.alma</groupId>
<artifactId>not-alone-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.atlanmod.commons</groupId>
<artifactId>commons-core</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
......
package fr.univnantes.alma;
import fr.univnantes.alma.thrift.GameServerService;
import fr.univnantes.alma.handler.GameServiceHandler;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import org.apache.thrift.server.TServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@SpringBootApplication
import javax.servlet.Servlet;
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class NotAloneApplication {
public static void main(String[] args) {
SpringApplication.run(NotAloneApplication.class, args);
}
@Bean
public TProtocolFactory tProtocolFactory() {
return new TBinaryProtocol.Factory();
}
@Bean
public ServletRegistrationBean gameServer(TProtocolFactory protocolFactory, GameServiceHandler handler) {
TServlet tServlet = new TServlet(new GameServerService.Processor<GameServiceHandler>(handler), protocolFactory);
return new ServletRegistrationBean(tServlet, "/api");
}
}
package fr.univnantes.alma.common;
public class GameJoinRequest {
}
package fr.univnantes.alma.common;
import fr.univnantes.alma.common.GameJoinRequest;
public interface GameService {
/**
* Creates a game for a number of players
* @param expectedPlayers The number of expected players, between 2 and 7
*
* @return an int, the game identification
*/
int createGame(int expectedPlayers);
/**
*
* @param gameId
* @param request
* @return
*/
int join(int gameId, GameJoinRequest request);
}
package fr.univnantes.alma.game;
import fr.univnantes.alma.common.GameJoinRequest;
import org.atlanmod.commons.log.Log;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
public class Game {
/**
* Stores arriving registrations.
*/
private final BlockingQueue<GameJoinRequest> requests;
/**
* Counter used to increment player identifications.
*/
private final AtomicInteger idCounter = new AtomicInteger(0);
private final AtomicInteger expectedPlayers;
private Thread play;
public Game(int expectedPlayers) {
this.expectedPlayers = new AtomicInteger(expectedPlayers);
this.requests = new ArrayBlockingQueue<GameJoinRequest>(expectedPlayers);
play = new Thread(() -> this.start());
play.start();
}
public int join(GameJoinRequest request) {
int id = idCounter.getAndIncrement();
requests.offer(request);
return id;
}
private void start() {
this.waitForPlayers();
Log.info("We can start !");
}
private void waitForPlayers() {
Log.info("Waiting for request. Expecting {0} players.", expectedPlayers);
GameJoinRequest request;
while (requests.size() < expectedPlayers.intValue()) {
try {
request = requests.take();
this.handleRequest(request);
} catch (InterruptedException e) {
Log.error(e);
}
}
}
private void handleRequest(GameJoinRequest request) {
}
}
package fr.univnantes.alma.game;
import fr.univnantes.alma.common.GameJoinRequest;
import fr.univnantes.alma.common.GameService;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import static org.atlanmod.commons.Preconditions.checkArgument;
@Component
public class GameServiceController implements GameService {
private final AtomicInteger idCounter = new AtomicInteger(0);
private final Map<Integer, Game> games = new HashMap<>();
@Override
public int createGame(int expectedPlayers) {
checkArgument(expectedPlayers > 1 && expectedPlayers <= 7, "A game must have between 2 and 7 players");
int newId = idCounter.incrementAndGet();
Game newGame = new Game(expectedPlayers);
games.put(newId, newGame);
return newId;
}
@Override
public int join(int gameId, GameJoinRequest request) {
Game game = games.get(gameId);
return game.join(request);
}
}
package fr.univnantes.alma.handler;
import fr.univnantes.alma.common.GameJoinRequest;
import fr.univnantes.alma.thrift.GameNotFound;
import fr.univnantes.alma.thrift.GameServerService;
import fr.univnantes.alma.thrift.JoinRequest;
import fr.univnantes.alma.common.GameService;
import org.apache.thrift.TException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class GameServiceHandler implements GameServerService.Iface {
@Autowired
GameService service;
@Override
public int createGame(int numberOfPlayers) throws TException {
return service.createGame(numberOfPlayers);
}