diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 4343a0f7..65d8375b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -51,14 +51,13 @@ jobs:
strategy:
fail-fast: false
matrix:
- platform: [macos-latest, ubuntu-20.04, windows-latest]
+ platform: [windows-latest]
defaults:
run:
working-directory: 'frontend'
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
-
- name: setup node
uses: actions/setup-node@v4
with:
@@ -67,6 +66,10 @@ jobs:
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
+ - uses: Swatinem/rust-cache@v2
+ with:
+ key: ${{ matrix.config.rust_target }}
+
- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-20.04'
run: |
@@ -79,4 +82,6 @@ jobs:
# If tagName and releaseId are omitted tauri-action will only build the app and won't try to upload any asstes.
- uses: tauri-apps/tauri-action@v0
env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
+ TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
\ No newline at end of file
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index e5b7046d..9c397d81 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -13,7 +13,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- platform: [macos-latest, ubuntu-20.04, windows-latest]
+ platform: [windows-latest]
defaults:
run:
working-directory: 'frontend'
@@ -29,6 +29,10 @@ jobs:
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
+ - uses: Swatinem/rust-cache@v2
+ with:
+ key: ${{ matrix.config.rust_target }}
+
- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-20.04'
run: |
@@ -41,12 +45,15 @@ jobs:
- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
+ TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
with:
- tagName: app-v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version
+ tagName: betterfleet-v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version
releaseName: "BetterFleet v__VERSION__"
releaseBody: "See the assets to download this version and install."
releaseDraft: true
prerelease: false
+
publish-backend:
name: Backend app
runs-on: ubuntu-latest
diff --git a/.gitignore b/.gitignore
index 5233c456..11a36e97 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
-deployement/psql-data/
+deployment/psql-data/
.idea/
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index 261eeb9e..b51aaae6 100644
--- a/LICENSE
+++ b/LICENSE
@@ -2,6 +2,20 @@
Version 2.0, January 2004
http://www.apache.org/licenses/
+ 0. Specific Exclusion Clause.
+
+ It is expressly stipulated that [Lazarus], identified by their online pseudonym
+ associated with the creation and management of the FleetCreator application,
+ is under no circumstances granted the right to use, modify, distribute,
+ or sell the [BetterFleet] application (the "Product"), for both personal
+ and commercial purposes. This prohibition is indefinite until expressly
+ revoked in writing by the Product's owner. Any violation of this clause will
+ result in legal action and demands for remedy in accordance with applicable laws.
+
+ This clause is incorporated into the Project [BetterFleet]'s license,
+ and its breach constitutes an infringement of the terms of this license,
+ potentially leading to civil and/or criminal penalties.
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
diff --git a/README.md b/README.md
index 6225be0d..6111c506 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,76 @@
-![banner](/frontend/src/assets/banners/banner.png)
-# BetterFleet
\ No newline at end of file
+![image](/frontend/src/assets/banners/banner.png)
+
+# BetterFleet
+
+## About BetterFleet
+
+BetterFleet is a free open source application designed to enhance the gaming experience in Sea Of Thieves by
+facilitating the creation of alliances among players. With BetterFleet, you can organize game sessions and invite your
+friends to join in a simple and intuitive manner.
+
+:warning: BetterFleet is not an official application of Sea Of Thieves. It was developed by the community for
+players looking to improve their gaming experience.
+---
+
+## Features
+
+- **Automatic Session Management:** Facilitates joining the same server with your friends by providing real-time in-game status and server information.
+
+- **Increase likelihood of finding a server:** Includes an automatic "Set sail" feature so that everyone clicks at the same time.
+
+- **Self-Hosted Backend:** The open-source nature of the application allows users to host the backend, offering greater control over deployment and maintenance.
+
+- **Statistics Tracking:** Provides statistical insights to help users assess their server-finding success rate.
+---
+
+## Comparison of Fleet Management Applications: BetterFleet vs. FleetCreator
+
+| Feature | BetterFleet | FleetCreator |
+|---------------------------------------|-----------------------------|-----------------------------|
+| Speed | :question: (Need benchmark) | :question: (Need benchmark) |
+| Ad free | :white_check_mark: | :x: |
+| Complete free access | :white_check_mark: | :x: |
+| UX friendly | :white_check_mark: | :x: |
+| Open source | :white_check_mark: | :x: |
+| IPv6 support | :white_check_mark: | :x: |
+| Automatic click between the same crew | :white_check_mark: | :x: |
+| Size of file | <20MB | >200MB |
+| No memory leak | :white_check_mark: | :warning:* |
+
+\* FleetCreator has been observed to consume 8GB of RAM after 10 hours of usage, indicating a possible memory leak.
+
+---
+
+## OS Compatibility
+
+| Operating System | Compatible |
+|------------------|--------------------|
+| Windows 11 | :white_check_mark: |
+| Windows 10 | :white_check_mark: |
+| macOS | :x: |
+| Linux | :x: |
+
+---
+
+## Credits đ„
+
+- **Development:** [Zelytra](https://zelytra.fr) & [dadodasyra](https://github.com/dadodasyra)
+- **Design/Graphics:** [ZeTro](https://zetro.fr)
+- **Translator/proofreader:** [Ichabodt](https://github.com/Ichabodt)
+
+We thank everyone who contributes to making BetterFleet better every day. If you would like to contribute to the
+project, feel free to fork the repository and submit your pull requests.
+
+---
+
+## License đ
+
+BetterFleet is distributed under the MIT license. See the [LICENSE](/LICENSE) file for more information.
+
+---
+
+## Support
+
+If you have any questions or encounter problems with the app, please open an issue.
+
+We hope you enjoy using BetterFleet as much as we enjoyed developing it!
diff --git a/backend/pom.xml b/backend/pom.xml
index 56a9bd92..94fbf969 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -13,7 +13,7 @@
UTF-8quarkus-bomio.quarkus.platform
- 3.7.4
+ 3.8.1true3.2.5
@@ -52,10 +52,20 @@
rest-assuredtest
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+ 2.16.1
+ io.quarkusquarkus-websockets
+
+ org.json
+ json
+ 20231013
+
diff --git a/backend/src/main/java/fr/zelytra/PublicEndpoints.java b/backend/src/main/java/fr/zelytra/PublicEndpoints.java
index aa2a8bee..c247f703 100644
--- a/backend/src/main/java/fr/zelytra/PublicEndpoints.java
+++ b/backend/src/main/java/fr/zelytra/PublicEndpoints.java
@@ -1,12 +1,9 @@
package fr.zelytra;
-import io.quarkus.logging.Log;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
-import java.util.UUID;
-
@Path("/")
public class PublicEndpoints {
diff --git a/backend/src/main/java/fr/zelytra/session/SessionManager.java b/backend/src/main/java/fr/zelytra/session/SessionManager.java
index 15ce4bc7..ced13d27 100644
--- a/backend/src/main/java/fr/zelytra/session/SessionManager.java
+++ b/backend/src/main/java/fr/zelytra/session/SessionManager.java
@@ -1,13 +1,15 @@
package fr.zelytra.session;
-import com.fasterxml.jackson.databind.ObjectMapper;
import fr.zelytra.session.fleet.Fleet;
-import fr.zelytra.session.fleet.Player;
+import fr.zelytra.session.player.Player;
+import fr.zelytra.session.server.SotServer;
+import fr.zelytra.session.socket.MessageType;
import io.quarkus.logging.Log;
import jakarta.annotation.Nullable;
-import java.io.IOException;
-import java.util.*;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
/**
* Manages sessions for a multiplayer game, allowing players to create, join, and leave sessions.
@@ -18,11 +20,15 @@ public class SessionManager {
private final HashMap sessions;
+ // SotServer cached to avoid API spam and faster server response
+ private final HashMap sotServers;
+
/**
* Private constructor for singleton pattern.
*/
private SessionManager() {
this.sessions = new HashMap<>();
+ this.sotServers = new HashMap<>();
}
/**
@@ -65,9 +71,9 @@ public boolean isSessionExist(String sessionId) {
*
* @param sessionId The ID of the session to join.
* @param player The player attempting to join the session.
- * @return true if the player was successfully added, false otherwise.
+ * @return the Fleet where the player was added or null
*/
- public boolean joinSession(String sessionId, Player player) {
+ public Fleet joinSession(String sessionId, Player player) {
// First, leave any session the player might currently be in
if (getPlayerFromSessionId(player.getSocket().getId()) != null) {
leaveSession(player);
@@ -76,11 +82,11 @@ public boolean joinSession(String sessionId, Player player) {
Fleet fleet = getFleetFromId(sessionId);
if (fleet == null) {
Log.error("[" + sessionId + "] Session doesnt exist for player : " + player.getUsername());
- return false;
+ return null;
}
fleet.getPlayers().add(player);
Log.info("[" + sessionId + "] " + player.getUsername() + " Join the session !");
- return true;
+ return fleet;
}
/**
@@ -91,7 +97,10 @@ public boolean joinSession(String sessionId, Player player) {
public void leaveSession(Player player) {
for (Fleet fleet : sessions.values()) {
fleet.getPlayers().remove(player);
- SessionSocket.broadcastSessionUpdate(fleet.getSessionId());
+ fleet.getServers().forEach((key, value) -> {
+ value.getConnectedPlayers().remove(player);
+ });
+ SessionSocket.broadcastDataToSession(fleet.getSessionId(), MessageType.UPDATE, fleet);
Log.info("[" + fleet.getSessionId() + "] " + player.getUsername() + " Leave the session !");
// Clean empty session
@@ -170,5 +179,55 @@ public boolean isPlayerInSession(Player player, String sessionId) {
return false; // The specified player is not found in the session
}
+ public SotServer getServerFromHashing(SotServer server) {
+ String hash = server.generateHash();
+
+ // Return cached SOT server
+ if (sotServers.containsKey(hash)) {
+ return sotServers.get(hash);
+ }
+
+ // The object inject may not be completed, so we're creating fresh one to make sure all data has been initialized
+ SotServer newServer = new SotServer(server.getIp(), server.getPort());
+ sotServers.put(newServer.getHash(), newServer);
+ return newServer;
+ }
+ public void playerJoinSotServer(Player player, SotServer server) {
+ SotServer findedSotServer = getServerFromHashing(server);
+
+ Fleet fleet = getFleetByPlayerName(player.getUsername());
+ assert fleet != null;
+
+ // Detect if the server is not already know by the fleet
+ if (!fleet.getServers().containsKey(findedSotServer.getHash())) {
+ fleet.getServers().put(findedSotServer.getHash(), findedSotServer);
+ }
+ // Do not add player if already in
+ if (fleet.getServers().get(findedSotServer.getHash()).getConnectedPlayers().contains(player)) {
+ return;
+ }
+
+ // Add player to SotServer in Fleet and broadcast update
+ fleet.getServers().get(findedSotServer.getHash()).getConnectedPlayers().add(player);
+ Log.info("[" + fleet.getSessionId() + "] " + player.getUsername() + " join the SotServer: " + fleet.getServers().get(findedSotServer.getHash()).getHash());
+ SessionSocket.broadcastDataToSession(fleet.getSessionId(), MessageType.UPDATE, fleet);
+ }
+
+ public void playerLeaveSotServer(Player player, SotServer server) {
+ SotServer findedSotServer = getServerFromHashing(server);
+
+ Fleet fleet = getFleetByPlayerName(player.getUsername());
+ assert fleet != null;
+
+ SotServer fleetFindedServer = fleet.getServers().get(findedSotServer.getHash());
+ fleetFindedServer.getConnectedPlayers().remove(player);
+
+ // If SotServer empty remove server from the list
+ if (fleetFindedServer.getConnectedPlayers().isEmpty()) {
+ fleet.getServers().remove(fleetFindedServer.getHash());
+ }
+ Log.info("[" + fleet.getSessionId() + "] " + player.getUsername() + " leave the SotServer: " + fleetFindedServer.getHash());
+ SessionSocket.broadcastDataToSession(fleet.getSessionId(), MessageType.UPDATE, fleet);
+ }
}
diff --git a/backend/src/main/java/fr/zelytra/session/SessionSocket.java b/backend/src/main/java/fr/zelytra/session/SessionSocket.java
index 49ac333e..f31ea644 100644
--- a/backend/src/main/java/fr/zelytra/session/SessionSocket.java
+++ b/backend/src/main/java/fr/zelytra/session/SessionSocket.java
@@ -1,11 +1,18 @@
package fr.zelytra.session;
import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import fr.zelytra.session.countdown.SessionCountDown;
import fr.zelytra.session.fleet.Fleet;
-import fr.zelytra.session.fleet.Player;
+import fr.zelytra.session.player.Player;
+import fr.zelytra.session.server.SotServer;
+import fr.zelytra.session.socket.MessageType;
+import fr.zelytra.session.socket.SocketMessage;
import io.quarkus.logging.Log;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.websocket.*;
@@ -13,7 +20,7 @@
import jakarta.websocket.server.ServerEndpoint;
import java.io.IOException;
-import java.util.Objects;
+import java.util.TimeZone;
import java.util.concurrent.*;
@ServerEndpoint("/sessions/{sessionId}") // WebSocket endpoint
@@ -39,55 +46,128 @@ public void onOpen(Session session) {
});
sessionTimeoutTasks.put(session.getId(), timeoutTask);
Log.info("[ANYONE] Connecting...");
-
}
+
@OnMessage
public void onMessage(String message, Session session, @PathParam("sessionId") String sessionId) throws JsonProcessingException {
- // Cancel the timeout task since we've received the message
- Future> timeoutTask = sessionTimeoutTasks.remove(session.getId());
- if (timeoutTask != null) {
- timeoutTask.cancel(true);
- }
-
ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);
- Player player = objectMapper.readValue(message, Player.class);
- player.setSocket(session);
+ // Deserialize the incoming message to SocketMessage>
+ SocketMessage> socketMessage = objectMapper.readValue(message, new TypeReference<>() {
+ });
+
+ // Handle the message based on its type
+ switch (socketMessage.messageType()) {
+ case CONNECT -> {
+ Player player = objectMapper.convertValue(socketMessage.data(), Player.class);
+ handleConnectMessage(player, session, sessionId);
+ }
+ case UPDATE -> {
+ Player player = objectMapper.convertValue(socketMessage.data(), Player.class);
+ handleLeaveMessage(player);
+ }
+ case START_COUNTDOWN -> {
+ SessionCountDown countDown = objectMapper.convertValue(socketMessage.data(), SessionCountDown.class);
+ handleStartCountdown(session, countDown);
+ }
+ case CLEAR_STATUS -> {
+ handleClearStatus(session);
+ }
+ case JOIN_SERVER -> {
+ SotServer sotServer = objectMapper.convertValue(socketMessage.data(), SotServer.class);
+ handleJoinServerMessage(session, sotServer);
+ }
+ case LEAVE_SERVER -> {
+ SotServer sotServer = objectMapper.convertValue(socketMessage.data(), SotServer.class);
+ handleLeaveServerMessage(session, sotServer);
+ }
+ default -> Log.info("Unhandled message type: " + socketMessage.messageType());
+ }
+ }
+
+ private void handleClearStatus(Session session) {
SessionManager manager = SessionManager.getInstance();
+ Player player = manager.getPlayerFromSessionId(session.getId());
+ Fleet fleet = manager.getFleetByPlayerName(player.getUsername());
+ fleet.getPlayers().forEach((playerInList) -> {
+ playerInList.setReady(false);
+ });
+ Log.info("[" + fleet.getSessionId() + "] Clearing status of all player");
+ broadcastDataToSession(fleet.getSessionId(), MessageType.UPDATE, fleet);
+ }
- //Check if it's an update player request
- if (manager.isPlayerInSession(player, player.getSessionId())) {
+ private void handleStartCountdown(Session session, SessionCountDown countDown) {
- Fleet fleet = manager.getFleetFromId(player.getSessionId());
- assert fleet != null;
- Player foundedplayer = fleet.getPlayerFromUsername(player.getUsername());
+ countDown.calculateClickTime();
- foundedplayer.setReady(player.isReady());
- foundedplayer.setStatus(player.getStatus());
+ SessionManager manager = SessionManager.getInstance();
+ Player player = manager.getPlayerFromSessionId(session.getId());
+ Fleet fleet = manager.getFleetByPlayerName(player.getUsername());
- broadcastSessionUpdate(player.getSessionId().toUpperCase());
+ Log.info("[" + fleet.getSessionId() + "] Starting countdown at " + countDown.getClickTime().toString());
+ broadcastDataToSession(fleet.getSessionId(), MessageType.RUN_COUNTDOWN, countDown);
+ }
- Log.info("[" + player.getUsername() + "] Data updated for session !");
- return;
+ // Extracted method to handle JOIN_SERVER messages
+ private void handleJoinServerMessage(Session session, SotServer sotServer) {
+ SessionManager manager = SessionManager.getInstance();
+ Player player = manager.getPlayerFromSessionId(session.getId());
+ manager.playerJoinSotServer(player, sotServer);
+ }
+
+ // Extracted method to handle LEAVE_SERVER messages
+ private void handleLeaveServerMessage(Session session, SotServer sotServer) {
+ SessionManager manager = SessionManager.getInstance();
+ Player player = manager.getPlayerFromSessionId(session.getId());
+ manager.playerLeaveSotServer(player, sotServer);
+ }
+
+ // Extracted method to handle CONNECT messages
+ private void handleConnectMessage(Player player, Session session, String sessionId) {
+ // Cancel the timeout task since we've received the message
+ Future> timeoutTask = sessionTimeoutTasks.remove(session.getId());
+ if (timeoutTask != null) {
+ timeoutTask.cancel(true);
}
+ SessionManager manager = SessionManager.getInstance();
+ player.setSocket(session);
+
Log.info("[" + player.getUsername() + "] Connected !");
+
//Create session if no id provided
if (sessionId == null || sessionId.isEmpty()) {
String newSessionId = manager.createSession();
- manager.joinSession(newSessionId, player);
+ Fleet fleet = manager.joinSession(newSessionId, player);
player.setMaster(true);
- broadcastSessionUpdate(newSessionId);
+ broadcastDataToSession(newSessionId, MessageType.UPDATE, fleet);
} else {
- manager.joinSession(sessionId, player);
- broadcastSessionUpdate(sessionId);
+ Fleet fleet = manager.joinSession(sessionId, player);
+ broadcastDataToSession(sessionId, MessageType.UPDATE, fleet);
}
+
+ }
+
+ // Extracted method to handle LEAVE messages
+ private void handleLeaveMessage(Player player) {
+ SessionManager manager = SessionManager.getInstance();
+ Fleet fleet = manager.getFleetFromId(player.getSessionId());
+ assert fleet != null;
+ Player foundedplayer = fleet.getPlayerFromUsername(player.getUsername());
+
+ foundedplayer.setReady(player.isReady());
+ foundedplayer.setStatus(player.getStatus());
+
+ broadcastDataToSession(player.getSessionId(), MessageType.UPDATE, fleet);
+
+ Log.info("[" + player.getUsername() + "] Data updated for session !");
}
@OnClose
@@ -120,10 +200,28 @@ public void onError(Session session, Throwable throwable) throws IOException {
session.close();
}
+
/**
- * @param sessionId Fleet session id
+ * Broadcasts a message to all players within a session.
+ *
+ * This method sends a specified data object to all players in a session identified by the sessionId. The message type
+ * and data to be broadcast are specified by the parameters. It uses {@link SessionManager} to check if the session
+ * exists and to retrieve the corresponding {@link Fleet} of players. If the session does not exist, it logs an info
+ * message and returns without sending any data. It constructs a {@link SocketMessage} with the messageType and data,
+ * converts it into JSON format, and then broadcasts this JSON string to all players in the session using their sockets.
+ * If any error occurs during the JSON conversion or broadcasting, it logs an error or throws an {@link Error} respectively.
+ *
+ * @param The type of data to be broadcasted. This allows the method to be used with various types of
+ * data objects.
+ * @param sessionId The ID of the session to which the data will be broadcast. This is used to identify the
+ * group of players who should receive the message.
+ * @param messageType The type of the message to be sent. This helps in identifying the purpose or action of
+ * the message on the client side.
+ * @param data The data to be broadcast. This is the actual content of the message being sent to the players.
+ * The type of this data is generic, allowing for flexibility in what can be sent.
+ * @throws Error if there is an issue with converting the {@link SocketMessage} object to a JSON string.
*/
- public static void broadcastSessionUpdate(String sessionId) {
+ public static void broadcastDataToSession(String sessionId, MessageType messageType, T data) {
SessionManager manager = SessionManager.getInstance();
if (!manager.isSessionExist(sessionId)) {
@@ -133,21 +231,28 @@ public static void broadcastSessionUpdate(String sessionId) {
Fleet fleet = manager.getFleetFromId(sessionId);
assert fleet != null;
- // Send to all players the Fleet data
+ SocketMessage message = new SocketMessage<>(messageType, data);
+
+ // Send to all players the Countdown data
ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.registerModule(new JavaTimeModule());
+ objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // To serialize as ISO-8601 strings
+ objectMapper.setTimeZone(TimeZone.getTimeZone("UTC"));
String json;
try {
- json = objectMapper.writeValueAsString(fleet);
+ json = objectMapper.writeValueAsString(message);
} catch (JsonProcessingException e) {
- throw new RuntimeException(e);
+ throw new Error(e);
}
for (Player player : fleet.getPlayers()) {
player.getSocket().getAsyncRemote().sendText(json, result -> {
if (result.getException() != null) {
- System.out.println("Unable to send message: " + result.getException());
+ Log.error("Unable to send message: " + result.getException());
}
});
}
}
+
+
}
diff --git a/backend/src/main/java/fr/zelytra/session/fleet/SessionStatus.java b/backend/src/main/java/fr/zelytra/session/SessionStatus.java
similarity index 85%
rename from backend/src/main/java/fr/zelytra/session/fleet/SessionStatus.java
rename to backend/src/main/java/fr/zelytra/session/SessionStatus.java
index 080fe0cf..08ffe79c 100644
--- a/backend/src/main/java/fr/zelytra/session/fleet/SessionStatus.java
+++ b/backend/src/main/java/fr/zelytra/session/SessionStatus.java
@@ -1,4 +1,4 @@
-package fr.zelytra.session.fleet;
+package fr.zelytra.session;
public enum SessionStatus {
WAITING, // Waiting for player to be ready
diff --git a/backend/src/main/java/fr/zelytra/session/countdown/SessionCountDown.java b/backend/src/main/java/fr/zelytra/session/countdown/SessionCountDown.java
new file mode 100644
index 00000000..6d83a2c9
--- /dev/null
+++ b/backend/src/main/java/fr/zelytra/session/countdown/SessionCountDown.java
@@ -0,0 +1,37 @@
+package fr.zelytra.session.countdown;
+
+import java.time.LocalTime;
+
+public class SessionCountDown {
+ private LocalTime startingTimer;
+ private LocalTime clickTime;
+
+ public SessionCountDown() {
+
+ }
+
+ public SessionCountDown(LocalTime startingTimer) {
+ this.startingTimer = startingTimer;
+ calculateClickTime();
+ }
+
+ public void calculateClickTime() {
+ this.clickTime = startingTimer.plusSeconds(6);
+ }
+
+ public LocalTime getStartingTimer() {
+ return startingTimer;
+ }
+
+ public void setStartingTimer(LocalTime startingTimer) {
+ this.startingTimer = startingTimer;
+ }
+
+ public LocalTime getClickTime() {
+ return clickTime;
+ }
+
+ public void setClickTime(LocalTime clickTime) {
+ this.clickTime = clickTime;
+ }
+}
diff --git a/backend/src/main/java/fr/zelytra/session/fleet/Fleet.java b/backend/src/main/java/fr/zelytra/session/fleet/Fleet.java
index 2cd88ae2..d0861159 100644
--- a/backend/src/main/java/fr/zelytra/session/fleet/Fleet.java
+++ b/backend/src/main/java/fr/zelytra/session/fleet/Fleet.java
@@ -1,6 +1,11 @@
package fr.zelytra.session.fleet;
+import fr.zelytra.session.SessionStatus;
+import fr.zelytra.session.player.Player;
+import fr.zelytra.session.server.SotServer;
+
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
@@ -9,14 +14,14 @@ public class Fleet {
private String sessionId;
private String sessionName;
private List players;
- private List servers;
+ private final HashMap servers;
private SessionStatus status;
public Fleet(String sessionId) {
this.sessionId = sessionId;
this.sessionName = "A session name"; //TODO
this.players = new ArrayList<>();
- this.servers = new ArrayList<>();
+ this.servers = new HashMap<>();
this.status = SessionStatus.WAITING;
}
@@ -53,14 +58,10 @@ public void setPlayers(List players) {
this.players = players;
}
- public List getServers() {
+ public HashMap getServers() {
return servers;
}
- public void setServers(List servers) {
- this.servers = servers;
- }
-
public SessionStatus getStatus() {
return status;
}
diff --git a/backend/src/main/java/fr/zelytra/session/fleet/PlayerStates.java b/backend/src/main/java/fr/zelytra/session/fleet/PlayerStates.java
deleted file mode 100644
index b7bfc2bf..00000000
--- a/backend/src/main/java/fr/zelytra/session/fleet/PlayerStates.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package fr.zelytra.session.fleet;
-
-public enum PlayerStates {
- OFFLINE, // Game not detected
- ONLINE, // Game detected and open but not in game
- IN_GAME // Player in a server
-}
-
diff --git a/backend/src/main/java/fr/zelytra/session/fleet/SotServer.java b/backend/src/main/java/fr/zelytra/session/fleet/SotServer.java
deleted file mode 100644
index b93dde3d..00000000
--- a/backend/src/main/java/fr/zelytra/session/fleet/SotServer.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package fr.zelytra.session.fleet;
-
-import java.util.List;
-
-public class SotServer {
-
- private String ip;
- private int port;
- private String location;
- private List connectedPlayers;
-
- // Constructor
- public SotServer(String ip, int port, String location, List connectedPlayers) {
- this.ip = ip;
- this.port = port;
- this.location = location;
- this.connectedPlayers = connectedPlayers;
- }
-
- // Getters and Setters
- public String getIp() {
- return ip;
- }
-
- public void setIp(String ip) {
- this.ip = ip;
- }
-
- public int getPort() {
- return port;
- }
-
- public void setPort(int port) {
- this.port = port;
- }
-
- public String getLocation() {
- return location;
- }
-
- public void setLocation(String location) {
- this.location = location;
- }
-
- public List getConnectedPlayers() {
- return connectedPlayers;
- }
-
- public void setConnectedPlayers(List connectedPlayers) {
- this.connectedPlayers = connectedPlayers;
- }
-}
-
diff --git a/backend/src/main/java/fr/zelytra/session/ip/ProxyCheckAPI.java b/backend/src/main/java/fr/zelytra/session/ip/ProxyCheckAPI.java
new file mode 100644
index 00000000..afadc764
--- /dev/null
+++ b/backend/src/main/java/fr/zelytra/session/ip/ProxyCheckAPI.java
@@ -0,0 +1,84 @@
+package fr.zelytra.session.ip;
+
+import io.quarkus.logging.Log;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+/**
+ * Class retrieving data from ProxyChecker api
+ * web site
+ *