Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Joseph NISON--GUYON
Not Alone
Commits
d2e991fd
Commit
d2e991fd
authored
Nov 17, 2020
by
Gerson Sunyé
Browse files
Initial implementation of Game component
parent
0b04889a
Changes
14
Hide whitespace changes
Inline
Side-by-side
not-alone-core/src/main/thrift/common.thrift
View file @
d2e991fd
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
}
not-alone-core/src/main/thrift/game-client.thrift
View file @
d2e991fd
include "common.thrift"
namespace java fr.univnantes.alma.thrift
service GameClientService {
bool ping() throws (1:common.InvalidOperationException e)
}
not-alone-core/src/main/thrift/game-server.thrift
View file @
d2e991fd
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),
i32 createGame(i32 numberOfPlayers)
list <CrossPlatformResource> getLi
st
(
) throws (1:common.
InvalidOperationException
e)
,
i32 join(i32 gameId, JoinRequest reque
st) throws (1:common.
GameNotFound
e)
bool ping() throws (1:common.InvalidOperationException
e)
void start(i32 gameId) throws (1:common.GameNotFound
e)
}
not-alone-doc/src/doc/asciidoc/_sections/composants.adoc
View file @
d2e991fd
= Conception préliminaire
== Création d'une partie
.Join game
[plantuml]
....
participant "__one:Player__" as player1
participant "__two:Player__" as player2
participant "__three:Player__" as player3
participant "__four:Player__" as player4
participant "__five:Player__" as player5
participant "__six:Player__" as player6
participant "__game:GameServer__" as game
player1 -> game : id := createGame(6)
par
player1 -> game : playerId := join(id, one)
player2 -> game : playerId := join(id, two)
player3 -> game : playerId := join(id, three)
player4 -> game : playerId := join(id, four)
player5 -> game : playerId := join(id, five)
player6 -> game : playerId := join(id, six)
end
game -> game : start()
....
.Questions ouveres (à faire)
- Les joeurs ne peuvent pas envcoyer juste une `id`, ils doivent aussi envoyer une adress/port pour que le serveur puisse les contacter
- Le serveur doit prévenir les joueurs du début de la partie.
.L'interface GameServer
[plantuml]
....
interface GameServer {
createGame(numberOfPlayers : Integer): Integer
join(gameId : Integer): Integer
satrt()
}
....
not-alone-doc/src/doc/asciidoc/_sections/conception.adoc
View file @
d2e991fd
=
Conception
d
é
taill
é
e
==
Game
Server
.
GameSever
[
plantuml
]
....
interface
GameServer
{
createGame
(
numberOfPlayers
:
Integer
):
Integer
join
(
gameId
:
Integer
):
Integer
start
()
}
package
game
{
class
"GameServerController"
as
controller
{
createGame
(
numberOfPlayers
:
Integer
):
Integer
join
(
gameId
:
Integer
):
Integer
start
()
}
class
"Game"
as
game
{
id
:
Integer
{
id
}
numberOfPlayers
:
Integer
}
class
"Player"
as
player
{
id
:
Integer
{
id
}
}
GameServer
<|--
controller
controller
*-
"[*] games"
game
:
\
t
\
t
\
t
controller
*--
"[0..7] players"
player
}
note
right
of
game
:
Uncompleted
!
....
[
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
GameServerController
::
start
()
{
start
while
(
enough
players
?)
:
JoinRequest
<
:
handleRequest
();
endwhile
:
Game
Start
>
stop
}
----
not-alone-server/not-alone-server.iml
deleted
100644 → 0
View file @
0b04889a
<?xml version="1.0" encoding="UTF-8"?>
<module
version=
"4"
>
<component
name=
"CheckStyle-IDEA-Module"
>
<option
name=
"configuration"
>
<map
/>
</option>
</component>
</module>
\ No newline at end of file
not-alone-server/pom.xml
View file @
d2e991fd
<?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>
...
...
@@ -21,21 +21,32 @@
</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>
...
...
not-alone-server/src/main/java/fr/univnantes/alma/NotAloneApplication.java
View file @
d2e991fd
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"
);
}
}
not-alone-server/src/main/java/fr/univnantes/alma/common/GameJoinRequest.java
0 → 100644
View file @
d2e991fd
package
fr.univnantes.alma.common
;
public
class
GameJoinRequest
{
}
not-alone-server/src/main/java/fr/univnantes/alma/common/GameService.java
0 → 100644
View file @
d2e991fd
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
);
void
start
(
int
gameId
)
throws
InterruptedException
;
}
not-alone-server/src/main/java/fr/univnantes/alma/game/Game.java
0 → 100644
View file @
d2e991fd
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
;
public
Game
(
int
expectedPlayers
)
{
this
.
expectedPlayers
=
new
AtomicInteger
(
expectedPlayers
);
this
.
requests
=
new
ArrayBlockingQueue
<
GameJoinRequest
>(
expectedPlayers
);
}
public
int
join
(
GameJoinRequest
request
)
{
int
id
=
idCounter
.
getAndIncrement
();
requests
.
offer
(
request
);
return
id
;
}
public
void
start
()
{
Thread
t
=
new
Thread
(()
->
{
this
.
waitForPlayers
();
Log
.
info
(
"We can start !"
);
}
);
t
.
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
)
{
}
}
not-alone-server/src/main/java/fr/univnantes/alma/game/GameServiceController.java
0 → 100644
View file @
d2e991fd
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
);
}
@Override
public
void
start
(
int
gameId
)
throws
InterruptedException
{
Game
game
=
games
.
get
(
gameId
);
game
.
start
();
}
}
not-alone-server/src/main/java/fr/univnantes/alma/handler/GameServiceHandler.java
0 → 100644
View file @
d2e991fd
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
);
}
@Override
public
int
join
(
int
gameId
,
JoinRequest
request
)
throws
TException
{
return
service
.
join
(
gameId
,
new
GameJoinRequest
());
}
@Override
public
void
start
(
int
gameId
)
throws
GameNotFound
,
TException
{
try
{
service
.
start
(
gameId
);
}
catch
(
InterruptedException
e
)
{
throw
new
GameNotFound
();
}
}
}
not-alone-server/src/test/java/fr/univnantes/alma/NotAloneApplicationTest.java
0 → 100644
View file @
d2e991fd
package
fr.univnantes.alma
;
import
fr.univnantes.alma.thrift.GameServerService
;
import
fr.univnantes.alma.thrift.JoinRequest
;
import
org.apache.thrift.TException
;
import
org.apache.thrift.protocol.TProtocol
;
import
org.apache.thrift.protocol.TProtocolFactory
;
import
org.apache.thrift.transport.THttpClient
;
import
org.apache.thrift.transport.TTransport
;
import
org.junit.jupiter.api.BeforeEach
;
import
org.junit.jupiter.api.Test
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.boot.web.server.LocalServerPort
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
@SpringBootTest
(
webEnvironment
=
SpringBootTest
.
WebEnvironment
.
RANDOM_PORT
,
classes
=
NotAloneApplication
.
class
)
class
NotAloneApplicationTest
{
@Autowired
protected
TProtocolFactory
protocolFactory
;
@LocalServerPort
protected
int
port
;
protected
GameServerService
.
Iface
client
;
@BeforeEach
public
void
setUp
()
throws
Exception
{
TTransport
transport
=
new
THttpClient
(
"http://localhost:"
+
port
+
"/api"
);
TProtocol
protocol
=
protocolFactory
.
getProtocol
(
transport
);
client
=
new
GameServerService
.
Client
(
protocol
);
}
@Test
public
void
testCreateGame
()
throws
TException
{
int
id
=
client
.
createGame
(
4
);
assertThat
(
id
).
isGreaterThan
(
0
);
}
@Test
public
void
testJoinGame
()
throws
TException
,
InterruptedException
{
int
id
=
client
.
createGame
(
4
);
client
.
join
(
id
,
new
JoinRequest
(
"one"
));
client
.
join
(
id
,
new
JoinRequest
(
"two"
));
client
.
join
(
id
,
new
JoinRequest
(
"three"
));
client
.
join
(
id
,
new
JoinRequest
(
"four"
));
client
.
start
(
id
);
Thread
.
sleep
(
1000
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment