summaryrefslogtreecommitdiff
path: root/jws/epibazaar
diff options
context:
space:
mode:
Diffstat (limited to 'jws/epibazaar')
-rw-r--r--jws/epibazaar/common/pom.xml114
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/ItemAggregate.java71
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/ResetInventoryAggregate.java12
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/SellItemAggregate.java12
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/SyncInventoryAggregate.java12
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/UpgradeItemProducerAggregate.java10
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/UpgradeShopAggregate.java12
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/request/ItemRequest.java13
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/request/ItemsRequest.java12
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/request/MoveRequest.java11
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/request/StartRequest.java10
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ItemResponse.java13
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ItemsResponse.java12
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/MoveResponse.java11
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/PlayerResponse.java18
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ShopPriceResponse.java10
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ShopResponse.java12
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ShopsResponse.java12
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/StartResponse.java12
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/UpgradeCostResponse.java12
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/CollectItemCommand.java14
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/CreateShopCommand.java10
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/ResetInventoryCommand.java11
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/SellItemCommand.java15
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/SyncInventoryCommand.java11
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/UpgradeCollectRateCommand.java10
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/UpgradeMovementSpeedCommand.java10
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/UpgradeShopPriceCommand.java12
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/UpgradeStaminaCommand.java10
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/utils/Direction.java15
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/utils/ErrorInfo.java10
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/utils/ItemInfo.java20
-rw-r--r--jws/epibazaar/common/src/main/java/fr/epita/assistants/common/utils/Point.java13
-rw-r--r--jws/epibazaar/common/src/main/resources/application.properties3
-rw-r--r--jws/epibazaar/inventory/pom.xml135
-rw-r--r--jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/converter/InventoryConverter.java24
-rw-r--r--jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/data/model/ItemModel.java25
-rw-r--r--jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/data/repository/ItemRepository.java48
-rw-r--r--jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/domain/entity/ItemEntity.java13
-rw-r--r--jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/domain/entity/ItemsEntity.java13
-rw-r--r--jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/domain/service/InventoryService.java59
-rw-r--r--jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/presentation/subscriber/CommandSubscriber.java59
-rw-r--r--jws/epibazaar/inventory/src/main/resources/application.properties11
-rw-r--r--jws/epibazaar/inventory/src/main/resources/db/migration/V1__Init.sql7
-rw-r--r--jws/epibazaar/item-producer/.env7
-rw-r--r--jws/epibazaar/item-producer/pom.xml135
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/converter/ItemProducerConverter.java126
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/model/GameModel.java19
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/model/ItemModel.java28
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/model/PlayerModel.java37
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/repository/GameRepository.java59
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/repository/ItemRepository.java50
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/repository/PlayerRepository.java62
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/GameEntity.java4
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/ItemEntity.java13
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/ItemsEntity.java13
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/MoveEntity.java11
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/PlayerEntity.java18
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/StartEntity.java11
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/UpgradeCostEntity.java12
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/service/ErwenService.java4
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/service/ItemProducerService.java199
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/presentation/rest/HelloWorldResource.java19
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/presentation/rest/ItemProducerResource.java154
-rw-r--r--jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/presentation/subscriber/AggregateSubscriber.java47
-rw-r--r--jws/epibazaar/item-producer/src/main/resources/application.properties13
-rw-r--r--jws/epibazaar/item-producer/src/main/resources/db/migration/V1__Init.sql25
-rw-r--r--jws/epibazaar/item-producer/src/main/resources/maps/custom.epimap16
-rw-r--r--jws/epibazaar/item-producer/src/main/resources/maps/huge.epimap30
-rw-r--r--jws/epibazaar/item-producer/src/main/resources/maps/pretty.epimap16
-rw-r--r--jws/epibazaar/item-producer/src/main/resources/openapi.yaml287
-rw-r--r--jws/epibazaar/pom.xml359
-rw-r--r--jws/epibazaar/shop/.env4
-rw-r--r--jws/epibazaar/shop/pom.xml135
-rw-r--r--jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/converter/ShopConverter.java24
-rw-r--r--jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/data/model/ItemModel.java28
-rw-r--r--jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/data/model/ShopModel.java18
-rw-r--r--jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/data/repository/ItemRepository.java39
-rw-r--r--jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/data/repository/ShopRepository.java30
-rw-r--r--jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/domain/entity/ErwenEntity.java4
-rw-r--r--jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/domain/entity/StartEntity.java9
-rw-r--r--jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/domain/service/ErwenService.java4
-rw-r--r--jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/domain/service/ShopService.java79
-rw-r--r--jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/presentation/rest/HelloWorldResource.java19
-rw-r--r--jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/presentation/rest/ShopResource.java63
-rw-r--r--jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/presentation/subscriber/AggregateSubscriber.java41
-rw-r--r--jws/epibazaar/shop/src/main/resources/application.properties13
-rw-r--r--jws/epibazaar/shop/src/main/resources/db/migration/V1__Init.sql15
-rw-r--r--jws/epibazaar/shop/src/main/resources/openapi.yaml242
-rw-r--r--jws/epibazaar/viewer.tar.gzbin0 -> 1570562 bytes
90 files changed, 3500 insertions, 0 deletions
diff --git a/jws/epibazaar/common/pom.xml b/jws/epibazaar/common/pom.xml
new file mode 100644
index 0000000..c1de2b7
--- /dev/null
+++ b/jws/epibazaar/common/pom.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+ 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>fr.epita.assistants</groupId>
+ <artifactId>epibazaar</artifactId>
+ <version>1.0.0</version>
+ </parent>
+ <artifactId>common</artifactId>
+ <version>1.0.0</version>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifest>
+ <mainClass>fully.qualified.MainClass</mainClass>
+ </manifest>
+ </archive>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-maven-plugin</artifactId>
+ <version>${quarkus.platform.version}</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <goals>
+ <goal>build</goal>
+ <goal>generate-code</goal>
+ <goal>generate-code-tests</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>${compiler-plugin.version}</version>
+ <configuration>
+ <parameters>${maven.compiler.parameters}</parameters>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${versions.maven-surefire-plugin}</version>
+ <configuration>
+ <systemPropertyVariables>
+ <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
+ <maven.home>${maven.home}</maven.home>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <profiles>
+ <profile>
+ <id>fetch-bom</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>io.quarkus.platform</groupId>
+ <artifactId>quarkus-bom-quarkus-platform-properties</artifactId>
+ <version>3.17.5</version>
+ <type>properties</type>
+ </dependency>
+ </dependencies>
+ </profile>
+ <profile>
+ <id>native</id>
+ <activation>
+ <property>
+ <name>native</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>${versions.maven-surefire-plugin}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <systemPropertyVariables>
+ <native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
+ <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
+ <maven.home>${maven.home}</maven.home>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <properties>
+ <quarkus.package.type>native</quarkus.package.type>
+ </properties>
+ </profile>
+ </profiles>
+</project>
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/ItemAggregate.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/ItemAggregate.java
new file mode 100644
index 0000000..2c21136
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/ItemAggregate.java
@@ -0,0 +1,71 @@
+package fr.epita.assistants.common.aggregate;
+
+import fr.epita.assistants.common.utils.ItemInfo;
+import io.smallrye.common.constraint.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Value;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Value
+public class ItemAggregate {
+ @NotNull
+ public ResourceType type;
+ @NotNull
+ public Float quantity;
+ @Getter
+ @AllArgsConstructor
+ public enum ResourceType {
+ MONEY(new ItemInfo()
+ .withCollectable(false)
+ .withWalkable(false)
+ .withCollectQuantity(0)
+ .withPrice(null)
+ .withValue('M')
+ ),
+ GROUND(new ItemInfo()
+ .withCollectable(false)
+ .withWalkable(true)
+ .withCollectQuantity(0)
+ .withPrice(null)
+ .withValue('G')
+ ),
+ WATER(new ItemInfo()
+ .withCollectable(false)
+ .withWalkable(false)
+ .withCollectQuantity(0)
+ .withPrice(null)
+ .withValue('O')
+ ),
+ ROCK(new ItemInfo()
+ .withCollectable(true)
+ .withWalkable(true)
+ .withCollectQuantity(3)
+ .withPrice(3f)
+ .withValue('R')
+ ),
+ WOOD(new ItemInfo()
+ .withCollectable(true)
+ .withWalkable(true)
+ .withCollectQuantity(5)
+ .withPrice(2f)
+ .withValue('W')
+ );
+
+ private static final Map<Character, ResourceType> lookup = new HashMap<>();
+
+ static {
+ for (ResourceType entity : ResourceType.values()) {
+ lookup.put(entity.getItemInfo().getValue(), entity);
+ }
+ }
+
+ private final ItemInfo itemInfo;
+
+ public static ResourceType getResource(Character c) {
+ return lookup.get(c);
+ }
+ }
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/ResetInventoryAggregate.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/ResetInventoryAggregate.java
new file mode 100644
index 0000000..a044af6
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/ResetInventoryAggregate.java
@@ -0,0 +1,12 @@
+package fr.epita.assistants.common.aggregate;
+
+import io.smallrye.common.constraint.NotNull;
+import lombok.Value;
+
+import java.util.List;
+
+@Value
+public class ResetInventoryAggregate {
+ @NotNull
+ List<ItemAggregate> items;
+} \ No newline at end of file
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/SellItemAggregate.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/SellItemAggregate.java
new file mode 100644
index 0000000..f0d478c
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/SellItemAggregate.java
@@ -0,0 +1,12 @@
+package fr.epita.assistants.common.aggregate;
+
+import io.smallrye.common.constraint.NotNull;
+import lombok.Value;
+
+import java.util.List;
+
+@Value
+public class SellItemAggregate {
+ @NotNull
+ List<ItemAggregate> items;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/SyncInventoryAggregate.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/SyncInventoryAggregate.java
new file mode 100644
index 0000000..1c7e489
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/SyncInventoryAggregate.java
@@ -0,0 +1,12 @@
+package fr.epita.assistants.common.aggregate;
+
+import io.smallrye.common.constraint.NotNull;
+import lombok.Value;
+
+import java.util.List;
+
+@Value
+public class SyncInventoryAggregate {
+ @NotNull
+ List<ItemAggregate> items;
+} \ No newline at end of file
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/UpgradeItemProducerAggregate.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/UpgradeItemProducerAggregate.java
new file mode 100644
index 0000000..c977061
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/UpgradeItemProducerAggregate.java
@@ -0,0 +1,10 @@
+package fr.epita.assistants.common.aggregate;
+
+import io.smallrye.common.constraint.NotNull;
+import lombok.Value;
+
+@Value
+public class UpgradeItemProducerAggregate {
+ @NotNull
+ Float newMoney;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/UpgradeShopAggregate.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/UpgradeShopAggregate.java
new file mode 100644
index 0000000..09aa31c
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/aggregate/UpgradeShopAggregate.java
@@ -0,0 +1,12 @@
+package fr.epita.assistants.common.aggregate;
+
+import io.smallrye.common.constraint.NotNull;
+import lombok.Value;
+
+@Value
+public class UpgradeShopAggregate {
+ @NotNull
+ Integer shopId;
+ @NotNull
+ Float newMoney;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/request/ItemRequest.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/request/ItemRequest.java
new file mode 100644
index 0000000..b84667b
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/request/ItemRequest.java
@@ -0,0 +1,13 @@
+package fr.epita.assistants.common.api.request;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+
+@Getter
+@AllArgsConstructor
+public class ItemRequest {
+ float quantity;
+ ItemAggregate.ResourceType type;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/request/ItemsRequest.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/request/ItemsRequest.java
new file mode 100644
index 0000000..ff873db
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/request/ItemsRequest.java
@@ -0,0 +1,12 @@
+package fr.epita.assistants.common.api.request;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.List;
+
+@Getter
+@AllArgsConstructor
+public class ItemsRequest {
+ List<ItemRequest> itemsRequest;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/request/MoveRequest.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/request/MoveRequest.java
new file mode 100644
index 0000000..745fa2b
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/request/MoveRequest.java
@@ -0,0 +1,11 @@
+package fr.epita.assistants.common.api.request;
+
+import fr.epita.assistants.common.utils.Direction;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class MoveRequest {
+ Direction direction;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/request/StartRequest.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/request/StartRequest.java
new file mode 100644
index 0000000..275cd27
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/request/StartRequest.java
@@ -0,0 +1,10 @@
+package fr.epita.assistants.common.api.request;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class StartRequest {
+ String mapPath;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ItemResponse.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ItemResponse.java
new file mode 100644
index 0000000..f5cfcc0
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ItemResponse.java
@@ -0,0 +1,13 @@
+package fr.epita.assistants.common.api.response;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class ItemResponse {
+ long id;
+ float quantity;
+ ItemAggregate.ResourceType type;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ItemsResponse.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ItemsResponse.java
new file mode 100644
index 0000000..919b4e6
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ItemsResponse.java
@@ -0,0 +1,12 @@
+package fr.epita.assistants.common.api.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.List;
+
+@Getter
+@AllArgsConstructor
+public class ItemsResponse {
+ List<ItemResponse> itemsResponse;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/MoveResponse.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/MoveResponse.java
new file mode 100644
index 0000000..3b7d8cc
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/MoveResponse.java
@@ -0,0 +1,11 @@
+package fr.epita.assistants.common.api.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class MoveResponse {
+ int posX;
+ int posY;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/PlayerResponse.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/PlayerResponse.java
new file mode 100644
index 0000000..b852f27
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/PlayerResponse.java
@@ -0,0 +1,18 @@
+package fr.epita.assistants.common.api.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.time.LocalDateTime;
+
+@Getter
+@AllArgsConstructor
+public class PlayerResponse {
+ int posX;
+ int posY;
+ LocalDateTime lastMove;
+ LocalDateTime lastCollect;
+ float moveSpeedMultiplier;
+ float staminaMultiplier;
+ float collectRateMultiplier;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ShopPriceResponse.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ShopPriceResponse.java
new file mode 100644
index 0000000..59cf22e
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ShopPriceResponse.java
@@ -0,0 +1,10 @@
+package fr.epita.assistants.common.api.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class ShopPriceResponse {
+ float shopPrice;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ShopResponse.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ShopResponse.java
new file mode 100644
index 0000000..c168df5
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ShopResponse.java
@@ -0,0 +1,12 @@
+package fr.epita.assistants.common.api.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class ShopResponse {
+ int id;
+ float priceMultiplier;
+ float upgradePrice;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ShopsResponse.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ShopsResponse.java
new file mode 100644
index 0000000..f2a114b
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/ShopsResponse.java
@@ -0,0 +1,12 @@
+package fr.epita.assistants.common.api.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.List;
+
+@Getter
+@AllArgsConstructor
+public class ShopsResponse {
+ List<ShopResponse> shops;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/StartResponse.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/StartResponse.java
new file mode 100644
index 0000000..463564c
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/StartResponse.java
@@ -0,0 +1,12 @@
+package fr.epita.assistants.common.api.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.List;
+
+@Getter
+@AllArgsConstructor
+public class StartResponse {
+ List<List<String>> map;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/UpgradeCostResponse.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/UpgradeCostResponse.java
new file mode 100644
index 0000000..19557a1
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/api/response/UpgradeCostResponse.java
@@ -0,0 +1,12 @@
+package fr.epita.assistants.common.api.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class UpgradeCostResponse {
+ float upgradeCollectCost;
+ float upgradeMoveCost;
+ float upgradeStaminaCost;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/CollectItemCommand.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/CollectItemCommand.java
new file mode 100644
index 0000000..94752cc
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/CollectItemCommand.java
@@ -0,0 +1,14 @@
+package fr.epita.assistants.common.command;
+
+import io.smallrye.common.constraint.NotNull;
+import lombok.Value;
+
+import static fr.epita.assistants.common.aggregate.ItemAggregate.ResourceType;
+
+@Value
+public class CollectItemCommand {
+ @NotNull
+ ResourceType type;
+ @NotNull
+ Float collectRateMultiplier;
+} \ No newline at end of file
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/CreateShopCommand.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/CreateShopCommand.java
new file mode 100644
index 0000000..f5e56e5
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/CreateShopCommand.java
@@ -0,0 +1,10 @@
+package fr.epita.assistants.common.command;
+
+import io.smallrye.common.constraint.NotNull;
+import lombok.Value;
+
+@Value
+public class CreateShopCommand {
+ @NotNull
+ public Float price;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/ResetInventoryCommand.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/ResetInventoryCommand.java
new file mode 100644
index 0000000..c2bdfc3
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/ResetInventoryCommand.java
@@ -0,0 +1,11 @@
+package fr.epita.assistants.common.command;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
+
+@JsonInclude(NON_NULL)
+public class ResetInventoryCommand {
+ public ResetInventoryCommand() {
+ }
+} \ No newline at end of file
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/SellItemCommand.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/SellItemCommand.java
new file mode 100644
index 0000000..aaa8c0b
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/SellItemCommand.java
@@ -0,0 +1,15 @@
+package fr.epita.assistants.common.command;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import io.smallrye.common.constraint.NotNull;
+import lombok.Value;
+
+import java.util.List;
+
+@Value
+public class SellItemCommand {
+ @NotNull
+ List<ItemAggregate> items;
+ @NotNull
+ Float priceMultiplier;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/SyncInventoryCommand.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/SyncInventoryCommand.java
new file mode 100644
index 0000000..d077093
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/SyncInventoryCommand.java
@@ -0,0 +1,11 @@
+package fr.epita.assistants.common.command;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
+
+@JsonInclude(NON_NULL)
+public class SyncInventoryCommand {
+ public SyncInventoryCommand() {
+ }
+} \ No newline at end of file
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/UpgradeCollectRateCommand.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/UpgradeCollectRateCommand.java
new file mode 100644
index 0000000..de0feaf
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/UpgradeCollectRateCommand.java
@@ -0,0 +1,10 @@
+package fr.epita.assistants.common.command;
+
+import io.smallrye.common.constraint.NotNull;
+import lombok.Value;
+
+@Value
+public class UpgradeCollectRateCommand {
+ @NotNull
+ Float price;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/UpgradeMovementSpeedCommand.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/UpgradeMovementSpeedCommand.java
new file mode 100644
index 0000000..ce3504c
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/UpgradeMovementSpeedCommand.java
@@ -0,0 +1,10 @@
+package fr.epita.assistants.common.command;
+
+import io.smallrye.common.constraint.NotNull;
+import lombok.Value;
+
+@Value
+public class UpgradeMovementSpeedCommand {
+ @NotNull
+ Float price;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/UpgradeShopPriceCommand.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/UpgradeShopPriceCommand.java
new file mode 100644
index 0000000..9fa68a1
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/UpgradeShopPriceCommand.java
@@ -0,0 +1,12 @@
+package fr.epita.assistants.common.command;
+
+import io.smallrye.common.constraint.NotNull;
+import lombok.Value;
+
+@Value
+public class UpgradeShopPriceCommand {
+ @NotNull
+ Integer shopId;
+ @NotNull
+ Float price;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/UpgradeStaminaCommand.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/UpgradeStaminaCommand.java
new file mode 100644
index 0000000..de4fa7e
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/command/UpgradeStaminaCommand.java
@@ -0,0 +1,10 @@
+package fr.epita.assistants.common.command;
+
+import io.smallrye.common.constraint.NotNull;
+import lombok.Value;
+
+@Value
+public class UpgradeStaminaCommand {
+ @NotNull
+ Float price;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/utils/Direction.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/utils/Direction.java
new file mode 100644
index 0000000..815016c
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/utils/Direction.java
@@ -0,0 +1,15 @@
+package fr.epita.assistants.common.utils;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum Direction {
+ UP(new Point(0, -1)),
+ DOWN(new Point(0, 1)),
+ RIGHT(new Point(1, 0)),
+ LEFT(new Point(-1, 0));
+
+ private final Point point;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/utils/ErrorInfo.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/utils/ErrorInfo.java
new file mode 100644
index 0000000..cd1a2d4
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/utils/ErrorInfo.java
@@ -0,0 +1,10 @@
+package fr.epita.assistants.common.utils;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class ErrorInfo {
+ private String message;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/utils/ItemInfo.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/utils/ItemInfo.java
new file mode 100644
index 0000000..02d40fb
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/utils/ItemInfo.java
@@ -0,0 +1,20 @@
+package fr.epita.assistants.common.utils;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.With;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Getter
+@With
+public class ItemInfo {
+ private boolean isCollectable;
+ private boolean isWalkable;
+
+ private char value;
+
+ private int collectQuantity;
+ private Float price;
+}
diff --git a/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/utils/Point.java b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/utils/Point.java
new file mode 100644
index 0000000..f9ebcf8
--- /dev/null
+++ b/jws/epibazaar/common/src/main/java/fr/epita/assistants/common/utils/Point.java
@@ -0,0 +1,13 @@
+package fr.epita.assistants.common.utils;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+@AllArgsConstructor
+@Setter
+@Getter
+public class Point {
+ private int posX;
+ private int posY;
+}
diff --git a/jws/epibazaar/common/src/main/resources/application.properties b/jws/epibazaar/common/src/main/resources/application.properties
new file mode 100644
index 0000000..9db5e48
--- /dev/null
+++ b/jws/epibazaar/common/src/main/resources/application.properties
@@ -0,0 +1,3 @@
+quarkus.devservices.enabled=true
+quarkus.kafka.devservices.image-name=reg.undercloud.cri.epita.fr/docker/redpandadata/redpanda:v24.1.2
+%test.quarkus.devservices.enabled=false
diff --git a/jws/epibazaar/inventory/pom.xml b/jws/epibazaar/inventory/pom.xml
new file mode 100644
index 0000000..b8af7c8
--- /dev/null
+++ b/jws/epibazaar/inventory/pom.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+ 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>fr.epita.assistants</groupId>
+ <artifactId>epibazaar</artifactId>
+ <version>1.0.0</version>
+ </parent>
+
+ <artifactId>inventory</artifactId>
+ <version>1.0.0</version>
+ <dependencies>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-messaging-kafka</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-jdbc-postgresql</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-hibernate-orm-panache</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>fr.epita.assistants</groupId>
+ <artifactId>common</artifactId>
+ <version>1.0.0</version>
+ <scope>compile</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifest>
+ <mainClass>fully.qualified.MainClass</mainClass>
+ </manifest>
+ </archive>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-maven-plugin</artifactId>
+ <version>${quarkus.platform.version}</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <goals>
+ <goal>build</goal>
+ <goal>generate-code</goal>
+ <goal>generate-code-tests</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>${compiler-plugin.version}</version>
+ <configuration>
+ <parameters>${maven.compiler.parameters}</parameters>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${versions.maven-surefire-plugin}</version>
+ <configuration>
+ <systemPropertyVariables>
+ <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
+ <maven.home>${maven.home}</maven.home>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <profiles>
+ <profile>
+ <id>fetch-bom</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>io.quarkus.platform</groupId>
+ <artifactId>quarkus-bom-quarkus-platform-properties</artifactId>
+ <version>3.17.5</version>
+ <type>properties</type>
+ </dependency>
+ </dependencies>
+ </profile>
+ <profile>
+ <id>native</id>
+ <activation>
+ <property>
+ <name>native</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>${versions.maven-surefire-plugin}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <systemPropertyVariables>
+ <native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
+ <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
+ <maven.home>${maven.home}</maven.home>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <properties>
+ <quarkus.package.type>native</quarkus.package.type>
+ </properties>
+ </profile>
+ </profiles>
+</project>
diff --git a/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/converter/InventoryConverter.java b/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/converter/InventoryConverter.java
new file mode 100644
index 0000000..62c7994
--- /dev/null
+++ b/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/converter/InventoryConverter.java
@@ -0,0 +1,24 @@
+package fr.epita.assistants.inventory.converter;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import fr.epita.assistants.common.api.response.ItemResponse;
+import fr.epita.assistants.common.api.response.ItemsResponse;
+import fr.epita.assistants.inventory.data.model.ItemModel;
+import fr.epita.assistants.inventory.domain.entity.ItemEntity;
+import fr.epita.assistants.inventory.domain.entity.ItemsEntity;
+
+public class InventoryConverter {
+ public static ItemAggregate updatedItem(ItemModel item) {
+ return new ItemAggregate(item.getType(), item.getQuantity());
+ }
+
+ public static ItemResponse EntityToResponse(ItemEntity e) {
+ return new ItemResponse(e.getId(), e.getQuantity(), e.getType());
+ }
+
+ public static ItemsResponse EntityToResponse(ItemsEntity e) {
+ if (e == null)
+ return null;
+ return new ItemsResponse(e.getItems().stream().map(InventoryConverter::EntityToResponse).toList());
+ }
+}
diff --git a/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/data/model/ItemModel.java b/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/data/model/ItemModel.java
new file mode 100644
index 0000000..29a182b
--- /dev/null
+++ b/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/data/model/ItemModel.java
@@ -0,0 +1,25 @@
+package fr.epita.assistants.inventory.data.model;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.persistence.*;
+import lombok.*;
+
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@Entity
+@Setter
+@Table(name = "item")
+public class ItemModel {
+ @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
+ Long id;
+ Float quantity;
+ @Enumerated(value = EnumType.STRING)
+ ItemAggregate.ResourceType type;
+
+ public ItemModel(float quantity, ItemAggregate.ResourceType type) {
+ this.quantity = quantity;
+ this.type = type;
+ }
+}
diff --git a/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/data/repository/ItemRepository.java b/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/data/repository/ItemRepository.java
new file mode 100644
index 0000000..129c815
--- /dev/null
+++ b/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/data/repository/ItemRepository.java
@@ -0,0 +1,48 @@
+package fr.epita.assistants.inventory.data.repository;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import fr.epita.assistants.inventory.data.model.ItemModel;
+import io.quarkus.hibernate.orm.panache.PanacheRepository;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.transaction.Transactional;
+
+import java.util.List;
+import java.util.Optional;
+
+@ApplicationScoped
+public class ItemRepository implements PanacheRepository<ItemModel> {
+
+ @Transactional
+ public void clearDB() {
+ deleteAll();
+ }
+
+ @Transactional
+ public List<ItemModel> getItems() {
+ return find("where quantity > 0").stream().toList();
+ }
+
+ @Transactional
+ public Optional<ItemModel> exists(ItemAggregate.ResourceType type) {
+ return find("type = ?1", type).firstResultOptional();
+ }
+
+ @Transactional
+ public ItemModel addItem(ItemAggregate.ResourceType type, Float amount) {
+ ItemModel res = new ItemModel(amount, type);
+ persist(res);
+ return res;
+ }
+
+ // amount should already be the updated amount
+ @Transactional
+ public ItemModel fillInventory(ItemAggregate.ResourceType type, Float amount) {
+ update("quantity = ?1 where type = ?2", amount, type);
+ return new ItemModel(amount, type);
+ }
+
+ @Transactional
+ public List<ItemModel> getMoney() {
+ return find("where type = ?1", ItemAggregate.ResourceType.MONEY).stream().toList();
+ }
+}
diff --git a/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/domain/entity/ItemEntity.java b/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/domain/entity/ItemEntity.java
new file mode 100644
index 0000000..028d09e
--- /dev/null
+++ b/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/domain/entity/ItemEntity.java
@@ -0,0 +1,13 @@
+package fr.epita.assistants.inventory.domain.entity;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class ItemEntity {
+ long id;
+ float quantity;
+ ItemAggregate.ResourceType type;
+}
diff --git a/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/domain/entity/ItemsEntity.java b/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/domain/entity/ItemsEntity.java
new file mode 100644
index 0000000..c0a96ac
--- /dev/null
+++ b/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/domain/entity/ItemsEntity.java
@@ -0,0 +1,13 @@
+package fr.epita.assistants.inventory.domain.entity;
+
+import fr.epita.assistants.inventory.domain.entity.ItemEntity;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.List;
+
+@Getter
+@AllArgsConstructor
+public class ItemsEntity {
+ List<ItemEntity> items;
+}
diff --git a/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/domain/service/InventoryService.java b/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/domain/service/InventoryService.java
new file mode 100644
index 0000000..fc25abf
--- /dev/null
+++ b/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/domain/service/InventoryService.java
@@ -0,0 +1,59 @@
+package fr.epita.assistants.inventory.domain.service;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import fr.epita.assistants.common.aggregate.ResetInventoryAggregate;
+import fr.epita.assistants.common.command.CollectItemCommand;
+import fr.epita.assistants.inventory.converter.InventoryConverter;
+import fr.epita.assistants.inventory.data.model.ItemModel;
+import fr.epita.assistants.inventory.data.repository.ItemRepository;
+import fr.epita.assistants.inventory.domain.entity.ItemEntity;
+import fr.epita.assistants.inventory.domain.entity.ItemsEntity;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+
+import java.util.List;
+import java.util.Optional;
+
+@ApplicationScoped
+public class InventoryService {
+ @Inject
+ ItemRepository itemRepository;
+
+ public ResetInventoryAggregate resetInventory() {
+ ResetInventoryAggregate res =
+ new ResetInventoryAggregate(itemRepository.getItems().stream().map(m -> new ItemAggregate(m.getType()
+ , m.getQuantity())).toList());
+ itemRepository.clearDB();
+ return res;
+ }
+
+ public ItemAggregate collectItem(CollectItemCommand cmd) {
+ Optional<ItemModel> item = itemRepository.exists(cmd.getType());
+ if (item.isPresent()) {
+ ItemModel updated = itemRepository.fillInventory(cmd.getType(),
+ cmd.getCollectRateMultiplier() * cmd.getType().getItemInfo().getCollectQuantity() + item.get().getQuantity());
+ return InventoryConverter.updatedItem(updated);
+ } else {
+ ItemModel newItem = itemRepository.addItem(cmd.getType(),
+ cmd.getCollectRateMultiplier() * cmd.getType().getItemInfo().getCollectQuantity());
+ return InventoryConverter.updatedItem(newItem);
+ }
+ }
+
+ public ItemsEntity getAllItems() {
+ return new ItemsEntity(itemRepository.getItems().stream().map(m -> new ItemEntity(m.getId(),
+ m.getQuantity(), m.getType())).toList());
+ }
+
+ public Double getMoney() {
+ List<ItemModel> entries = itemRepository.getMoney();
+ if (entries.isEmpty())
+ return null;
+ return entries.stream().mapToDouble(m -> m.getQuantity().doubleValue()).sum();
+ }
+
+ public Float pay(Float price) {
+ itemRepository.fillInventory(ItemAggregate.ResourceType.MONEY, getMoney().floatValue() - price);
+ return getMoney().floatValue();
+ }
+}
diff --git a/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/presentation/subscriber/CommandSubscriber.java b/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/presentation/subscriber/CommandSubscriber.java
new file mode 100644
index 0000000..3a95a3a
--- /dev/null
+++ b/jws/epibazaar/inventory/src/main/java/fr/epita/assistants/inventory/presentation/subscriber/CommandSubscriber.java
@@ -0,0 +1,59 @@
+package fr.epita.assistants.inventory.presentation.subscriber;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import fr.epita.assistants.common.aggregate.ResetInventoryAggregate;
+import fr.epita.assistants.common.aggregate.SyncInventoryAggregate;
+import fr.epita.assistants.common.aggregate.UpgradeItemProducerAggregate;
+import fr.epita.assistants.common.command.*;
+import fr.epita.assistants.inventory.domain.service.InventoryService;
+import io.smallrye.reactive.messaging.annotations.Broadcast;
+import jakarta.inject.Inject;
+import org.eclipse.microprofile.reactive.messaging.Incoming;
+import org.eclipse.microprofile.reactive.messaging.Outgoing;
+
+public class CommandSubscriber {
+ @Inject
+ InventoryService inventoryService;
+
+ @Broadcast
+ @Incoming("reset-inventory-command")
+ @Outgoing("reset-inventory-aggregate")
+ public ResetInventoryAggregate commandListener(ResetInventoryCommand cmd) {
+ return inventoryService.resetInventory();
+ }
+
+ @Broadcast
+ @Incoming("collect-item-command")
+ @Outgoing("collect-item-aggregate")
+ public ItemAggregate commandListener(CollectItemCommand cmd) {
+ return inventoryService.collectItem(cmd);
+ }
+
+ @Broadcast
+ @Incoming("sync-inventory-command")
+ @Outgoing("sync-inventory-aggregate")
+ public SyncInventoryAggregate commandListener(SyncInventoryCommand cmd) {
+ return new SyncInventoryAggregate(inventoryService.getAllItems().getItems().stream().map(e -> new ItemAggregate(e.getType(), e.getQuantity())).toList());
+ }
+
+ @Broadcast
+ @Incoming("upgrade-collect-rate-command")
+ @Outgoing("upgrade-collect-rate-aggregate")
+ public UpgradeItemProducerAggregate commandListener(UpgradeCollectRateCommand cmd) {
+ return new UpgradeItemProducerAggregate(inventoryService.pay(cmd.getPrice()));
+ }
+
+ @Broadcast
+ @Incoming("upgrade-movement-speed-command")
+ @Outgoing("upgrade-movement-speed-aggregate")
+ public UpgradeItemProducerAggregate commandListener(UpgradeMovementSpeedCommand cmd) {
+ return new UpgradeItemProducerAggregate(inventoryService.pay(cmd.getPrice()));
+ }
+
+ @Broadcast
+ @Incoming("upgrade-stamina-command")
+ @Outgoing("upgrade-stamina-aggregate")
+ public UpgradeItemProducerAggregate commandListener(UpgradeStaminaCommand cmd) {
+ return new UpgradeItemProducerAggregate(inventoryService.pay(cmd.getPrice()));
+ }
+}
diff --git a/jws/epibazaar/inventory/src/main/resources/application.properties b/jws/epibazaar/inventory/src/main/resources/application.properties
new file mode 100644
index 0000000..fedcdd0
--- /dev/null
+++ b/jws/epibazaar/inventory/src/main/resources/application.properties
@@ -0,0 +1,11 @@
+%dev.quarkus.http.port=8999
+quarkus.datasource.db-kind=postgresql
+quarkus.datasource.username=postgres
+quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/inventory?currentSchema=public
+quarkus.transaction-manager.default-transaction-timeout=3000s
+quarkus.hibernate-orm.log.queries-slower-than-ms=200
+quarkus.hibernate-orm.database.generation=drop-and-create
+
+quarkus.kafka.devservices.image-name=reg.undercloud.cri.epita.fr/docker/redpandadata/redpanda:v24.1.2
+quarkus.devservices.enabled=true
+%test.quarkus.devservices.enabled=false
diff --git a/jws/epibazaar/inventory/src/main/resources/db/migration/V1__Init.sql b/jws/epibazaar/inventory/src/main/resources/db/migration/V1__Init.sql
new file mode 100644
index 0000000..3c1e091
--- /dev/null
+++ b/jws/epibazaar/inventory/src/main/resources/db/migration/V1__Init.sql
@@ -0,0 +1,7 @@
+CREATE TABLE IF NOT EXISTS "item"
+(
+ id SERIAL PRIMARY KEY NOT NULL,
+
+ type VARCHAR(64) NOT NULL,
+ quantity FLOAT NOT NULL
+);
diff --git a/jws/epibazaar/item-producer/.env b/jws/epibazaar/item-producer/.env
new file mode 100644
index 0000000..9b1af1e
--- /dev/null
+++ b/jws/epibazaar/item-producer/.env
@@ -0,0 +1,7 @@
+JWS_TICK_DURATION=100
+JWS_DELAY_COLLECT=3
+JWS_DELAY_MOVEMENT=2
+JWS_UPGRADE_COLLECT_COST=50.0
+JWS_UPGRADE_MOVE_COST=27.5
+JWS_UPGRADE_STAMINA_COST=32.25
+JWS_UPGRADE_MULTIPLIER=1.15 \ No newline at end of file
diff --git a/jws/epibazaar/item-producer/pom.xml b/jws/epibazaar/item-producer/pom.xml
new file mode 100644
index 0000000..bea50b4
--- /dev/null
+++ b/jws/epibazaar/item-producer/pom.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+ 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>fr.epita.assistants</groupId>
+ <artifactId>epibazaar</artifactId>
+ <version>1.0.0</version>
+ </parent>
+
+ <artifactId>item-producer</artifactId>
+ <version>1.0.0</version>
+ <dependencies>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-messaging-kafka</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-jdbc-postgresql</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-hibernate-orm-panache</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>fr.epita.assistants</groupId>
+ <artifactId>common</artifactId>
+ <version>1.0.0</version>
+ <scope>compile</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifest>
+ <mainClass>fully.qualified.MainClass</mainClass>
+ </manifest>
+ </archive>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-maven-plugin</artifactId>
+ <version>${quarkus.platform.version}</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <goals>
+ <goal>build</goal>
+ <goal>generate-code</goal>
+ <goal>generate-code-tests</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>${compiler-plugin.version}</version>
+ <configuration>
+ <parameters>${maven.compiler.parameters}</parameters>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${versions.maven-surefire-plugin}</version>
+ <configuration>
+ <systemPropertyVariables>
+ <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
+ <maven.home>${maven.home}</maven.home>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <profiles>
+ <profile>
+ <id>fetch-bom</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>io.quarkus.platform</groupId>
+ <artifactId>quarkus-bom-quarkus-platform-properties</artifactId>
+ <version>3.17.5</version>
+ <type>properties</type>
+ </dependency>
+ </dependencies>
+ </profile>
+ <profile>
+ <id>native</id>
+ <activation>
+ <property>
+ <name>native</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>${versions.maven-surefire-plugin}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <systemPropertyVariables>
+ <native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
+ <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
+ <maven.home>${maven.home}</maven.home>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <properties>
+ <quarkus.package.type>native</quarkus.package.type>
+ </properties>
+ </profile>
+ </profiles>
+</project>
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/converter/ItemProducerConverter.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/converter/ItemProducerConverter.java
new file mode 100644
index 0000000..cb81247
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/converter/ItemProducerConverter.java
@@ -0,0 +1,126 @@
+package fr.epita.assistants.item_producer.converter;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import fr.epita.assistants.common.aggregate.ResetInventoryAggregate;
+import fr.epita.assistants.common.api.request.StartRequest;
+import fr.epita.assistants.common.api.response.*;
+import fr.epita.assistants.item_producer.data.model.PlayerModel;
+import fr.epita.assistants.item_producer.domain.entity.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ItemProducerConverter {
+ public static StartEntity Start(StartRequest r) {
+ if (r.getMapPath() == null || r.getMapPath().isEmpty())
+ return null;
+ return new StartEntity(r.getMapPath(), null);
+ }
+
+ public static Map<ItemAggregate.ResourceType, Float> DeleteItems(ResetInventoryAggregate items) {
+ Map<ItemAggregate.ResourceType, Float> map = new HashMap<>();
+ for (ItemAggregate i : items.getItems()) {
+ map.merge(i.getType(), i.getQuantity(), Float::sum);
+ }
+ return map;
+ }
+
+ public static MoveEntity Move(PlayerModel playerMove) {
+ return new MoveEntity(playerMove.getPosX(), playerMove.getPosY());
+ }
+
+ public static List<List<String>> RLEtoMap(String rle) {
+ List<String> lines = List.of(rle.split(";"));
+ List<List<String>> map = new ArrayList<>();
+ for (int k = 0; k < lines.size(); k++) {
+ map.add(new ArrayList<>());
+ for (int i = 0; i < lines.get(k).length(); i++) {
+ for (int j = 0; j < lines.get(k).charAt(i) - '0'; j++) {
+ String type = ItemAggregate.ResourceType.getResource(lines.get(k).charAt(i + 1)).toString();
+ map.get(k).add(type);
+ }
+ i++;
+ }
+ }
+ return map;
+ }
+
+ public static String MapToRLE(List<List<String>> map) {
+ List<String> rows = new ArrayList<>();
+ for (List<String> resourceRow : map) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < resourceRow.size(); i++) {
+ int j;
+ // count sequence of this resource type
+ String s = resourceRow.get(i);
+ for (j = i; j < resourceRow.size() && s.equals(resourceRow.get(j)); j++) {
+ continue;
+ }
+ int tmp = j;
+ j -= i;
+ i = tmp - 1;
+ while (j > 9) {
+ sb.append('9');
+ sb.append(ItemAggregate.ResourceType.valueOf(s).getItemInfo().getValue());
+ j -= 9;
+ }
+ if (j > 0) {
+ sb.append(j);
+ sb.append(ItemAggregate.ResourceType.valueOf(s).getItemInfo().getValue());
+ }
+ }
+ rows.add(sb.toString());
+ }
+ return String.join(";", rows);
+ }
+
+ public static StartEntity Collect(String resource) {
+ List<List<String>> map = new ArrayList<>();
+ map.add(new ArrayList<>());
+ map.getFirst().add(resource);
+ return new StartEntity(null, MapToRLE(map));
+ }
+
+ public static PlayerEntity ResponseToEntity(PlayerResponse r) {
+ return new PlayerEntity(r.getPosX(), r.getPosY(), r.getLastMove(), r.getLastCollect(),
+ r.getMoveSpeedMultiplier(), r.getStaminaMultiplier(), r.getCollectRateMultiplier());
+ }
+
+ public static StartEntity ResponseToEntity(StartResponse r) {
+ return new StartEntity(null, MapToRLE(r.getMap()));
+ }
+
+ public static StartResponse EntityToResponse(StartEntity e) {
+ if (e == null)
+ return null;
+ return new StartResponse(RLEtoMap(e.getRle()));
+ }
+ public static ItemResponse EntityToResponse(ItemEntity e) {
+ return new ItemResponse(e.getId(), e.getQuantity(), e.getType());
+ }
+
+ public static ItemsResponse EntityToResponse(ItemsEntity e) {
+ if (e == null)
+ return null;
+ return new ItemsResponse(e.getItems().stream().map(ItemProducerConverter::EntityToResponse).toList());
+ }
+
+ public static PlayerResponse EntityToResponse(PlayerEntity e) {
+ if (e == null)
+ return null;
+ return new PlayerResponse(e.getPosX(), e.getPosY(), e.getLastMove(), e.getLastCollect(),
+ e.getMoveSpeedMultiplier(), e.getStaminaMultiplier(), e.getCollectRateMultiplier());
+ }
+
+ public static MoveResponse EntityToResponse(MoveEntity e) {
+ if (e == null)
+ return null;
+ return new MoveResponse(e.getPosX(), e.getPosY());
+ }
+
+ public static UpgradeCostResponse EntityToResponse(UpgradeCostEntity e) {
+ return null;
+ }
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/model/GameModel.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/model/GameModel.java
new file mode 100644
index 0000000..7cca88c
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/model/GameModel.java
@@ -0,0 +1,19 @@
+package fr.epita.assistants.item_producer.data.model;
+
+import jakarta.persistence.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Entity
+@Setter
+@Table(name = "game")
+public class GameModel {
+ @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
+ Long id;
+ String map;
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/model/ItemModel.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/model/ItemModel.java
new file mode 100644
index 0000000..68d765a
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/model/ItemModel.java
@@ -0,0 +1,28 @@
+package fr.epita.assistants.item_producer.data.model;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import jakarta.persistence.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Entity
+@Setter
+@Table(name = "item")
+public class ItemModel {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ Long id;
+ @Enumerated(value = EnumType.STRING)
+ ItemAggregate.ResourceType type;
+ Float quantity;
+
+ public ItemModel(float quantity, ItemAggregate.ResourceType type) {
+ this.quantity = quantity;
+ this.type = type;
+ }
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/model/PlayerModel.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/model/PlayerModel.java
new file mode 100644
index 0000000..943b5a3
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/model/PlayerModel.java
@@ -0,0 +1,37 @@
+package fr.epita.assistants.item_producer.data.model;
+
+import jakarta.persistence.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.time.LocalDateTime;
+
+@Getter
+@Setter
+@Entity
+@AllArgsConstructor
+@NoArgsConstructor
+@Table(name = "player")
+public class PlayerModel {
+ Float collectRateMultiplier;
+ Float moveSpeedMultiplier;
+ Integer posX;
+ Integer posY;
+ Float staminaMultiplier;
+ LocalDateTime lastCollect;
+ LocalDateTime lastMove;
+ @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
+ Long id;
+
+ public PlayerModel(float collectRateMultiplier, float moveSpeedMultiplier, int posX, int posY, float staminaMultiplier, LocalDateTime lastCollect, LocalDateTime lastMove) {
+ this.collectRateMultiplier = collectRateMultiplier;
+ this.moveSpeedMultiplier = moveSpeedMultiplier;
+ this.posX = posX;
+ this.posY = posY;
+ this.staminaMultiplier = staminaMultiplier;
+ this.lastCollect = lastCollect;
+ this.lastMove = lastMove;
+ }
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/repository/GameRepository.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/repository/GameRepository.java
new file mode 100644
index 0000000..e48f844
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/repository/GameRepository.java
@@ -0,0 +1,59 @@
+package fr.epita.assistants.item_producer.data.repository;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import fr.epita.assistants.item_producer.converter.ItemProducerConverter;
+import fr.epita.assistants.item_producer.data.model.GameModel;
+import io.quarkus.hibernate.orm.panache.PanacheRepository;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.transaction.Transactional;
+
+import java.util.List;
+
+@ApplicationScoped
+public class GameRepository implements PanacheRepository<GameModel> {
+ @Transactional
+ public String getMap() {
+ return getGame().getMap();
+ }
+
+ private GameModel getGame() {
+ return findAll().firstResult();
+ }
+
+ @Transactional
+ public boolean isEmpty() {
+ return count() == 0;
+ }
+
+ @Transactional
+ public void clearDB() {
+ deleteAll();
+ }
+
+ @Transactional
+ public void addEntry(String rle) {
+ GameModel game = new GameModel();
+ game.setMap(rle);
+ persist(game);
+ }
+
+ @Transactional
+ public boolean isValidCollect(int x, int y) {
+ List<List<String>> map = ItemProducerConverter.RLEtoMap(getMap());
+ return ItemAggregate.ResourceType.valueOf(map.get(y).get(x)).getItemInfo().isCollectable();
+ }
+
+ @Transactional
+ public void setToGround(int x, int y) {
+ List<List<String>> map = ItemProducerConverter.RLEtoMap(getMap());
+ map.get(y).set(x, ItemAggregate.ResourceType.GROUND.toString());
+ String rle = ItemProducerConverter.MapToRLE(map);
+ update("map = ?1 where id = ?2", rle, getGame().getId());
+ }
+
+ @Transactional
+ public String collectResource(int posX, int posY) {
+ List<List<String>> map = ItemProducerConverter.RLEtoMap(getMap());
+ return map.get(posY).get(posX);
+ }
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/repository/ItemRepository.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/repository/ItemRepository.java
new file mode 100644
index 0000000..b46311f
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/repository/ItemRepository.java
@@ -0,0 +1,50 @@
+package fr.epita.assistants.item_producer.data.repository;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import fr.epita.assistants.item_producer.data.model.ItemModel;
+import io.quarkus.hibernate.orm.panache.PanacheRepository;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.transaction.Transactional;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+@ApplicationScoped
+public class ItemRepository implements PanacheRepository<ItemModel> {
+ @Transactional
+ public void deleteItems(Map<ItemAggregate.ResourceType, Float> toDelete) {
+ for (ItemAggregate.ResourceType type : toDelete.keySet()) {
+ ItemModel item = find("type = ?1", type).firstResult();
+ if (item != null)
+ update("quantity = ?1 where type = ?2", item.getQuantity() - toDelete.get(type), type);
+ }
+ }
+
+ @Transactional
+ public List<ItemModel> getItems() {
+ return find("where quantity > 0").stream().toList();
+ }
+
+ @Transactional
+ public Optional<ItemModel> exists(ItemAggregate.ResourceType type) {
+ return find("type = ?1", type).firstResultOptional();
+ }
+
+ @Transactional
+ public void addItem(ItemAggregate.ResourceType type, Float amount) {
+ ItemModel res = new ItemModel(amount, type);
+ persist(res);
+ }
+
+ // amount should already be the updated amount
+ @Transactional
+ public void fillInventory(ItemAggregate.ResourceType type, Float amount) {
+ update("quantity = ?1 where type = ?2", amount, type);
+ }
+
+ @Transactional
+ public List<ItemModel> getMoney() {
+ return find("where type = ?1", ItemAggregate.ResourceType.MONEY).stream().toList();
+ }
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/repository/PlayerRepository.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/repository/PlayerRepository.java
new file mode 100644
index 0000000..b5bcde7
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/data/repository/PlayerRepository.java
@@ -0,0 +1,62 @@
+package fr.epita.assistants.item_producer.data.repository;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import fr.epita.assistants.common.utils.Direction;
+import fr.epita.assistants.item_producer.converter.ItemProducerConverter;
+import fr.epita.assistants.item_producer.data.model.PlayerModel;
+import io.quarkus.hibernate.orm.panache.PanacheRepository;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.transaction.Transactional;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@ApplicationScoped
+public class PlayerRepository implements PanacheRepository<PlayerModel> {
+ @Transactional
+ public void clearDB() {
+ deleteAll();
+ }
+
+ @Transactional
+ public void addEntry() {
+ PlayerModel player = new PlayerModel(1, 1, 0, 0, 1, null, null);
+ persist(player);
+ }
+
+ @Transactional
+ public PlayerModel getFirstPlayer() {
+ return findAll().firstResult();
+ }
+
+ @Transactional
+ public boolean isValidMove(Direction direction, String rle) {
+ PlayerModel playerModel = getFirstPlayer();
+ int x = playerModel.getPosX() + direction.getPoint().getPosX();
+ int y = playerModel.getPosY() + direction.getPoint().getPosY();
+ List<List<String>> map = ItemProducerConverter.RLEtoMap(rle);
+ return y >= 0 && x >= 0 && x < map.getFirst().size() && y < map.getFirst().size() && ItemAggregate.ResourceType.valueOf(map.get(y).get(x)).getItemInfo().isWalkable();
+ }
+
+ @Transactional
+ public void movePlayer(Direction direction) {
+ PlayerModel player = getFirstPlayer();
+ update("posX = ?1, posY = ?2, lastMove = ?3 where id = ?4", player.getPosX() + direction.getPoint().getPosX()
+ , player.getPosY() + direction.getPoint().getPosY(), LocalDateTime.now(), player.getId());
+ }
+
+ public void updateMoveSpeed(Float newSpeed) {
+ PlayerModel player = getFirstPlayer();
+ update("moveSpeedMultiplier = ?1 where id = ?2", newSpeed, player.getId());
+ }
+
+ public void updateCollectRate(Float newRate) {
+ PlayerModel player = getFirstPlayer();
+ update("collectRateMultiplier = ?1 where id = ?2", newRate, player.getId());
+ }
+
+ public void updateStamina(Float newStamina) {
+ PlayerModel player = getFirstPlayer();
+ update("staminaMultiplier = ?1 where id = ?2", newStamina, player.getId());
+ }
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/GameEntity.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/GameEntity.java
new file mode 100644
index 0000000..e248cb5
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/GameEntity.java
@@ -0,0 +1,4 @@
+package fr.epita.assistants.item_producer.domain.entity;
+
+public class GameEntity {
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/ItemEntity.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/ItemEntity.java
new file mode 100644
index 0000000..a8b666d
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/ItemEntity.java
@@ -0,0 +1,13 @@
+package fr.epita.assistants.item_producer.domain.entity;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class ItemEntity {
+ long id;
+ float quantity;
+ ItemAggregate.ResourceType type;
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/ItemsEntity.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/ItemsEntity.java
new file mode 100644
index 0000000..b03b373
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/ItemsEntity.java
@@ -0,0 +1,13 @@
+package fr.epita.assistants.item_producer.domain.entity;
+
+import fr.epita.assistants.common.api.response.ItemResponse;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.List;
+
+@Getter
+@AllArgsConstructor
+public class ItemsEntity {
+ List<ItemEntity> items;
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/MoveEntity.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/MoveEntity.java
new file mode 100644
index 0000000..72ea511
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/MoveEntity.java
@@ -0,0 +1,11 @@
+package fr.epita.assistants.item_producer.domain.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class MoveEntity {
+ int posX;
+ int posY;
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/PlayerEntity.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/PlayerEntity.java
new file mode 100644
index 0000000..0913c3f
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/PlayerEntity.java
@@ -0,0 +1,18 @@
+package fr.epita.assistants.item_producer.domain.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.time.LocalDateTime;
+
+@AllArgsConstructor
+@Getter
+public class PlayerEntity {
+ int posX;
+ int posY;
+ LocalDateTime lastMove;
+ LocalDateTime lastCollect;
+ float moveSpeedMultiplier;
+ float staminaMultiplier;
+ float collectRateMultiplier;
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/StartEntity.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/StartEntity.java
new file mode 100644
index 0000000..44a4961
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/StartEntity.java
@@ -0,0 +1,11 @@
+package fr.epita.assistants.item_producer.domain.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class StartEntity {
+ String mapPath;
+ String rle;
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/UpgradeCostEntity.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/UpgradeCostEntity.java
new file mode 100644
index 0000000..fac79e0
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/entity/UpgradeCostEntity.java
@@ -0,0 +1,12 @@
+package fr.epita.assistants.item_producer.domain.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class UpgradeCostEntity {
+ float upgradeCollectCost;
+ float upgradeMoveCost;
+ float upgradeStaminaCost;
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/service/ErwenService.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/service/ErwenService.java
new file mode 100644
index 0000000..fb3a507
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/service/ErwenService.java
@@ -0,0 +1,4 @@
+package fr.epita.assistants.item_producer.domain.service;
+
+public class ErwenService {
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/service/ItemProducerService.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/service/ItemProducerService.java
new file mode 100644
index 0000000..2a224c7
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/domain/service/ItemProducerService.java
@@ -0,0 +1,199 @@
+package fr.epita.assistants.item_producer.domain.service;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import fr.epita.assistants.common.aggregate.ResetInventoryAggregate;
+import fr.epita.assistants.common.api.response.*;
+import fr.epita.assistants.common.command.*;
+import fr.epita.assistants.common.utils.Direction;
+import fr.epita.assistants.item_producer.converter.ItemProducerConverter;
+import fr.epita.assistants.item_producer.data.model.ItemModel;
+import fr.epita.assistants.item_producer.data.model.PlayerModel;
+import fr.epita.assistants.item_producer.data.repository.GameRepository;
+import fr.epita.assistants.item_producer.data.repository.ItemRepository;
+import fr.epita.assistants.item_producer.data.repository.PlayerRepository;
+import fr.epita.assistants.item_producer.domain.entity.*;
+import io.smallrye.reactive.messaging.annotations.Broadcast;
+import jakarta.enterprise.context.ApplicationScoped;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.eclipse.microprofile.reactive.messaging.Channel;
+import org.eclipse.microprofile.reactive.messaging.Emitter;
+
+import jakarta.inject.Inject;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@ApplicationScoped
+public class ItemProducerService {
+ @ConfigProperty(name = "JWS_TICK_DURATION")
+ String tps;
+ @ConfigProperty(name = "JWS_DELAY_MOVEMENT")
+ String movementDelay;
+ @ConfigProperty(name = "JWS_DELAY_COLLECT")
+ String collectDelay;
+ @ConfigProperty(name = "JWS_UPGRADE_COLLECT_COST")
+ String upgradeCollectCost;
+ @ConfigProperty(name = "JWS_UPGRADE_MOVE_COST")
+ String upgradeMoveCost;
+ @ConfigProperty(name = "JWS_UPGRADE_STAMINA_COST")
+ String upgradeStaminaCost;
+ @ConfigProperty(name = "JWS_UPGRADE_MULTIPLIER")
+ String upgradeMultiplier;
+ @Inject
+ PlayerRepository playerRepository;
+ @Inject
+ GameRepository gameRepository;
+ @Inject
+ ItemRepository itemRepository;
+
+ @Inject
+ @Channel("reset-inventory-command")
+ @Broadcast
+ Emitter<ResetInventoryCommand> resetInventoryCommandEmitter;
+ @Inject
+ @Channel("collect-item-command")
+ @Broadcast
+ Emitter<CollectItemCommand> collectItemCommandEmitter;
+ @Inject
+ @Channel("upgrade-movement-speed-command")
+ @Broadcast
+ Emitter<UpgradeMovementSpeedCommand> upgradeMovementSpeedCommandEmitter;
+ @Inject
+ @Channel("upgrade-stamina-command")
+ @Broadcast
+ Emitter<UpgradeStaminaCommand> upgradeStaminaCommandEmitter;
+ @Inject
+ @Channel("upgrade-collect-rate-command")
+ @Broadcast
+ Emitter<UpgradeCollectRateCommand> upgradeCollectRateCommandEmitter;
+
+ public StartEntity startGame(StartEntity startEntity) {
+ if (startEntity == null)
+ return null;
+ gameRepository.clearDB();
+ playerRepository.clearDB();
+ try (Stream<String> stream = Files.lines(Paths.get(startEntity.getMapPath()))) {
+ if (new File(startEntity.getMapPath()).isDirectory())
+ return null;
+ String rle = stream.collect(Collectors.joining(";"));
+ gameRepository.addEntry(rle);
+ playerRepository.addEntry();
+ resetInventoryCommandEmitter.send(new ResetInventoryCommand());
+ return new StartEntity(null, rle);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ public void clearItems(ResetInventoryAggregate items) {
+ itemRepository.deleteItems(ItemProducerConverter.DeleteItems(items));
+ }
+
+ public ItemsEntity getAllItems() {
+ return new ItemsEntity(itemRepository.getItems().stream().map(m -> new ItemEntity(m.getId(),
+ m.getQuantity(), m.getType())).toList());
+ }
+
+ public boolean isGameRunning() {
+ return !gameRepository.isEmpty();
+ }
+
+ public boolean canMove() {
+ long tickRate = Long.parseLong(tps);
+ long moveDelay = Long.parseLong(movementDelay);
+ PlayerEntity player = getCurrentPlayer();
+ return player.getLastMove() == null || player.getLastMove().plus((long) (moveDelay * tickRate * player.getMoveSpeedMultiplier()),
+ ChronoUnit.MILLIS).isBefore(LocalDateTime.now());
+ }
+
+ public boolean canCollect() {
+ long tickRate = Long.parseLong(tps);
+ long collectDelayLong = Long.parseLong(collectDelay);
+ PlayerEntity player = getCurrentPlayer();
+ return player.getLastCollect() == null || player.getLastCollect().plus((long) (collectDelayLong * tickRate * player.getMoveSpeedMultiplier()),
+ ChronoUnit.MILLIS).isBefore(LocalDateTime.now());
+ }
+
+ public PlayerEntity getCurrentPlayer() {
+ PlayerModel p = playerRepository.getFirstPlayer();
+ return new PlayerEntity(p.getPosX(), p.getPosY(), p.getLastMove(), p.getLastCollect(),
+ p.getMoveSpeedMultiplier(), p.getStaminaMultiplier(), p.getCollectRateMultiplier());
+ }
+
+ public UpgradeCostEntity getUpgradeCosts() {
+ return new UpgradeCostEntity(Float.parseFloat(upgradeCollectCost),
+ Float.parseFloat(upgradeMoveCost), Float.parseFloat(upgradeStaminaCost));
+ }
+
+ public MoveEntity move(Direction direction) {
+ if (direction == null)
+ return null;
+ if (!playerRepository.isValidMove(direction, gameRepository.getMap()))
+ return null;
+ playerRepository.movePlayer(direction);
+ return ItemProducerConverter.Move(playerRepository.getFirstPlayer());
+ }
+
+ public StartEntity collect() {
+ PlayerEntity player = getCurrentPlayer();
+ if (!gameRepository.isValidCollect(player.getPosX(), player.getPosY()))
+ return null;
+ String item = gameRepository.collectResource(player.getPosX(), player.getPosY());
+ gameRepository.setToGround(player.getPosX(), player.getPosY());
+ collectItemCommandEmitter.send(new CollectItemCommand(ItemAggregate.ResourceType.valueOf(item),
+ player.getCollectRateMultiplier()));
+ return ItemProducerConverter.Collect(item);
+ }
+
+ public void collectItem(ItemAggregate agr) {
+ Optional<ItemModel> item = itemRepository.exists(agr.getType());
+ if (item.isPresent()) {
+ itemRepository.fillInventory(agr.getType(), agr.getQuantity());
+ } else {
+ itemRepository.addItem(agr.getType(), agr.getQuantity());
+ }
+ }
+
+ public Double getMoney() {
+ List<ItemModel> entries = itemRepository.getMoney();
+ if (entries.isEmpty())
+ return null;
+ return entries.stream().mapToDouble(m -> m.getQuantity().doubleValue()).sum();
+ }
+
+ public void upgradeMove() {
+ upgradeMovementSpeedCommandEmitter.send(new UpgradeMovementSpeedCommand(Float.parseFloat(upgradeMoveCost)));
+ }
+
+ public void updateMove() {
+ playerRepository.updateMoveSpeed(getCurrentPlayer().getMoveSpeedMultiplier() - Float.parseFloat(upgradeMultiplier));
+ }
+
+ public void upgradeCollect() {
+ upgradeCollectRateCommandEmitter.send(new UpgradeCollectRateCommand(Float.parseFloat(upgradeMoveCost)));
+ }
+
+ public void updateCollect() {
+ playerRepository.updateCollectRate(getCurrentPlayer().getCollectRateMultiplier() - Float.parseFloat(upgradeMultiplier));
+ }
+
+ public void upgradeStamina() {
+ upgradeStaminaCommandEmitter.send(new UpgradeStaminaCommand(Float.parseFloat(upgradeMoveCost)));
+ }
+
+ public void updateStamina() {
+ playerRepository.updateStamina(getCurrentPlayer().getStaminaMultiplier() - Float.parseFloat(upgradeMultiplier));
+ }
+
+ public void pay(Float newMoney) {
+ itemRepository.fillInventory(ItemAggregate.ResourceType.MONEY, newMoney);
+ }
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/presentation/rest/HelloWorldResource.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/presentation/rest/HelloWorldResource.java
new file mode 100644
index 0000000..9f9cb70
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/presentation/rest/HelloWorldResource.java
@@ -0,0 +1,19 @@
+package fr.epita.assistants.item_producer.presentation.rest;
+
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
+
+@Path("/hello")
+@Produces(MediaType.TEXT_PLAIN)
+@Consumes(MediaType.TEXT_PLAIN)
+public class HelloWorldResource {
+ @GET @Path("/")
+ public String helloWorld() {
+ return "Hello World!";
+ }
+
+ @GET @Path("/{name}")
+ public String helloWorld(@PathParam("name") String name) {
+ return "Hello " + name + "!";
+ }
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/presentation/rest/ItemProducerResource.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/presentation/rest/ItemProducerResource.java
new file mode 100644
index 0000000..fcebee9
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/presentation/rest/ItemProducerResource.java
@@ -0,0 +1,154 @@
+package fr.epita.assistants.item_producer.presentation.rest;
+
+import fr.epita.assistants.common.api.request.MoveRequest;
+import fr.epita.assistants.common.api.request.StartRequest;
+import fr.epita.assistants.common.api.response.MoveResponse;
+import fr.epita.assistants.common.api.response.StartResponse;
+import fr.epita.assistants.common.utils.ErrorInfo;
+import fr.epita.assistants.item_producer.converter.ItemProducerConverter;
+import fr.epita.assistants.item_producer.domain.service.ItemProducerService;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+
+@Path("/")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class ItemProducerResource {
+ @Inject
+ ItemProducerService itemProducerService;
+
+ @Path("/")
+ @GET
+ public Response getInventory() {
+ Response.ResponseBuilder rb;
+ if (!itemProducerService.isGameRunning())
+ rb = Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Game is not running"));
+ else
+ rb = Response.ok(ItemProducerConverter.EntityToResponse(itemProducerService.getAllItems()));
+ return rb.build();
+ }
+
+ @Path("player")
+ @GET
+ public Response getPlayer() {
+ Response.ResponseBuilder rb;
+ if (!itemProducerService.isGameRunning())
+ rb = Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Game is not running"));
+ else
+ rb = Response.ok(ItemProducerConverter.EntityToResponse(itemProducerService.getCurrentPlayer()));
+ return rb.build();
+ }
+ @Path("start")
+ @POST
+ public Response start(StartRequest startRequest) {
+ StartResponse r = ItemProducerConverter.EntityToResponse(itemProducerService.startGame(ItemProducerConverter.Start(startRequest)));
+ Response.ResponseBuilder res;
+ if (r == null)
+ res = Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Bad request for /start"));
+ else
+ res = Response.ok(r);
+ return res.build();
+ }
+ @Path("upgrades")
+ @GET
+ public Response getUpgrades() {
+ Response.ResponseBuilder rb;
+ if (!itemProducerService.isGameRunning())
+ rb = Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Game is not running"));
+ else
+ rb = Response.ok(ItemProducerConverter.EntityToResponse(itemProducerService.getUpgradeCosts()));
+ return rb.build();
+ }
+
+ @Path("collect")
+ @POST
+ public Response collect() {
+ Response.ResponseBuilder rb;
+ if (!itemProducerService.isGameRunning())
+ rb = Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Game is not running"));
+ else if (!itemProducerService.canCollect())
+ rb = Response.status(Response.Status.TOO_MANY_REQUESTS).entity(new ErrorInfo("Input too early, wait " +
+ "before trying to move again"));
+ else {
+ StartResponse rep = ItemProducerConverter.EntityToResponse(itemProducerService.collect());
+ if (rep == null)
+ rb = Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Can't collect on this tile"));
+ else
+ rb = Response.ok(rep);
+ }
+ return rb.build();
+ }
+
+ @Path("move")
+ @POST
+ public Response move(MoveRequest moveRequest) {
+ Response.ResponseBuilder rb;
+ if (!itemProducerService.isGameRunning())
+ rb = Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Game is not running"));
+ else if (!itemProducerService.canMove())
+ rb = Response.status(Response.Status.TOO_MANY_REQUESTS).entity(new ErrorInfo("Input too early, wait " +
+ "before trying to move again"));
+ else {
+ MoveResponse rep = ItemProducerConverter.EntityToResponse(itemProducerService.move(moveRequest.getDirection()));
+ if (rep == null)
+ rb = Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Tried to move out of bounds " +
+ "(or maybe you felt like you were Jesus)"));
+ else
+ rb = Response.ok(rep);
+ }
+ return rb.build();
+ }
+
+ @Path("upgrade/collect")
+ @PATCH
+ public Response upgradeCollect() {
+ Response.ResponseBuilder rb;
+ if (!itemProducerService.isGameRunning())
+ rb = Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Game is not running."));
+ else if (itemProducerService.getMoney() == null)
+ rb = Response.status(Response.Status.NOT_FOUND).entity(new ErrorInfo("No money was found."));
+ else if (itemProducerService.getMoney() < itemProducerService.getUpgradeCosts().getUpgradeCollectCost())
+ rb = Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("You are poor."));
+ else {
+ itemProducerService.upgradeCollect();
+ rb = Response.noContent();
+ }
+ return rb.build();
+ }
+
+ @Path("upgrade/move")
+ @PATCH
+ public Response upgradeMove() {
+ Response.ResponseBuilder rb;
+ if (!itemProducerService.isGameRunning())
+ rb = Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Game is not running."));
+ else if (itemProducerService.getMoney() == null)
+ rb = Response.status(Response.Status.NOT_FOUND).entity(new ErrorInfo("No money was found."));
+ else if (itemProducerService.getMoney() < itemProducerService.getUpgradeCosts().getUpgradeMoveCost())
+ rb = Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("You are poor."));
+ else {
+ itemProducerService.upgradeMove();
+ rb = Response.noContent();
+ }
+ return rb.build();
+ }
+
+ @Path("upgrade/stamina")
+ @PATCH
+ public Response upgradeStamina() {
+ Response.ResponseBuilder rb;
+ if (!itemProducerService.isGameRunning())
+ rb = Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Game is not running."));
+ else if (itemProducerService.getMoney() == null)
+ rb = Response.status(Response.Status.NOT_FOUND).entity(new ErrorInfo("No money was found."));
+ else if (itemProducerService.getMoney() < itemProducerService.getUpgradeCosts().getUpgradeStaminaCost())
+ rb = Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("You are poor."));
+ else {
+ itemProducerService.upgradeStamina();
+ rb = Response.noContent();
+ }
+ return rb.build();
+ }
+}
diff --git a/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/presentation/subscriber/AggregateSubscriber.java b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/presentation/subscriber/AggregateSubscriber.java
new file mode 100644
index 0000000..c6f3231
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/java/fr/epita/assistants/item_producer/presentation/subscriber/AggregateSubscriber.java
@@ -0,0 +1,47 @@
+package fr.epita.assistants.item_producer.presentation.subscriber;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import fr.epita.assistants.common.aggregate.ResetInventoryAggregate;
+import fr.epita.assistants.common.aggregate.UpgradeItemProducerAggregate;
+import fr.epita.assistants.item_producer.domain.service.ItemProducerService;
+import io.smallrye.reactive.messaging.annotations.Broadcast;
+import jakarta.inject.Inject;
+import org.eclipse.microprofile.reactive.messaging.Incoming;
+
+public class AggregateSubscriber {
+ @Inject
+ ItemProducerService itemProducerService;
+
+ @Broadcast
+ @Incoming("reset-inventory-aggregate")
+ public void commandListener(ResetInventoryAggregate aggregate) {
+ itemProducerService.clearItems(aggregate);
+ }
+
+ @Broadcast
+ @Incoming("collect-item-aggregate")
+ public void commandListener(ItemAggregate agr) {
+ itemProducerService.collectItem(agr);
+ }
+
+ @Broadcast
+ @Incoming("upgrade-collect-rate-aggregate")
+ public void collectCommandListener(UpgradeItemProducerAggregate agr) {
+ itemProducerService.pay(agr.getNewMoney());
+ itemProducerService.updateCollect();
+ }
+
+ @Broadcast
+ @Incoming("upgrade-movement-speed-aggregate")
+ public void moveCommandListener(UpgradeItemProducerAggregate agr) {
+ itemProducerService.pay(agr.getNewMoney());
+ itemProducerService.updateMove();
+ }
+
+ @Broadcast
+ @Incoming("upgrade-stamina-aggregate")
+ public void staminaCommandListener(UpgradeItemProducerAggregate agr) {
+ itemProducerService.pay(agr.getNewMoney());
+ itemProducerService.updateStamina();
+ }
+}
diff --git a/jws/epibazaar/item-producer/src/main/resources/application.properties b/jws/epibazaar/item-producer/src/main/resources/application.properties
new file mode 100644
index 0000000..498479f
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/resources/application.properties
@@ -0,0 +1,13 @@
+%dev.quarkus.http.port=8081
+quarkus.datasource.db-kind=postgresql
+quarkus.datasource.username=postgres
+quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/item_producer?currentSchema=public
+quarkus.transaction-manager.default-transaction-timeout=3000s
+quarkus.hibernate-orm.log.queries-slower-than-ms=200
+quarkus.http.cors=true
+quarkus.http.cors.origins=*
+quarkus.hibernate-orm.database.generation=drop-and-create
+
+quarkus.kafka.devservices.image-name=reg.undercloud.cri.epita.fr/docker/redpandadata/redpanda:v24.1.2
+quarkus.devservices.enabled=true
+%test.quarkus.devservices.enabled=false
diff --git a/jws/epibazaar/item-producer/src/main/resources/db/migration/V1__Init.sql b/jws/epibazaar/item-producer/src/main/resources/db/migration/V1__Init.sql
new file mode 100644
index 0000000..0eede01
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/resources/db/migration/V1__Init.sql
@@ -0,0 +1,25 @@
+CREATE TABLE IF NOT EXISTS "game"
+(
+ id SERIAL PRIMARY KEY NOT NULL,
+ map TEXT NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS "item"
+(
+ id SERIAL PRIMARY KEY NOT NULL,
+
+ type VARCHAR(64) NOT NULL,
+ quantity FLOAT NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS "player"
+(
+ id SERIAL PRIMARY KEY NOT NULL,
+ pos_x INTEGER NOT NULL,
+ pos_y INTEGER NOT NULL,
+ last_move TIMESTAMP,
+ last_collect TIMESTAMP,
+ move_speed_multiplier FLOAT NOT NULL,
+ stamina_multiplier FLOAT NOT NULL,
+ collect_rate_multiplier FLOAT NOT NULL
+);
diff --git a/jws/epibazaar/item-producer/src/main/resources/maps/custom.epimap b/jws/epibazaar/item-producer/src/main/resources/maps/custom.epimap
new file mode 100644
index 0000000..5b510f3
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/resources/maps/custom.epimap
@@ -0,0 +1,16 @@
+2G4R3W5G2R
+5G3W4R2G2W
+6R3G2W5G
+3W5G6R2W
+4G3R4W5G
+2W5R3G4W2G
+6G4R3W3G
+4R6G3W3R
+5G2W5R4G
+3W5R4G3W1G
+2G6W3R5G
+4W5G3R4W
+3G4R5W4G
+5R3G6W2R
+2W5G4R5W
+9G7G \ No newline at end of file
diff --git a/jws/epibazaar/item-producer/src/main/resources/maps/huge.epimap b/jws/epibazaar/item-producer/src/main/resources/maps/huge.epimap
new file mode 100644
index 0000000..d8384bd
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/resources/maps/huge.epimap
@@ -0,0 +1,30 @@
+9G9G9G3G
+8G3W3R2G2R2G2W1R4G1R2G
+7G2W1G3R1W1G1R1W2G1R1G1R1G1R1G2W2R1G
+1G1W4G1R1G1W1R5G2R4G1R1W1R2G1W3G
+1G1W1R2G2R1G1W2R3G2W2G2O3G2R3G1W1G
+1G1W1G2W7G4O3G2O3R3G2W1G
+1G1R4G1R3G1R3G2O3G2O2R3G2W2G
+4G3R3G3R8O3R2G1W3G
+4G3R1G5R4O2G1W2R1G2R5G
+4G9R1G3O9G4G
+5G4R2W2O1R5O2G3W1R5G
+3G4R2G8O1G7W1G2W2G
+3G1R1G2R1G1W9O1W2G1R2W6G
+1G1R1G2R2G1R1W1G6O4W9O1G
+1G4R1G2R1W1G3O1G2O5W1G7O1G
+1G1W2R1W1G1R1G2W3O2R1O4W1G1R7O1G
+5G3W3G2O1G1W1G3W1G1W1G7O1G
+1G2R2G2W4R2O3G3W1R1G1W1G1R5O1G
+1G1W1R1G2R4W1R1G1R1G3R2W5G5O1G
+1G2R2G1R2W1R2G6R1W1G9O1O1G
+2G2W9R2R3W2G9O1G
+6G3W2G4R3W2G2O1W6O1G
+1G3R2G3W2G3R1G3W2R2O1R6O1G
+1G3R1G1W3R2W1R2G2W1G3R2O1R1O1G1O1G1W1O1G
+3G2W1G2R1G2R2G2W3G1R1W2G2R1G1W1G1R1O1G
+3G1W1R3G2R4G1R2G1W1G1R2W2R1G1W3R1G
+1G4W1G3R2W3G2R3W1R2W3R1G2R2G
+2G3W1G2R6G2R2G2R1G1W1G2W1G1R1G1W1G
+2G3W1G1W1G4W9G1G2R1W1G2R2G
+9G9G9G3G \ No newline at end of file
diff --git a/jws/epibazaar/item-producer/src/main/resources/maps/pretty.epimap b/jws/epibazaar/item-producer/src/main/resources/maps/pretty.epimap
new file mode 100644
index 0000000..3699c22
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/resources/maps/pretty.epimap
@@ -0,0 +1,16 @@
+9G7G
+2G6O3G4R1G
+2G5O4G3R2G
+2G4O4G3W2G1G
+2G3O4G5W1G1G
+2G3O3G5W3G
+2G3G4W4G3R
+2G3R3G4W3O1G
+1G2R3G4W4O2G
+1G3G3W6O3G
+1G2W4G5O4G
+1G2W3G4R3G3G
+1G3R4G4R1G3G
+1G5R4G4R2G
+1G5R3G6G1G
+9G7G
diff --git a/jws/epibazaar/item-producer/src/main/resources/openapi.yaml b/jws/epibazaar/item-producer/src/main/resources/openapi.yaml
new file mode 100644
index 0000000..16e0465
--- /dev/null
+++ b/jws/epibazaar/item-producer/src/main/resources/openapi.yaml
@@ -0,0 +1,287 @@
+---
+openapi: 3.1.0
+tags:
+- name: Game Management
+- name: Player Actions
+- name: Upgrades
+paths:
+ /:
+ get:
+ summary: Retrieve all inventory resources
+ description: Fetch all resources currently available in the inventory.
+ x-quarkus-openapi-method-ref: m98752433_-1109396335
+ tags:
+ - Game Management
+ responses:
+ "200":
+ description: Resources successfully retrieved.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ItemsResponse"
+ "400":
+ description: The game is not running.
+ servers:
+ - url: http://localhost:8081/
+ /collect:
+ post:
+ summary: Collect resources
+ description: Collect the resource available on the player's current tile.
+ x-quarkus-openapi-method-ref: m98752433_799402137
+ tags:
+ - Player Actions
+ responses:
+ "200":
+ description: Resource successfully collected and sent to inventory.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/StartResponse"
+ "400":
+ description: Invalid tile or the game is not running.
+ "429":
+ description: Player has recently collected and must wait before collecting
+ again.
+ servers:
+ - url: http://localhost:8081/
+ /move:
+ post:
+ summary: Move player
+ description: "Move the player in the specified direction (left, right, up, or\
+ \ down)."
+ x-quarkus-openapi-method-ref: m98752433_-1586243046
+ tags:
+ - Player Actions
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/MoveRequest"
+ required: true
+ responses:
+ "200":
+ description: Player successfully moved.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/MoveResponse"
+ "400":
+ description: Invalid direction or the game is not running.
+ "429":
+ description: Player has recently moved and must wait before moving again.
+ servers:
+ - url: http://localhost:8081/
+ /player:
+ get:
+ summary: Retrieve player information
+ description: Fetch information about the current player.
+ x-quarkus-openapi-method-ref: m98752433_-1988770431
+ tags:
+ - Game Management
+ responses:
+ "200":
+ description: Player information successfully retrieved.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/PlayerResponse"
+ "400":
+ description: The game is not running.
+ servers:
+ - url: http://localhost:8081/
+ /start:
+ post:
+ summary: Start the game
+ description: Initialize and start the item-producer game. Synchronizes the database
+ with the `Inventory` service.
+ x-quarkus-openapi-method-ref: m98752433_677674067
+ tags:
+ - Game Management
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/StartRequest"
+ required: true
+ responses:
+ "200":
+ description: The game started successfully.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/StartResponse"
+ "400":
+ description: Invalid `path` provided.
+ servers:
+ - url: http://localhost:8081/
+ /upgrade/collect:
+ patch:
+ summary: Upgrade collection rate
+ description: Increase the amount of resources collected per action.
+ x-quarkus-openapi-method-ref: m98752433_274012880
+ tags:
+ - Upgrades
+ responses:
+ "204":
+ description: Collection rate upgrade successfully applied.
+ "400":
+ description: Insufficient funds or the game is not running.
+ "404":
+ description: The money was not found.
+ servers:
+ - url: http://localhost:8081/
+ /upgrade/move:
+ patch:
+ summary: Upgrade move speed
+ description: Decrease the tick rate required for the player to move.
+ x-quarkus-openapi-method-ref: m98752433_1889564488
+ tags:
+ - Upgrades
+ responses:
+ "204":
+ description: Move speed upgrade successfully applied.
+ "400":
+ description: Insufficient funds or the game is not running.
+ "404":
+ description: The money was not found.
+ servers:
+ - url: http://localhost:8081/
+ /upgrade/stamina:
+ patch:
+ summary: Upgrade stamina
+ description: Decrease the tick rate required to collect resources.
+ x-quarkus-openapi-method-ref: m98752433_-1142370765
+ tags:
+ - Upgrades
+ responses:
+ "204":
+ description: Stamina upgrade successfully applied.
+ "400":
+ description: Insufficient funds or the game is not running.
+ "404":
+ description: The money was not found.
+ servers:
+ - url: http://localhost:8081/
+ /upgrades:
+ get:
+ summary: Retrieve upgrade costs
+ description: Fetch the costs of all available upgrades.
+ x-quarkus-openapi-method-ref: m98752433_-99503618
+ tags:
+ - Game Management
+ responses:
+ "200":
+ description: Upgrade costs successfully retrieved.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UpgradeCostResponse"
+ "400":
+ description: The game is not running.
+ servers:
+ - url: http://localhost:8081/
+components:
+ schemas:
+ Direction:
+ type: string
+ enum:
+ - UP
+ - DOWN
+ - RIGHT
+ - LEFT
+ ItemResponse:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int32
+ quantity:
+ type: number
+ format: float
+ type:
+ $ref: "#/components/schemas/ResourceType"
+ ItemsResponse:
+ type: object
+ properties:
+ itemsResponse:
+ type: array
+ items:
+ $ref: "#/components/schemas/ItemResponse"
+ LocalDateTime:
+ type: string
+ format: date-time
+ examples:
+ - 2022-03-10T12:15:50
+ MoveRequest:
+ type: object
+ properties:
+ direction:
+ $ref: "#/components/schemas/Direction"
+ MoveResponse:
+ type: object
+ properties:
+ posX:
+ type: integer
+ format: int32
+ posY:
+ type: integer
+ format: int32
+ PlayerResponse:
+ type: object
+ properties:
+ posX:
+ type: integer
+ format: int32
+ posY:
+ type: integer
+ format: int32
+ lastMove:
+ $ref: "#/components/schemas/LocalDateTime"
+ lastCollect:
+ $ref: "#/components/schemas/LocalDateTime"
+ moveSpeedMultiplier:
+ type: number
+ format: float
+ staminaMultiplier:
+ type: number
+ format: float
+ collectRateMultiplier:
+ type: number
+ format: float
+ ResourceType:
+ type: string
+ enum:
+ - MONEY
+ - GROUND
+ - WATER
+ - ROCK
+ - WOOD
+ StartRequest:
+ type: object
+ properties:
+ mapPath:
+ type: string
+ StartResponse:
+ type: object
+ properties:
+ map:
+ type: array
+ items:
+ type: array
+ items:
+ $ref: "#/components/schemas/ResourceType"
+ UpgradeCostResponse:
+ type: object
+ properties:
+ upgradeCollectCost:
+ type: number
+ format: float
+ upgradeMoveCost:
+ type: number
+ format: float
+ upgradeStaminaCost:
+ type: number
+ format: float
+info:
+ title: item-producer API
+ version: 1.0.0
diff --git a/jws/epibazaar/pom.xml b/jws/epibazaar/pom.xml
new file mode 100644
index 0000000..c0ed297
--- /dev/null
+++ b/jws/epibazaar/pom.xml
@@ -0,0 +1,359 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+ 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>
+
+ <groupId>fr.epita.assistants</groupId>
+ <artifactId>epibazaar</artifactId>
+ <version>1.0.0</version>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>common</module>
+ <module>item-producer</module>
+ <module>inventory</module>
+ <module>shop</module>
+ </modules>
+
+ <properties>
+ <maven.compiler.release>21</maven.compiler.release>
+ <maven.compiler.source>21</maven.compiler.source>
+ <maven.compiler.target>21</maven.compiler.target>
+
+ <compiler-plugin.version>3.13.0</compiler-plugin.version>
+ <maven.compiler.parameters>true</maven.compiler.parameters>
+
+ <versions.maven-surefire-plugin>3.0.0-M5</versions.maven-surefire-plugin>
+ <versions.maven-jar-plugin>3.4.1</versions.maven-jar-plugin>
+ <versions.maven-install-plugin>3.1.2</versions.maven-install-plugin>
+
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+
+ <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
+ <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
+ <quarkus.platform.version>3.17.5</quarkus.platform.version>
+
+ <skipITs>true</skipITs>
+ <surefire.reportsDirectory>${project.build.directory}../../target/surefire-reports</surefire.reportsDirectory>
+ </properties>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>${quarkus.platform.group-id}</groupId>
+ <artifactId>${quarkus.platform.artifact-id}</artifactId>
+ <version>${quarkus.platform.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-junit5</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-rest-jackson</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-rest-jackson-deployment</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-arc</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <version>1.18.36</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.smallrye.reactive</groupId>
+ <artifactId>smallrye-reactive-messaging-in-memory</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.awaitility</groupId>
+ <artifactId>awaitility</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <version>3.26.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.rest-assured</groupId>
+ <artifactId>rest-assured</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpmime</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-rest-kotlin</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-messaging-kafka-deployment</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus.platform</groupId>
+ <artifactId>quarkus-bom</artifactId>
+ <version>${quarkus.platform.version}</version>
+ <type>pom</type>
+ </dependency>
+
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-junit5-properties</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opentest4j</groupId>
+ <artifactId>opentest4j</artifactId>
+ <version>1.3.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apiguardian</groupId>
+ <artifactId>apiguardian-api</artifactId>
+ <version>1.1.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-params</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-junit-platform</artifactId>
+ <version>${versions.maven-surefire-plugin}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>common-java5</artifactId>
+ <version>3.5.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-shared-utils</artifactId>
+ <version>3.5.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.platform</groupId>
+ <artifactId>junit-platform-engine</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.platform</groupId>
+ <artifactId>junit-platform-launcher</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-api</artifactId>
+ <version>3.5.2</version>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus.platform</groupId>
+ <artifactId>quarkus-maven-plugin</artifactId>
+ <version>3.17.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>${versions.maven-jar-plugin}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <version>${versions.maven-install-plugin}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-rest-kotlin-deployment</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.platform</groupId>
+ <artifactId>junit-platform-commons</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-repository-metadata</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-registry</artifactId>
+ <version>2.0.6</version>
+ </dependency>
+ <dependency>
+ <groupId>classworlds</groupId>
+ <artifactId>classworlds</artifactId>
+ <version>1.1-alpha-2</version>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-maven-plugin</artifactId>
+ <version>3.17.5</version>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-smallrye-openapi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.tngtech.archunit</groupId>
+ <artifactId>archunit-junit5</artifactId>
+ <version>1.3.0</version>
+ </dependency>
+ <dependency>
+ <groupId>io.github.classgraph</groupId>
+ <artifactId>classgraph</artifactId>
+ <version>4.8.179</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>3.3.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>3.7.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>3.7.0</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifest>
+ <mainClass>fully.qualified.MainClass</mainClass>
+ </manifest>
+ </archive>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-maven-plugin</artifactId>
+ <version>${quarkus.platform.version}</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <goals>
+ <goal>build</goal>
+ <goal>generate-code</goal>
+ <goal>generate-code-tests</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>${compiler-plugin.version}</version>
+ <configuration>
+ <parameters>${maven.compiler.parameters}</parameters>
+ <annotationProcessorPaths>
+ <path>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <version>1.18.36</version>
+ </path>
+ </annotationProcessorPaths>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${versions.maven-surefire-plugin}</version>
+ <configuration>
+ <systemPropertyVariables>
+ <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
+ <maven.home>${maven.home}</maven.home>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <profiles>
+ <profile>
+ <id>fetch-bom</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>io.quarkus.platform</groupId>
+ <artifactId>quarkus-bom-quarkus-platform-properties</artifactId>
+ <version>3.17.5</version>
+ <type>properties</type>
+ </dependency>
+ </dependencies>
+ </profile>
+ <profile>
+ <id>native</id>
+ <activation>
+ <property>
+ <name>native</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>${versions.maven-surefire-plugin}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <systemPropertyVariables>
+ <native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
+ <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
+ <maven.home>${maven.home}</maven.home>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <properties>
+ <quarkus.package.type>native</quarkus.package.type>
+ </properties>
+ </profile>
+ </profiles>
+</project>
diff --git a/jws/epibazaar/shop/.env b/jws/epibazaar/shop/.env
new file mode 100644
index 0000000..c83ee7f
--- /dev/null
+++ b/jws/epibazaar/shop/.env
@@ -0,0 +1,4 @@
+JWS_SHOP_PRICE=17.5
+JWS_UPGRADE_PRICE_COST=28.5
+JWS_UPGRADE_MULTIPLIER=1.15
+JWS_MAX_SHOP_QUANTITY=8 \ No newline at end of file
diff --git a/jws/epibazaar/shop/pom.xml b/jws/epibazaar/shop/pom.xml
new file mode 100644
index 0000000..6d07d08
--- /dev/null
+++ b/jws/epibazaar/shop/pom.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+ 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>fr.epita.assistants</groupId>
+ <artifactId>epibazaar</artifactId>
+ <version>1.0.0</version>
+ </parent>
+
+ <artifactId>shop</artifactId>
+ <version>1.0.0</version>
+ <dependencies>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-messaging-kafka</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-jdbc-postgresql</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-hibernate-orm-panache</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>fr.epita.assistants</groupId>
+ <artifactId>common</artifactId>
+ <version>1.0.0</version>
+ <scope>compile</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifest>
+ <mainClass>fully.qualified.MainClass</mainClass>
+ </manifest>
+ </archive>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-maven-plugin</artifactId>
+ <version>${quarkus.platform.version}</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <goals>
+ <goal>build</goal>
+ <goal>generate-code</goal>
+ <goal>generate-code-tests</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>${compiler-plugin.version}</version>
+ <configuration>
+ <parameters>${maven.compiler.parameters}</parameters>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${versions.maven-surefire-plugin}</version>
+ <configuration>
+ <systemPropertyVariables>
+ <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
+ <maven.home>${maven.home}</maven.home>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <profiles>
+ <profile>
+ <id>fetch-bom</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>io.quarkus.platform</groupId>
+ <artifactId>quarkus-bom-quarkus-platform-properties</artifactId>
+ <version>3.17.5</version>
+ <type>properties</type>
+ </dependency>
+ </dependencies>
+ </profile>
+ <profile>
+ <id>native</id>
+ <activation>
+ <property>
+ <name>native</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>${versions.maven-surefire-plugin}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <systemPropertyVariables>
+ <native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
+ <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
+ <maven.home>${maven.home}</maven.home>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <properties>
+ <quarkus.package.type>native</quarkus.package.type>
+ </properties>
+ </profile>
+ </profiles>
+</project>
diff --git a/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/converter/ShopConverter.java b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/converter/ShopConverter.java
new file mode 100644
index 0000000..1b3e8cb
--- /dev/null
+++ b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/converter/ShopConverter.java
@@ -0,0 +1,24 @@
+package fr.epita.assistants.shop.converter;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import fr.epita.assistants.common.aggregate.ResetInventoryAggregate;
+import fr.epita.assistants.shop.data.model.ItemModel;
+import jakarta.enterprise.context.ApplicationScoped;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@ApplicationScoped
+public class ShopConverter {
+ public static Map<ItemAggregate.ResourceType, Float> DeleteItems(ResetInventoryAggregate items) {
+ Map<ItemAggregate.ResourceType, Float> map = new HashMap<>();
+ for (ItemAggregate i : items.getItems()) {
+ map.merge(i.getType(), i.getQuantity(), Float::sum);
+ }
+ return map;
+ }
+
+ public static ItemAggregate updatedItem(ItemModel item) {
+ return new ItemAggregate(item.getType(), item.getQuantity());
+ }
+}
diff --git a/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/data/model/ItemModel.java b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/data/model/ItemModel.java
new file mode 100644
index 0000000..a16f7bc
--- /dev/null
+++ b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/data/model/ItemModel.java
@@ -0,0 +1,28 @@
+package fr.epita.assistants.shop.data.model;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import jakarta.persistence.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Entity
+@Setter
+@Table(name = "item")
+public class ItemModel {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ Long id;
+ @Enumerated(value = EnumType.STRING)
+ ItemAggregate.ResourceType type;
+ Float quantity;
+
+ public ItemModel(float quantity, ItemAggregate.ResourceType type) {
+ this.quantity = quantity;
+ this.type = type;
+ }
+} \ No newline at end of file
diff --git a/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/data/model/ShopModel.java b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/data/model/ShopModel.java
new file mode 100644
index 0000000..5f1c3ff
--- /dev/null
+++ b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/data/model/ShopModel.java
@@ -0,0 +1,18 @@
+package fr.epita.assistants.shop.data.model;
+import jakarta.persistence.*;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+@Getter
+@Setter
+@Entity
+@AllArgsConstructor
+@NoArgsConstructor
+@Table(name = "shop")
+public class ShopModel {
+ Float priceMultiplier;
+ Float upgradePrice;
+ @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
+ Integer id;
+}
diff --git a/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/data/repository/ItemRepository.java b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/data/repository/ItemRepository.java
new file mode 100644
index 0000000..c471eb4
--- /dev/null
+++ b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/data/repository/ItemRepository.java
@@ -0,0 +1,39 @@
+package fr.epita.assistants.shop.data.repository;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import fr.epita.assistants.shop.data.model.ItemModel;
+import io.quarkus.hibernate.orm.panache.PanacheRepository;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.transaction.Transactional;
+
+import java.util.Map;
+import java.util.Optional;
+
+@ApplicationScoped
+public class ItemRepository implements PanacheRepository<ItemModel> {
+ @Transactional
+ public void deleteItems(Map<ItemAggregate.ResourceType, Float> toDelete) {
+ for (ItemAggregate.ResourceType type : toDelete.keySet()) {
+ ItemModel item = find("type = ?1", type).firstResult();
+ if (item != null)
+ update("quantity = ?1 where type = ?2", item.getQuantity() - toDelete.get(type), type);
+ }
+ }
+
+ @Transactional
+ public Optional<ItemModel> exists(ItemAggregate.ResourceType type) {
+ return find("type = ?1", type).firstResultOptional();
+ }
+
+ @Transactional
+ public void addItem(ItemAggregate.ResourceType type, Float amount) {
+ ItemModel res = new ItemModel(amount, type);
+ persist(res);
+ }
+
+ // amount should already be the updated amount
+ @Transactional
+ public void fillInventory(ItemAggregate.ResourceType type, Float amount) {
+ update("quantity = ?1 where type = ?2", amount, type);
+ }
+}
diff --git a/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/data/repository/ShopRepository.java b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/data/repository/ShopRepository.java
new file mode 100644
index 0000000..1bc7c78
--- /dev/null
+++ b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/data/repository/ShopRepository.java
@@ -0,0 +1,30 @@
+package fr.epita.assistants.shop.data.repository;
+
+import fr.epita.assistants.common.api.request.StartRequest;
+import fr.epita.assistants.common.api.response.StartResponse;
+import fr.epita.assistants.common.utils.ErrorInfo;
+import fr.epita.assistants.shop.converter.ShopConverter;
+import fr.epita.assistants.shop.data.model.ShopModel;
+import fr.epita.assistants.shop.domain.service.ShopService;
+import io.quarkus.hibernate.orm.panache.PanacheRepository;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.transaction.Transactional;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.core.Response;
+
+@ApplicationScoped
+public class ShopRepository implements PanacheRepository<ShopModel> {
+ @Transactional
+ public void clearDB() {
+ deleteAll();
+ }
+ @Transactional
+ public void addEntry(Float priceMultiplier, Float upgradePriceCost) {
+ ShopModel shop = new ShopModel();
+ shop.setUpgradePrice(upgradePriceCost);
+ shop.setPriceMultiplier(priceMultiplier);
+ persist(shop);
+ }
+}
diff --git a/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/domain/entity/ErwenEntity.java b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/domain/entity/ErwenEntity.java
new file mode 100644
index 0000000..3bb22f1
--- /dev/null
+++ b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/domain/entity/ErwenEntity.java
@@ -0,0 +1,4 @@
+package fr.epita.assistants.shop.domain.entity;
+
+public class ErwenEntity {
+}
diff --git a/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/domain/entity/StartEntity.java b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/domain/entity/StartEntity.java
new file mode 100644
index 0000000..d26ac90
--- /dev/null
+++ b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/domain/entity/StartEntity.java
@@ -0,0 +1,9 @@
+package fr.epita.assistants.shop.domain.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class StartEntity {
+}
diff --git a/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/domain/service/ErwenService.java b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/domain/service/ErwenService.java
new file mode 100644
index 0000000..b7e8ad7
--- /dev/null
+++ b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/domain/service/ErwenService.java
@@ -0,0 +1,4 @@
+package fr.epita.assistants.shop.domain.service;
+
+public class ErwenService {
+}
diff --git a/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/domain/service/ShopService.java b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/domain/service/ShopService.java
new file mode 100644
index 0000000..06ed11c
--- /dev/null
+++ b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/domain/service/ShopService.java
@@ -0,0 +1,79 @@
+package fr.epita.assistants.shop.domain.service;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import fr.epita.assistants.common.aggregate.ResetInventoryAggregate;
+import fr.epita.assistants.common.aggregate.SyncInventoryAggregate;
+import fr.epita.assistants.common.command.CollectItemCommand;
+import fr.epita.assistants.common.command.ResetInventoryCommand;
+import fr.epita.assistants.common.command.SyncInventoryCommand;
+import fr.epita.assistants.shop.converter.ShopConverter;
+import fr.epita.assistants.shop.data.model.ItemModel;
+import fr.epita.assistants.shop.data.repository.ItemRepository;
+import fr.epita.assistants.shop.data.repository.ShopRepository;
+import io.smallrye.reactive.messaging.annotations.Broadcast;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.transaction.Transactional;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.eclipse.microprofile.reactive.messaging.Channel;
+import org.eclipse.microprofile.reactive.messaging.Emitter;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@ApplicationScoped
+public class ShopService {
+ @ConfigProperty(name = "JWS_SHOP_PRICE")
+ String shopPrice;
+ @ConfigProperty(name = "JWS_UPGRADE_PRICE_COST")
+ String upgradePriceCost;
+ @Inject
+ ItemRepository itemRepository;
+ @Inject
+ ShopRepository shopRepository;
+
+ @Inject
+ @Channel("sync-inventory-command")
+ @Broadcast
+ Emitter<SyncInventoryCommand> syncInventoryCommandEmitter;
+
+ public void clearItems(ResetInventoryAggregate items) {
+ itemRepository.deleteItems(ShopConverter.DeleteItems(items));
+ }
+
+ public void collectItem(ItemAggregate agr) {
+ Optional<ItemModel> item = itemRepository.exists(agr.getType());
+ if (item.isPresent()) {
+ itemRepository.fillInventory(agr.getType(), agr.getQuantity());
+ } else {
+ itemRepository.addItem(agr.getType(), agr.getQuantity());
+ }
+ }
+
+ public void startShop() {
+ shopRepository.clearDB();
+ shopRepository.addEntry(1f, Float.parseFloat(upgradePriceCost));
+ syncInventoryCommandEmitter.send(new SyncInventoryCommand());
+ }
+
+ @Transactional
+ public void updateItems(SyncInventoryAggregate agr) {
+ for (ItemAggregate item : agr.getItems()) {
+ Optional<ItemModel> it = itemRepository.exists(item.getType());
+ if (it.isPresent()) {
+ itemRepository.fillInventory(item.getType(), item.getQuantity() + it.get().getQuantity());
+ } else {
+ itemRepository.addItem(item.getType(), item.getQuantity());
+ }
+ }
+ }
+
+ public void pay(Float newMoney) {
+ itemRepository.fillInventory(ItemAggregate.ResourceType.MONEY, newMoney);
+ }
+}
diff --git a/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/presentation/rest/HelloWorldResource.java b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/presentation/rest/HelloWorldResource.java
new file mode 100644
index 0000000..e384c22
--- /dev/null
+++ b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/presentation/rest/HelloWorldResource.java
@@ -0,0 +1,19 @@
+package fr.epita.assistants.shop.presentation.rest;
+
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
+
+@Path("/hello")
+@Produces(MediaType.TEXT_PLAIN)
+@Consumes(MediaType.TEXT_PLAIN)
+public class HelloWorldResource {
+ @GET @Path("/")
+ public String helloWorld() {
+ return "Hello World!";
+ }
+
+ @GET @Path("/{name}")
+ public String helloWorld(@PathParam("name") String name) {
+ return "Hello " + name + "!";
+ }
+}
diff --git a/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/presentation/rest/ShopResource.java b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/presentation/rest/ShopResource.java
new file mode 100644
index 0000000..71719d1
--- /dev/null
+++ b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/presentation/rest/ShopResource.java
@@ -0,0 +1,63 @@
+package fr.epita.assistants.shop.presentation.rest;
+
+import fr.epita.assistants.common.api.request.ItemsRequest;
+import fr.epita.assistants.common.api.request.StartRequest;
+import fr.epita.assistants.common.utils.ErrorInfo;
+import fr.epita.assistants.shop.domain.service.ShopService;
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+
+@Path("/")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class ShopResource {
+ private final ShopService shopService;
+
+ @jakarta.inject.Inject
+ public ShopResource(ShopService shopService) {
+ this.shopService = shopService;
+ }
+
+ @Path("/")
+ @GET
+ public Response getRoot() {
+ return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Not implemented")).build();
+ }
+ @Path("/")
+ @POST
+ public Response postRoot() {
+ return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Not implemented")).build();
+ }
+ @Path("resources")
+ @GET
+ public Response resources() {
+ return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Not implemented")).build();
+ }
+ @Path("start")
+ @POST
+ public Response start() {
+ shopService.startShop();
+ return Response.status(Response.Status.NO_CONTENT).build();
+ }
+ @Path("price")
+ @GET
+ public Response price() {
+ return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Not implemented")).build();
+ }
+ @Path("{id}")
+ @POST
+ public Response getShop(@PathParam("id") int id) {
+ return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Not implemented")).build();
+ }
+ @Path("sell/{id}")
+ @PATCH
+ public Response sellItems(@PathParam("id") int id, ItemsRequest itemsRequest) {
+ return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Not implemented")).build();
+ }
+ @Path("upgrade/price/{id}")
+ @PATCH
+ public Response upgradeShop(@PathParam("id") int id) {
+ return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorInfo("Not implemented")).build();
+ }
+}
diff --git a/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/presentation/subscriber/AggregateSubscriber.java b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/presentation/subscriber/AggregateSubscriber.java
new file mode 100644
index 0000000..26247b9
--- /dev/null
+++ b/jws/epibazaar/shop/src/main/java/fr/epita/assistants/shop/presentation/subscriber/AggregateSubscriber.java
@@ -0,0 +1,41 @@
+package fr.epita.assistants.shop.presentation.subscriber;
+
+import fr.epita.assistants.common.aggregate.ItemAggregate;
+import fr.epita.assistants.common.aggregate.ResetInventoryAggregate;
+import fr.epita.assistants.common.aggregate.SyncInventoryAggregate;
+import fr.epita.assistants.common.aggregate.UpgradeItemProducerAggregate;
+import fr.epita.assistants.common.command.CollectItemCommand;
+import fr.epita.assistants.shop.domain.service.ShopService;
+import io.smallrye.reactive.messaging.annotations.Broadcast;
+import jakarta.inject.Inject;
+import org.eclipse.microprofile.reactive.messaging.Incoming;
+import org.eclipse.microprofile.reactive.messaging.Outgoing;
+
+public class AggregateSubscriber {
+ @Inject
+ ShopService shopService;
+
+ @Broadcast
+ @Incoming("sync-inventory-aggregate")
+ public void commandListener(SyncInventoryAggregate aggregate) {
+ shopService.updateItems(aggregate);
+ }
+
+ @Broadcast
+ @Incoming("upgrade-collect-rate-aggregate")
+ public void collectCommandListener(UpgradeItemProducerAggregate agr) {
+ shopService.pay(agr.getNewMoney());
+ }
+
+ @Broadcast
+ @Incoming("upgrade-movement-speed-aggregate")
+ public void moveCommandListener(UpgradeItemProducerAggregate agr) {
+ shopService.pay(agr.getNewMoney());
+ }
+
+ @Broadcast
+ @Incoming("upgrade-stamina-aggregate")
+ public void staminaCommandListener(UpgradeItemProducerAggregate agr) {
+ shopService.pay(agr.getNewMoney());
+ }
+}
diff --git a/jws/epibazaar/shop/src/main/resources/application.properties b/jws/epibazaar/shop/src/main/resources/application.properties
new file mode 100644
index 0000000..e2fa130
--- /dev/null
+++ b/jws/epibazaar/shop/src/main/resources/application.properties
@@ -0,0 +1,13 @@
+%dev.quarkus.http.port=8082
+quarkus.datasource.db-kind=postgresql
+quarkus.datasource.username=postgres
+quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/shop?currentSchema=public
+quarkus.transaction-manager.default-transaction-timeout=3000s
+quarkus.hibernate-orm.log.queries-slower-than-ms=200
+quarkus.http.cors=true
+quarkus.http.cors.origins=*
+quarkus.hibernate-orm.database.generation=drop-and-create
+
+quarkus.kafka.devservices.image-name=reg.undercloud.cri.epita.fr/docker/redpandadata/redpanda:v24.1.2
+quarkus.devservices.enabled=true
+%test.quarkus.devservices.enabled=false
diff --git a/jws/epibazaar/shop/src/main/resources/db/migration/V1__Init.sql b/jws/epibazaar/shop/src/main/resources/db/migration/V1__Init.sql
new file mode 100644
index 0000000..0161cb5
--- /dev/null
+++ b/jws/epibazaar/shop/src/main/resources/db/migration/V1__Init.sql
@@ -0,0 +1,15 @@
+CREATE TABLE IF NOT EXISTS "shop"
+(
+ id SERIAL PRIMARY KEY NOT NULL,
+
+ price_multiplier FLOAT NOT NULL,
+ upgrade_price FLOAT NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS "item"
+(
+ id SERIAL PRIMARY KEY NOT NULL,
+
+ type VARCHAR(64) NOT NULL,
+ quantity FLOAT NOT NULL
+);
diff --git a/jws/epibazaar/shop/src/main/resources/openapi.yaml b/jws/epibazaar/shop/src/main/resources/openapi.yaml
new file mode 100644
index 0000000..7b6928f
--- /dev/null
+++ b/jws/epibazaar/shop/src/main/resources/openapi.yaml
@@ -0,0 +1,242 @@
+---
+openapi: 3.1.0
+tags:
+- name: Game Management
+- name: Inventory Management
+- name: Shop Management
+- name: Shop Operations
+- name: Shop Upgrades
+components:
+ schemas:
+ ItemRequest:
+ type: object
+ properties:
+ quantity:
+ type: number
+ format: float
+ type:
+ $ref: "#/components/schemas/ResourceType"
+ ItemResponse:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int32
+ quantity:
+ type: number
+ format: float
+ type:
+ $ref: "#/components/schemas/ResourceType"
+ ItemsRequest:
+ type: object
+ properties:
+ itemsRequest:
+ type: array
+ items:
+ $ref: "#/components/schemas/ItemRequest"
+ ItemsResponse:
+ type: object
+ properties:
+ itemsResponse:
+ type: array
+ items:
+ $ref: "#/components/schemas/ItemResponse"
+ ResourceType:
+ type: string
+ enum:
+ - MONEY
+ - GROUND
+ - WATER
+ - ROCK
+ - WOOD
+ ShopPriceResponse:
+ type: object
+ properties:
+ shopPrice:
+ type: number
+ format: float
+ ShopResponse:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int32
+ priceMultiplier:
+ type: number
+ format: float
+ upgradePrice:
+ type: number
+ format: float
+ ShopsResponse:
+ type: object
+ properties:
+ shops:
+ type: array
+ items:
+ $ref: "#/components/schemas/ShopResponse"
+paths:
+ /:
+ get:
+ summary: Get all shops.
+ description: Retrieves all available shops.
+ x-quarkus-openapi-method-ref: m869844210_-222983088
+ tags:
+ - Shop Management
+ responses:
+ "200":
+ description: The shops were successfully retrieved.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ShopsResponse"
+ "400":
+ description: The game is not running.
+ servers:
+ - url: http://localhost:8082/
+ post:
+ summary: Create a new shop.
+ description: Creates a new shop.
+ x-quarkus-openapi-method-ref: m869844210_1764851887
+ tags:
+ - Shop Management
+ responses:
+ "204":
+ description: The shop creation request was successfully sent.
+ "400":
+ description: "The game has reached its max capacity, you do not have enough\
+ \ money, or the game is not running."
+ "404":
+ description: No money item found.
+ servers:
+ - url: http://localhost:8082/
+ /price:
+ get:
+ summary: Get the current shop price.
+ description: Retrieves the current shop price.
+ x-quarkus-openapi-method-ref: m869844210_-271831484
+ tags:
+ - Shop Management
+ responses:
+ "200":
+ description: The shop price was successfully retrieved.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ShopPriceResponse"
+ "400":
+ description: The game is not running.
+ servers:
+ - url: http://localhost:8082/
+ /resources:
+ get:
+ summary: Retrieve available resources in inventory.
+ description: Fetch all resources currently available in the inventory.
+ x-quarkus-openapi-method-ref: m911209932_-1184004262
+ tags:
+ - Inventory Management
+ responses:
+ "200":
+ description: The resources were successfully retrieved.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ItemsResponse"
+ "400":
+ description: The game is not running or the request is invalid.
+ servers:
+ - url: http://localhost:8082/
+ /sell/{id}:
+ patch:
+ summary: Sell items to a client.
+ description: Processes the sale of items to a client.
+ x-quarkus-openapi-method-ref: m869844210_-1356306674
+ tags:
+ - Shop Operations
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: integer
+ format: int32
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ItemsRequest"
+ required: true
+ responses:
+ "204":
+ description: The sell request was successfully sent.
+ "400":
+ description: "You do not have enough resources, an item is not sellable,\
+ \ an amount is invalid, or the game is not running."
+ "404":
+ description: The shop or an item was not found.
+ servers:
+ - url: http://localhost:8082/
+ /start:
+ post:
+ summary: Start the game.
+ description: Starts the game by sending a Kafka command.
+ x-quarkus-openapi-method-ref: m869844210_1873672464
+ tags:
+ - Game Management
+ responses:
+ "204":
+ description: The game started successfully.
+ servers:
+ - url: http://localhost:8082/
+ /upgrade/price/{id}:
+ patch:
+ summary: Upgrade the resource price for a specific shop.
+ description: Increases the resource price for a specific shop.
+ x-quarkus-openapi-method-ref: m869844210_-999917025
+ tags:
+ - Shop Upgrades
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: integer
+ format: int32
+ responses:
+ "204":
+ description: The price upgrade request was successfully sent.
+ "400":
+ description: You do not have enough money or the game is not running.
+ "404":
+ description: The shop was not found or the money was not found.
+ servers:
+ - url: http://localhost:8082/
+ /{id}:
+ get:
+ summary: Get a specific shop.
+ description: Retrieves details of a specific shop.
+ x-quarkus-openapi-method-ref: m869844210_868322035
+ tags:
+ - Shop Management
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: integer
+ format: int32
+ responses:
+ "200":
+ description: The shop was successfully retrieved.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ShopResponse"
+ "400":
+ description: The game is not running or the ID is not valid.
+ "404":
+ description: The shop was not found.
+ servers:
+ - url: http://localhost:8082/
+info:
+ title: shop API
+ version: 1.0.0
diff --git a/jws/epibazaar/viewer.tar.gz b/jws/epibazaar/viewer.tar.gz
new file mode 100644
index 0000000..01be4e4
--- /dev/null
+++ b/jws/epibazaar/viewer.tar.gz
Binary files differ