Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Anthony ROZEN
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
Supports
Markdown
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