Read the JavaDoc
at: https://s-schizophrene-trio.github.io/yatzi/
- Install
Gradle 5.3.1+
- Install
JDK 11.0.2
- Download
JavaFX 11
- Download
SDK Version 11
at https://gluonhq.com/products/javafx/ https://openjfx.io/openjfx-docs/#gradle -> JavaFX and IntelliJ -> Non-modular with Gradle
Settings->Compiler->Annotation Processors
[enable]- Install
lombok plugin
from marketplace to your idea. (restart)
If you get this Error Message in IntelliJ...
Error: JavaFX runtime components are missing, and are required to run this application
You have to set some VM Options
--module-path /path/to/your/javafx-sdk-11.0.2/lib --add-modules=javafx.controls,javafx.fxml
MainController
is used to build, load and display a view. He is also used to initialize the board logic.
ScreenType
is an enum with all available Screens. Each ScreenType
has to be implemented in the loadScreen
method
of the MainController
Type | Description |
---|---|
BOARD | The board view is the main view used for the yatzi game. |
SETUP | The setup view is used to initialize the game mode. The User can join or create a server. |
STATUS | The status bar will be added on each view and can be access from each controller. |
The YatziApplication
, an instance of javafx.application.Application
creates a global ch.juventus.yatzi.ui.models.FXContext
which holds the
main stage and the game instance of the application. The context will be accessed over the ViewContext
interface.
The context instance will be shared with the MainController
. This is necessary to adapt the window-size
and other global attributes. Each ScreenController
holds also an instance of the ViewContext
. This means every
component has access to global ViewContext
and its child values.
The ScreenHelper
class can be loaded by a javaFX class and have access to the main stage.
- https://icons8.de/icon/set/server/ios
- https://icons8.de/icon/25226/verbunden
- http://www.holshousersoftware.com/glass
If you want to load an image from resource folder inside a ScreenController
, use following methods.
// @param classloader The classloader of the context to access ressources
// @param subPath The sub-path in the base image folder eg. "icons/"
// @param key filename (lowercase)
// @param fileExt file ending eg. "png"
// @return A String with the relative image path
screenHelper.getImage(classloader, subpath, imageKey, fileExt)
//sample:
Image image1 = screenHelper.getImage(this.context.getClassloader(), "background/", "board_background", "jpg");
// render a image view based on this image:
ImageView imageView1 = screenHelper.renderImageView(context.getClassloader(), "icons/", "server", "png")
ImageView imageView1 = screenHelper.renderImageView(context.getClassloader(), "icons/", "server", "png", 200, 200)
Logs
------------------------------------------------------------------
* all characters should be written in lowercase
* LOGGER.debug("application started in {}ms", elapsedTime);
Comments
------------------------------------------------------------------
// the whole comment should be written in lowercase
JavaDoc
------------------------------------------------------------------
/**
* Describes the funcionality of the method.
* @param param1 Each Text should start with a Uppercase Character
* @param param2 Each Parameter has to be described
* @return Describes the Return Value
*/
public String testMethod(String param1, String param2) {
return new String("test-string");
}
The Yatzi Game is a full instance of a game. This Object can be used on multiple clients. The communication between message handlers, allows the developer to to make async calls.
The Board represents the play ground of this game. The board knows all users and the state of the game.
By definition, a socket is one endpoint of a two-way communication link between two programs running on different computers on a network. A socket is bound to a port number so that the transport layer can identify the application that data is destined to be sent to.
Sources
+---------------------------------------------------+
| |
| Player 1 (Host) |
| |
| +-----------------+ |
| +-----> | Message Handler | <-------------+ |
| | +-----------------+ | |
| | | |
| | +------------+ +---+--+ |
| | +-----------> | Client +----> | CT 1 | |
| | | +------------+ +------+ |
| ++---+---+ X | +-------------------------------------------+
| | Game | TCP | | |
| ++---+---+ X | | Player 2 |
| | | +------------+ +------+ | | |
| | +-----------> | Server +----> | CH 1 | | | +-----------------+ |
| | +------------+ +--+---- | | +---------> | Message Handler | |
| | | | | | +---------------+-+ |
| | +-----------------------+ | | | ^ |
| | | | | | | |
| | | +------+ | | +---+--+ +--------+ +-+----+ |
| | | +-----------------+ CH 2 |XX|XXXX_TCP_X|XXX| CT 1 | <---+ Client | <-----+ Game | |
| | | | +------+ | | +------+ +--------+ +------+ |
| | | | | | |
| | | | | +-------------------------------------------+
| | | | |
| | v v | +-------------------------------------------+
| | | | |
| | +-----------------+ +------+ | | +------+ +--------+ +------+ |
| +------> | Message Handler | <--------+ CH n |XX|XXX_TCP_XX|XX| CT 1 | <---+ Client | <-----+ Game | |
| +-----------------+ +------+ | | +---+--+ +--------+ +-+----+ |
| | | | | |
+---------------------------------------------------+ | | v |
| | +---------------+-+ |
| +---------> | Message Handler | |
| +-----------------+ |
| |
| |
| Player n |
CT = Client Task | |
CH = Client Handler +-------------------------------------------+
The Server holds all client handlers
, and handles all messages bundled to one message handler
.
Each new client will effect in a new client handler
thread.
The Client connects to a server socket
and will be a member or player of the game.
The client
crates a new task to handle the server <-> client
connection.
Attribute | Type | Description |
---|---|---|
Sender | UUID | UUID of the sender user / client. The server does not need to provide the Sender ID. |
Function | String | Defines the reason for this network transfer. |
Body | String | The needed Model translated to a JSON String |
Sent Time | Date | Time when the transfer object was sent to the network. |
Command | Description | Body |
---|---|---|
PLAYER_NEW | A new player will join the the game. | User |
MAX_PLAYERS_REACHED | The maximum of clients is reached. | - |
WAIT_FOR_GAME_READY | The server is waiting for new players to join. | - |
GAME_READY | The server has started the game. | - |
CLIENT_READY | The client is ready to start a new game. | - |
DICE_CHANGED | The dice set has been changed. | Dice[] |
ROUND_START | Starts a new round of the game. | YatziGame |
GAME_CHANGED | The game has been changed. (includes the currently active user) | YatziGame |
PLAYER_EXIT | A player leaves the game early. | User Id |
GAME_END | The game is finished. The user can exit the game or start a new party. | - |
The transfer body can hold every content as String. We use Json to transfer the body. A sample of our game_changed
event.
{
"board":{
"scores":{
"f27955ce-6a24-44a8-8dfa-e010e0e08982":{
"TOTAL":{
"fieldType":"TOTAL",
"value":9,
"isCalculated":true
},
"SUB_TOTAL":{
"fieldType":"SUB_TOTAL",
"value":9,
"isCalculated":true
},
"THREES":{
"fieldType":"THREES",
"value":3,
"isCalculated":false
},
"BONUS":{
"fieldType":"BONUS",
"value":0,
"isCalculated":true
},
"TWOS":{
"fieldType":"TWOS",
"value":6,
"isCalculated":false
}
},
"efe1402d-2eb2-4570-b724-f9ce257a29a9":{
"FOURS":{
"fieldType":"FOURS",
"value":4,
"isCalculated":false
},
"SUB_TOTAL":{
"fieldType":"SUB_TOTAL",
"value":4,
"isCalculated":true
},
"TOTAL":{
"fieldType":"TOTAL",
"value":4,
"isCalculated":true
},
"BONUS":{
"fieldType":"BONUS",
"value":0,
"isCalculated":true
}
}
}
},
"activeUserId":"efe1402d-2eb2-4570-b724-f9ce257a29a9",
"circleRoundPlayed":[
"efe1402d-2eb2-4570-b724-f9ce257a29a9"
],
"players":[
{
"userId":"f27955ce-6a24-44a8-8dfa-e010e0e08982",
"userName":"client",
"serveType":"CLIENT"
},
{
"userId":"efe1402d-2eb2-4570-b724-f9ce257a29a9",
"userName":"server",
"serveType":"SERVER"
}
]
}
Each client opens a new connection to the server. The server tries to keep alive these connections. This is needed to prevent latency during game play due of connection establishing.
This Yatzi Game (Host) is able to manage multiple Clients (max 7). To make this possible, the Server creates for each incoming Client a new Client Handler Thread.
https://cdncontribute.geeksforgeeks.org/wp-content/uploads/JavaSocketProgramming.png
Library: http://owner.aeonbits.org/docs/usage/
use the application.properties
file in src/main/resources/config
to configure the game parameters.
Each configuration property needs a method in the Config Interface in src/main/java/ch/juventus/yatzi/config
/**
* Timeout in seconds the client should wait until the timeout exceeded
* @return The client timeout as counter
*/
@DefaultValue("30")
@Key("client.connection.timeout")
int clientTimeout();
This project has its own javadoc theme. Use this theme for the docs assets. Add these java vm options to your start command.
-encoding UTF-8 -docencoding utf-8 -charset utf-8 -stylesheetfile /path/to/your/yatzi/javadoc-style.css
The Junit5 tests can be executed by ./gradlew clean test
$ docker-compose up
$ ./gradlew sonarqube \
-Dsonar.host.url=http://localhost:9000 \
-Dsonar.login=<your-token>
Colors
- yatzi-blue: #113f89
- yatzi-gray: #dbdbdb