Compare commits

...

3 commits

Author SHA1 Message Date
c58c8725e8 Added README 2026-04-24 21:03:48 +02:00
Gu://em_
b3bdec1049 tar dur, jws demotivant 2026-04-04 22:25:16 +02:00
Gu://em_
e1301f007b trop tard 2026-04-04 00:01:13 +02:00
19 changed files with 133 additions and 24 deletions

31
README.md Normal file
View file

@ -0,0 +1,31 @@
# JWS
> **Note** This is a school project, therefore it probably won't interest you if you are looking for something useful.
## Overview
JWS stands for Java Web Services and as its name doesn't suggest at all, it's basically a web server for a a pokemon-like game. It's written in Java and built onto Quarkus and Jakarta, providing a REST API with strict server-side rules like cooldowns and cheating prevention.
## Architecture
> **Note** Source code is located inside the `yakamon` folder, both others are school requirements and aren't important
Each layer is strictly separated and can only communicate via to the one directly below or above it via converters.
### Presentation Layer (REST & DTOs)
* located at `yakamon/jws/yakamon/src/main/java/fr/epita/assistants/yakamon/presentation`
* Handled by JAX-RS (Jakarta RESTful Web Services).
* Exposes standard HTTP endpoints (`/player`, `/move`, `/yakadex`, etc.). Full API specification can be found inside `yakamon/src/main/resources/openapi.yaml`
* Implements strict **Data Transfer Objects (DTOs)** for both Requests and Responses to ensure the internal database models are never exposed directly to the client.
### Business Logic Layer (Services)
* located at `yakamon/jws/yakamon/src/main/java/fr/epita/assistants/yakamon/domain`
* Acts as the brain of the application.
* Implements complex game rules: validating if a target tile is walkable based on the terrain type, calculating cooldowns between moves, and managing creature capture probabilities.
* **Converters** are used to translate Entities from the Data Layer into DTOs for the Presentation Layer.
### Data Access Layer (Hibernate ORM)
* located at `yakamon/jws/yakamon/src/main/java/fr/epita/assistants/yakamon/data`
* Manages persistence using **Hibernate ORM** with the Active Record / Repository pattern.
* Defines relational entities (Player, Game, Yakamon, Item) mapped to a PostgreSQL database.

View file

@ -9,10 +9,34 @@ public class ItemModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Integer id;
private Integer id;
@Enumerated
public ItemType type;
private ItemType type;
public Integer quantity;
private Integer quantity;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public ItemType getType() {
return type;
}
public void setType(ItemType type) {
this.type = type;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
}

View file

