From 8ecc23455f36da01c373b99a536ecd326b26c01a Mon Sep 17 00:00:00 2001 From: ilotterytea Date: Mon, 20 Jan 2025 23:32:34 +0500 Subject: feat: connection between server and game --- server/build.gradle | 3 +- .../frogartha/server/FrogarthaServer.java | 110 +++++++++++++++++++++ .../frogartha/server/PlayerConnection.java | 67 +++++++++++++ .../frogartha/server/ServerHandlers.java | 26 +++++ .../frogartha/server/ServerLauncher.java | 9 +- 5 files changed, 211 insertions(+), 4 deletions(-) create mode 100644 server/src/main/java/kz/ilotterytea/frogartha/server/FrogarthaServer.java create mode 100644 server/src/main/java/kz/ilotterytea/frogartha/server/PlayerConnection.java create mode 100644 server/src/main/java/kz/ilotterytea/frogartha/server/ServerHandlers.java (limited to 'server') diff --git a/server/build.gradle b/server/build.gradle index 1aaf851..d4acfbd 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'application' java.sourceCompatibility = 11 java.targetCompatibility = 11 if (JavaVersion.current().isJava9Compatible()) { - compileJava.options.release.set(11) + compileJava.options.release.set(11) } mainClassName = 'kz.ilotterytea.frogartha.server.ServerLauncher' @@ -12,6 +12,7 @@ application.setMainClass(mainClassName) eclipse.project.name = appName + '-server' dependencies { + api "org.java-websocket:Java-WebSocket:$javaWebsocketVersion" implementation project(':shared') } diff --git a/server/src/main/java/kz/ilotterytea/frogartha/server/FrogarthaServer.java b/server/src/main/java/kz/ilotterytea/frogartha/server/FrogarthaServer.java new file mode 100644 index 0000000..f6a9847 --- /dev/null +++ b/server/src/main/java/kz/ilotterytea/frogartha/server/FrogarthaServer.java @@ -0,0 +1,110 @@ +package kz.ilotterytea.frogartha.server; + +import kz.ilotterytea.frogartha.domain.Identity; +import kz.ilotterytea.frogartha.exceptions.PlayerKickException; +import org.java_websocket.WebSocket; +import org.java_websocket.framing.CloseFrame; +import org.java_websocket.handshake.ClientHandshake; +import org.java_websocket.server.WebSocketServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.ObjectInputStream; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Optional; + +public class FrogarthaServer extends WebSocketServer { + private static FrogarthaServer instance; + + private final Logger log; + private final ArrayList players; + + private FrogarthaServer() { + super(new InetSocketAddress(20015)); + this.log = LoggerFactory.getLogger(FrogarthaServer.class); + this.players = new ArrayList<>(); + } + + @Override + public void onOpen(WebSocket webSocket, ClientHandshake clientHandshake) { + PlayerConnection player = new PlayerConnection(webSocket); + log.info("{} ({}) connected!", player, webSocket.getRemoteSocketAddress().getAddress().getHostAddress()); + this.players.add(player); + } + + @Override + public void onClose(WebSocket webSocket, int i, String s, boolean b) { + Optional player = this.players.stream().filter((x) -> x.getConnection().equals(webSocket)).findFirst(); + + if (player.isPresent()) { + log.info("{} has let! Reason: {} {}", player.get(), i, s); + } else { + log.info("Unknown connection was closed! Reason: {} {}", i, s); + } + } + + @Override + public void onMessage(WebSocket webSocket, String s) { + this.players.removeIf((x) -> x.getConnection().equals(webSocket)); + webSocket.send("Invalid input."); + webSocket.close(CloseFrame.UNEXPECTED_CONDITION); + } + + @Override + public void onMessage(WebSocket conn, ByteBuffer message) { + Optional optionalPlayer = this.players.stream().filter((x) -> x.getConnection().equals(conn)).findFirst(); + + if (optionalPlayer.isEmpty()) { + conn.close(); + return; + } + + PlayerConnection player = optionalPlayer.get(); + + try { + // Deserializing the object + ByteArrayInputStream bais = new ByteArrayInputStream(message.array()); + ObjectInputStream ois = new ObjectInputStream(bais); + Object obj = ois.readObject(); + + if (obj instanceof Identity) ServerHandlers.handleIdentity(player, (Identity) obj); + else throw PlayerKickException.internalServerError(); + } catch (PlayerKickException e) { + kickConnection(player, e); + } catch (Exception e) { + log.error("An exception was thrown while processing message", e); + kickConnection(player, PlayerKickException.internalServerError()); + } + } + + @Override + public void onError(WebSocket webSocket, Exception e) { + log.error("Something went error", e); + } + + @Override + public void onStart() { + log.info("Running the server on port {}", getPort()); + setConnectionLostTimeout(0); + setConnectionLostTimeout(100); + } + + public void kickConnection(PlayerConnection player, PlayerKickException exception) { + player.send(exception); + player.getConnection().close(); + players.remove(player); + log.debug("Kicked out {}! Reason: {}", player, exception.getMessage()); + } + + public static FrogarthaServer getInstance() { + if (instance == null) instance = new FrogarthaServer(); + return instance; + } + + public ArrayList getPlayers() { + return players; + } +} diff --git a/server/src/main/java/kz/ilotterytea/frogartha/server/PlayerConnection.java b/server/src/main/java/kz/ilotterytea/frogartha/server/PlayerConnection.java new file mode 100644 index 0000000..c62dce5 --- /dev/null +++ b/server/src/main/java/kz/ilotterytea/frogartha/server/PlayerConnection.java @@ -0,0 +1,67 @@ +package kz.ilotterytea.frogartha.server; + +import kz.ilotterytea.frogartha.domain.Identity; +import org.java_websocket.WebSocket; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.sql.Timestamp; + +public class PlayerConnection { + private static int TOTAL_CONNECTION_IDS = 0; + + private final int id; + private final WebSocket connection; + private Identity identity; + + private final Timestamp connectedTimestamp; + + public PlayerConnection(WebSocket connection) { + this.connection = connection; + this.id = TOTAL_CONNECTION_IDS; + TOTAL_CONNECTION_IDS++; + + this.connectedTimestamp = new Timestamp(System.currentTimeMillis()); + this.identity = null; + } + + public void send(Object object) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(object); + } catch (IOException ignored) { + + } + + this.connection.send(baos.toByteArray()); + } + + public int getId() { + return id; + } + + public WebSocket getConnection() { + return connection; + } + + public Timestamp getConnectedTimestamp() { + return connectedTimestamp; + } + + public Identity getIdentity() { + return identity; + } + + public void setIdentity(Identity identity) { + this.identity = identity; + } + + @Override + public String toString() { + return "PlayerConnection{" + + "id=" + id + + '}'; + } +} diff --git a/server/src/main/java/kz/ilotterytea/frogartha/server/ServerHandlers.java b/server/src/main/java/kz/ilotterytea/frogartha/server/ServerHandlers.java new file mode 100644 index 0000000..87dc17d --- /dev/null +++ b/server/src/main/java/kz/ilotterytea/frogartha/server/ServerHandlers.java @@ -0,0 +1,26 @@ +package kz.ilotterytea.frogartha.server; + +import kz.ilotterytea.frogartha.domain.Acknowledge; +import kz.ilotterytea.frogartha.domain.Identity; +import kz.ilotterytea.frogartha.exceptions.PlayerKickException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ServerHandlers { + private static final Logger log = LoggerFactory.getLogger(ServerHandlers.class); + private static final FrogarthaServer server = FrogarthaServer.getInstance(); + + public static void handleIdentity(PlayerConnection player, Identity identity) { + if (server.getPlayers() + .stream() + .filter((x) -> x.getIdentity() != null) + .anyMatch((x) -> x.getIdentity().equals(identity) && x.getId() != player.getId())) { + server.kickConnection(player, PlayerKickException.loggedIn()); + return; + } + + player.setIdentity(identity); + player.send(new Acknowledge(player)); + log.debug("Successfully identified {} for {}", identity, player); + } +} diff --git a/server/src/main/java/kz/ilotterytea/frogartha/server/ServerLauncher.java b/server/src/main/java/kz/ilotterytea/frogartha/server/ServerLauncher.java index fc7c1e5..8c07f64 100644 --- a/server/src/main/java/kz/ilotterytea/frogartha/server/ServerLauncher.java +++ b/server/src/main/java/kz/ilotterytea/frogartha/server/ServerLauncher.java @@ -1,8 +1,11 @@ package kz.ilotterytea.frogartha.server; -/** Launches the server application. */ +/** + * Launches the server application. + */ public class ServerLauncher { public static void main(String[] args) { - // TODO Implement server application. + FrogarthaServer server = FrogarthaServer.getInstance(); + server.start(); } -} \ No newline at end of file +} -- cgit v1.2.3