@ -59,8 +59,8 @@ public class GameService {
// Initialize player inventory
ItemModel yakaballs = new ItemModel();
yakaballs.type = ItemType.YAKABALL;
yakaballs.quantity = 5;
yakaballs.setType(ItemType.YAKABALL);
yakaballs.setQuantity(5);
// Store
playerRepository.persist(player);

View file

@ -145,7 +145,7 @@ public class PlayerService {
ItemModel yakaballItem = itemRepository
.find("type", ItemType.YAKABALL)
.firstResult();
if (yakaballItem == null || yakaballItem.quantity < 1) {
if (yakaballItem == null || yakaballItem.getQuantity() < 1) {
throw new WebApplicationException(
Response.status(400).entity("Not enough Yakaballs").build()
);
@ -170,7 +170,7 @@ public class PlayerService {
ErrorCode.BAD_REQUEST.throwException("Yakamon species not found");
}
yakaballItem.quantity -= 1;
yakaballItem.setQuantity(yakaballItem.getQuantity() - 1);
itemRepository.persist(yakaballItem);
YakamonModel newYakamon = new YakamonModel();
@ -342,11 +342,11 @@ public class PlayerService {
.firstResult();
if (item == null) {
item = new ItemModel();
item.type = itemType;
item.quantity = 1;
item.setType(itemType);
item.setQuantity(1);
itemRepository.persist(item);
} else {
item.quantity += 1;
item.setQuantity(item.getQuantity() + 1);
itemRepository.persist(item);
}
}

View file

@ -1,7 +1,9 @@
package fr.epita.assistants.yakamon.presentation.api;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
public class YakamonAction {

View file

@ -1,7 +1,9 @@
package fr.epita.assistants.yakamon.presentation.api.request;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
public class StartGameRequest {

View file

@ -1,8 +1,10 @@
package fr.epita.assistants.yakamon.presentation.api.request;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
public class TeamFeedRequest {
public Integer quantity;

View file

@ -1,8 +1,10 @@
package fr.epita.assistants.yakamon.presentation.api.request;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
public class TeamRenameRequest {
public String newNickname;

View file

@ -2,21 +2,37 @@ package fr.epita.assistants.yakamon.presentation.api.response;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
public class GetInventoryResponse {
public class ItemType {
public String type;
public String value;
public ItemType() {}
public ItemType(String type, String value) {
this.type = type;
this.value = value;
}
}
public class Items {
public ItemType itemType;
public Integer quantity;
public Items() {}
public Items(ItemType itemType, Integer quantity) {
this.itemType = itemType;
this.quantity = quantity;
}
}
List<Items> items;
public List<Items> items;
}

View file

@ -1,7 +1,9 @@
package fr.epita.assistants.yakamon.presentation.api.response;
import fr.epita.assistants.yakamon.presentation.api.YakamonAction;
import lombok.NoArgsConstructor;
@NoArgsConstructor
public class PlayerCatchResponse extends YakamonAction {
public PlayerCatchResponse(

View file

@ -3,20 +3,36 @@ package fr.epita.assistants.yakamon.presentation.api.response;
import fr.epita.assistants.yakamon.utils.tile.ItemType;
import fr.epita.assistants.yakamon.utils.tile.TerrainType;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
public class PlayerCollectResponse {
public class TileType {
public class Collectible {
ItemType type;
String value;
public ItemType type;
public String value;
public Collectible() {}
public Collectible(ItemType type, String value) {
this.type = type;
this.value = value;
}
}
TerrainType terrainType;
Collectible collectible;
public TerrainType terrainType;
public Collectible collectible;
public TileType() {}
public TileType(TerrainType terrainType, Collectible collectible) {
this.terrainType = terrainType;
this.collectible = collectible;
}
}
public TileType tileType;

View file

@ -1,7 +1,9 @@
package fr.epita.assistants.yakamon.presentation.api.response;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
public class PlayerInfosResponse {
@ -10,7 +12,7 @@ public class PlayerInfosResponse {
public Integer posX;
public Integer posY;
public String lastMove;
public String lastCatch;
public String lastCollect;
public String lastCatch;
public String lastFeed;
}

View file

@ -1,7 +1,9 @@
package fr.epita.assistants.yakamon.presentation.api.response;
import fr.epita.assistants.yakamon.presentation.api.YakamonAction;
import lombok.NoArgsConstructor;
@NoArgsConstructor
public class TeamEvolveResponse extends YakamonAction {
public TeamEvolveResponse(

View file

@ -1,7 +1,9 @@
package fr.epita.assistants.yakamon.presentation.api.response;
import fr.epita.assistants.yakamon.presentation.api.YakamonAction;
import lombok.NoArgsConstructor;
@NoArgsConstructor
public class TeamFeedResponse extends YakamonAction {
public TeamFeedResponse(

View file

@ -2,9 +2,11 @@ package fr.epita.assistants.yakamon.presentation.api.response;
import fr.epita.assistants.yakamon.presentation.api.YakamonAction;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
public class TeamInfosResponse {
YakamonAction[] yakamons;
public YakamonAction[] yakamons;
}

View file

@ -1,7 +1,9 @@
package fr.epita.assistants.yakamon.presentation.api.response;
import fr.epita.assistants.yakamon.presentation.api.YakamonAction;
import lombok.NoArgsConstructor;
@NoArgsConstructor
public class TeamRenameResponse extends YakamonAction {
public TeamRenameResponse(

View file

@ -2,9 +2,11 @@ package fr.epita.assistants.yakamon.presentation.api.response;
import fr.epita.assistants.yakamon.presentation.api.YakadexEntry;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
public class YakadexAllInfosResponse {
YakadexEntry[] entries;
public YakadexEntry[] entries;
}

View file

@ -41,10 +41,10 @@ public class InventoryResource {
for (ItemModel item : items) {
GetInventoryResponse.Items responseItem = temp.new Items();
GetInventoryResponse.ItemType itemType = temp.new ItemType();
itemType.type = item.type.name();
itemType.value = item.type.name();
itemType.type = item.getType().name();
itemType.value = item.getType().name();
responseItem.itemType = itemType;
responseItem.quantity = item.quantity;
responseItem.quantity = item.getQuantity();
responseItems.add(responseItem);
}

View file

@ -123,12 +123,12 @@ public class PlayerResource {
player.lastMove != null
? player.lastMove.format(formatter)
: null,
player.lastCatch != null
? player.lastCatch.format(formatter)
: null,
player.lastCollect != null
? player.lastCollect.format(formatter)
: null,
player.lastCatch != null
? player.lastCatch.format(formatter)
: null,
player.lastFeed != null
? player.lastFeed.format(formatter)
: null