diff --git a/.idea/FuzzierSettings.xml b/.idea/FuzzierSettings.xml
index 4426b5e..0344d88 100644
--- a/.idea/FuzzierSettings.xml
+++ b/.idea/FuzzierSettings.xml
@@ -9,6 +9,6 @@
-
+
\ No newline at end of file
diff --git a/common/src/main/java/cz/jzitnik/common/socket/messages/game/creation/CreateGame.java b/common/src/main/java/cz/jzitnik/common/socket/messages/game/creation/CreateGame.java
new file mode 100644
index 0000000..ad4a593
--- /dev/null
+++ b/common/src/main/java/cz/jzitnik/common/socket/messages/game/creation/CreateGame.java
@@ -0,0 +1,6 @@
+package cz.jzitnik.common.socket.messages.game.creation;
+
+import cz.jzitnik.common.socket.SocketMessage;
+
+public class CreateGame implements SocketMessage {
+}
diff --git a/common/src/main/java/cz/jzitnik/common/socket/messages/game/creation/CreateGameResponse.java b/common/src/main/java/cz/jzitnik/common/socket/messages/game/creation/CreateGameResponse.java
new file mode 100644
index 0000000..30ded32
--- /dev/null
+++ b/common/src/main/java/cz/jzitnik/common/socket/messages/game/creation/CreateGameResponse.java
@@ -0,0 +1,6 @@
+package cz.jzitnik.common.socket.messages.game.creation;
+
+import cz.jzitnik.common.socket.SocketMessage;
+
+public class CreateGameResponse implements SocketMessage {
+}
diff --git a/game/src/main/java/cz/jzitnik/client/Game.java b/game/src/main/java/cz/jzitnik/client/Game.java
index b7c5496..ca2c77b 100644
--- a/game/src/main/java/cz/jzitnik/client/Game.java
+++ b/game/src/main/java/cz/jzitnik/client/Game.java
@@ -13,7 +13,7 @@ import org.reflections.Reflections;
import java.io.IOException;
public class Game {
- private final DependencyManager dependencyManager = new DependencyManager(new Reflections("cz.jzitnik"));
+ private final DependencyManager dependencyManager = new DependencyManager(new Reflections("cz.jzitnik.client"));
@InjectDependency
private Cli cli;
diff --git a/game/src/main/java/cz/jzitnik/client/ui/GlobalShortcuts.java b/game/src/main/java/cz/jzitnik/client/ui/GlobalShortcuts.java
index 9ff3cb3..02b0ac4 100644
--- a/game/src/main/java/cz/jzitnik/client/ui/GlobalShortcuts.java
+++ b/game/src/main/java/cz/jzitnik/client/ui/GlobalShortcuts.java
@@ -5,11 +5,9 @@ import cz.jzitnik.client.annotations.Dependency;
import cz.jzitnik.client.annotations.injectors.InjectDependency;
import cz.jzitnik.client.annotations.ui.KeyboardPressHandler;
import cz.jzitnik.client.annotations.ui.UI;
-import cz.jzitnik.client.events.ExitEvent;
-import cz.jzitnik.client.events.FullRedrawEvent;
-import cz.jzitnik.client.events.KeyboardPressEvent;
-import cz.jzitnik.client.events.PlayerMoveEvent;
+import cz.jzitnik.client.events.*;
import cz.jzitnik.client.utils.events.EventManager;
+import cz.jzitnik.common.socket.messages.Test;
@UI
@Dependency
@@ -37,4 +35,11 @@ public class GlobalShortcuts {
eventManager.emitEvent(new PlayerMoveEvent(event.getKeyStroke()));
return true;
}
+
+ @KeyboardPressHandler(character = 'p')
+ public boolean debugSocket(KeyboardPressEvent event) {
+ eventManager.emitEvent(new SendSocketMessageEvent(new Test()));
+
+ return true;
+ }
}
diff --git a/server/pom.xml b/server/pom.xml
index 6b9d574..88631d2 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -62,5 +62,11 @@
logback-classic
1.5.25
+
+
+ org.reflections
+ reflections
+ 0.10.2
+
diff --git a/server/src/main/java/cz/jzitnik/server/Main.java b/server/src/main/java/cz/jzitnik/server/Main.java
index a752d0a..bd7e836 100644
--- a/server/src/main/java/cz/jzitnik/server/Main.java
+++ b/server/src/main/java/cz/jzitnik/server/Main.java
@@ -1,14 +1,24 @@
package cz.jzitnik.server;
+import cz.jzitnik.server.context.AppContext;
+import cz.jzitnik.server.context.GlobalContext;
+import cz.jzitnik.server.events.EventManager;
+import cz.jzitnik.server.socket.WebSocket;
import jakarta.websocket.DeploymentException;
import org.glassfish.tyrus.server.Server;
+import org.reflections.Reflections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Scanner;
+import java.util.*;
public class Main {
static void main() throws DeploymentException {
+ GlobalContext globalContext = new GlobalContext();
+ AppContext.set(globalContext);
+
+ EventManager eventManager = new EventManager(new Reflections("cz.jzitnik.server"), globalContext);
+ globalContext.setEventManager(eventManager);
+ eventManager.start();
+
Map properties = new HashMap<>();
Server server = new Server("localhost", 8025, "/", properties, WebSocket.class);
diff --git a/server/src/main/java/cz/jzitnik/server/annotations/EventHandler.java b/server/src/main/java/cz/jzitnik/server/annotations/EventHandler.java
new file mode 100644
index 0000000..efc0d51
--- /dev/null
+++ b/server/src/main/java/cz/jzitnik/server/annotations/EventHandler.java
@@ -0,0 +1,14 @@
+package cz.jzitnik.server.annotations;
+
+import cz.jzitnik.common.socket.SocketMessage;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface EventHandler {
+ Class extends SocketMessage> value();
+}
diff --git a/server/src/main/java/cz/jzitnik/server/context/AppContext.java b/server/src/main/java/cz/jzitnik/server/context/AppContext.java
new file mode 100644
index 0000000..73f719f
--- /dev/null
+++ b/server/src/main/java/cz/jzitnik/server/context/AppContext.java
@@ -0,0 +1,13 @@
+package cz.jzitnik.server.context;
+
+public class AppContext {
+ private static GlobalContext globalContext;
+
+ public static void set(GlobalContext context) {
+ globalContext = context;
+ }
+
+ public static GlobalContext get() {
+ return globalContext;
+ }
+}
diff --git a/server/src/main/java/cz/jzitnik/server/context/GameManager.java b/server/src/main/java/cz/jzitnik/server/context/GameManager.java
new file mode 100644
index 0000000..6ff385e
--- /dev/null
+++ b/server/src/main/java/cz/jzitnik/server/context/GameManager.java
@@ -0,0 +1,4 @@
+package cz.jzitnik.server.context;
+
+public class GameManager {
+}
diff --git a/server/src/main/java/cz/jzitnik/server/context/GlobalContext.java b/server/src/main/java/cz/jzitnik/server/context/GlobalContext.java
new file mode 100644
index 0000000..52519d2
--- /dev/null
+++ b/server/src/main/java/cz/jzitnik/server/context/GlobalContext.java
@@ -0,0 +1,24 @@
+package cz.jzitnik.server.context;
+
+import cz.jzitnik.server.game.Client;
+import cz.jzitnik.server.events.EventManager;
+import cz.jzitnik.server.socket.SocketSession;
+import jakarta.websocket.Session;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.HashMap;
+
+public class GlobalContext {
+ @Getter
+ private final HashMap sessions = new HashMap<>();
+
+ @Getter
+ @Setter
+ private EventManager eventManager;
+
+ public void registerClient(Session session) {
+ Client client = new Client(new SocketSession(session));
+ sessions.put(session, client);
+ }
+}
diff --git a/server/src/main/java/cz/jzitnik/server/events/AbstractEventHandler.java b/server/src/main/java/cz/jzitnik/server/events/AbstractEventHandler.java
new file mode 100644
index 0000000..603b424
--- /dev/null
+++ b/server/src/main/java/cz/jzitnik/server/events/AbstractEventHandler.java
@@ -0,0 +1,8 @@
+package cz.jzitnik.server.events;
+
+import cz.jzitnik.common.socket.SocketMessage;
+import cz.jzitnik.server.game.Client;
+
+public abstract class AbstractEventHandler {
+ public abstract void handle(T event, Client client);
+}
diff --git a/server/src/main/java/cz/jzitnik/server/events/EventManager.java b/server/src/main/java/cz/jzitnik/server/events/EventManager.java
new file mode 100644
index 0000000..55b1e1d
--- /dev/null
+++ b/server/src/main/java/cz/jzitnik/server/events/EventManager.java
@@ -0,0 +1,77 @@
+package cz.jzitnik.server.events;
+
+import cz.jzitnik.common.socket.SocketMessage;
+import cz.jzitnik.server.game.Client;
+import cz.jzitnik.server.annotations.EventHandler;
+import cz.jzitnik.server.context.GlobalContext;
+import lombok.extern.slf4j.Slf4j;
+import org.reflections.Reflections;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+
+@Slf4j
+public class EventManager extends Thread {
+ private ExecutorService eventExecutor;
+ private final HashMap, AbstractEventHandler>> handlers = new HashMap<>();
+ private final BlockingQueue eventQueue = new LinkedBlockingQueue<>();
+
+ private record Registry(SocketMessage event, Client client) {}
+
+ public void emitEvent(SocketMessage event, Client client) {
+ eventQueue.add(new Registry(event, client));
+ }
+
+ public EventManager(Reflections reflections, GlobalContext globalContext) {
+ setDaemon(true);
+
+ var classes = reflections.getTypesAnnotatedWith(EventHandler.class);
+
+ for (var clazz : classes) {
+ EventHandler eventHandler = clazz.getAnnotation(EventHandler.class);
+ try {
+ var instance = (AbstractEventHandler>) clazz.getDeclaredConstructor(GlobalContext.class).newInstance(globalContext);
+ handlers.put(eventHandler.value(), instance);
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
+ NoSuchMethodException e) {
+ log.error("Failed to instantiate socket event handler: {}", clazz.getName(), e);
+ }
+ }
+ }
+
+ @Override
+ public void run() {
+ eventExecutor = Executors.newFixedThreadPool(6);
+ while (true) {
+ try {
+ Registry registry = eventQueue.take();
+ handleEvent(registry.event, registry.client);
+ } catch (InterruptedException e) {
+ eventExecutor.shutdownNow();
+ Thread.currentThread().interrupt();
+ }
+ }
+ //eventExecutor.shutdown();
+ }
+
+ @SuppressWarnings("unchecked")
+ private AbstractEventHandler getHandler(Class type) {
+ return (AbstractEventHandler) handlers.get(type);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void handleEvent(SocketMessage event, Client client) {
+ eventExecutor.submit(() -> {
+ try {
+ AbstractEventHandler handler = getHandler((Class) event.getClass());
+ handler.handle(event, client);
+ } catch (Exception e) {
+ log.error("Error", e);
+ }
+ });
+ }
+}
diff --git a/server/src/main/java/cz/jzitnik/server/events/handlers/CreateGameHandler.java b/server/src/main/java/cz/jzitnik/server/events/handlers/CreateGameHandler.java
new file mode 100644
index 0000000..cd58d8c
--- /dev/null
+++ b/server/src/main/java/cz/jzitnik/server/events/handlers/CreateGameHandler.java
@@ -0,0 +1,14 @@
+package cz.jzitnik.server.events.handlers;
+
+import cz.jzitnik.common.socket.messages.game.creation.CreateGame;
+import cz.jzitnik.server.annotations.EventHandler;
+import cz.jzitnik.server.events.AbstractEventHandler;
+import cz.jzitnik.server.game.Client;
+
+@EventHandler(CreateGame.class)
+public class CreateGameHandler extends AbstractEventHandler {
+ @Override
+ public void handle(CreateGame event, Client client) {
+
+ }
+}
diff --git a/server/src/main/java/cz/jzitnik/server/game/Client.java b/server/src/main/java/cz/jzitnik/server/game/Client.java
new file mode 100644
index 0000000..0ddae7f
--- /dev/null
+++ b/server/src/main/java/cz/jzitnik/server/game/Client.java
@@ -0,0 +1,5 @@
+package cz.jzitnik.server.game;
+
+import cz.jzitnik.server.socket.SocketSession;
+
+public record Client(SocketSession session) {}
\ No newline at end of file
diff --git a/server/src/main/java/cz/jzitnik/server/game/Game.java b/server/src/main/java/cz/jzitnik/server/game/Game.java
new file mode 100644
index 0000000..42011b3
--- /dev/null
+++ b/server/src/main/java/cz/jzitnik/server/game/Game.java
@@ -0,0 +1,4 @@
+package cz.jzitnik.server.game;
+
+public class Game {
+}
diff --git a/server/src/main/java/cz/jzitnik/server/socket/GlobalContextConfigurator.java b/server/src/main/java/cz/jzitnik/server/socket/GlobalContextConfigurator.java
new file mode 100644
index 0000000..2454e4d
--- /dev/null
+++ b/server/src/main/java/cz/jzitnik/server/socket/GlobalContextConfigurator.java
@@ -0,0 +1,14 @@
+package cz.jzitnik.server.socket;
+
+import cz.jzitnik.server.context.AppContext;
+import jakarta.websocket.HandshakeResponse;
+import jakarta.websocket.server.HandshakeRequest;
+import jakarta.websocket.server.ServerEndpointConfig;
+
+public class GlobalContextConfigurator extends ServerEndpointConfig.Configurator {
+
+ @Override
+ public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
+ sec.getUserProperties().put("globalContext", AppContext.get());
+ }
+}
diff --git a/server/src/main/java/cz/jzitnik/server/socket/SocketSession.java b/server/src/main/java/cz/jzitnik/server/socket/SocketSession.java
new file mode 100644
index 0000000..1fdde1c
--- /dev/null
+++ b/server/src/main/java/cz/jzitnik/server/socket/SocketSession.java
@@ -0,0 +1,29 @@
+package cz.jzitnik.server.socket;
+
+import cz.jzitnik.common.socket.SocketMessage;
+import cz.jzitnik.common.socket.messages.Test;
+import jakarta.websocket.Session;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+
+@RequiredArgsConstructor
+@Getter
+public class SocketSession {
+ private final Session session;
+
+ public void sendMessage(SocketMessage message) {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(message);
+ oos.flush();
+ session.getBasicRemote().sendBinary(java.nio.ByteBuffer.wrap(baos.toByteArray()));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/server/src/main/java/cz/jzitnik/server/WebSocket.java b/server/src/main/java/cz/jzitnik/server/socket/WebSocket.java
similarity index 54%
rename from server/src/main/java/cz/jzitnik/server/WebSocket.java
rename to server/src/main/java/cz/jzitnik/server/socket/WebSocket.java
index 5fa6558..623bc86 100644
--- a/server/src/main/java/cz/jzitnik/server/WebSocket.java
+++ b/server/src/main/java/cz/jzitnik/server/socket/WebSocket.java
@@ -1,7 +1,8 @@
-package cz.jzitnik.server;
+package cz.jzitnik.server.socket;
import cz.jzitnik.common.socket.SocketMessage;
-import cz.jzitnik.common.socket.messages.Test;
+import cz.jzitnik.server.game.Client;
+import cz.jzitnik.server.context.GlobalContext;
import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;
@@ -9,33 +10,25 @@ import lombok.extern.slf4j.Slf4j;
import java.io.*;
@Slf4j
-@ServerEndpoint("/ws")
+@ServerEndpoint(value = "/ws", configurator = GlobalContextConfigurator.class)
public class WebSocket {
- @OnOpen
- public void onOpen(Session session) {
- log.debug("Client connected: " + session.getId());
+ private GlobalContext globalContext;
- try {
- SocketMessage response = new Test();
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(baos);
- oos.writeObject(response);
- oos.flush();
- session.getBasicRemote().sendBinary(java.nio.ByteBuffer.wrap(baos.toByteArray()));
- } catch (IOException e) {
- e.printStackTrace();
- }
+ @OnOpen
+ public void onOpen(Session session, EndpointConfig config) {
+ this.globalContext = (GlobalContext) config.getUserProperties().get("globalContext");
+ globalContext.registerClient(session);
+ log.debug("Client connected: {}", session.getId());
}
- // Receive binary data from client
@OnMessage
public void onMessage(byte[] bytes, Session session) {
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais)) {
-
SocketMessage socketMessage = (SocketMessage) ois.readObject();
- System.out.println("Received: " + socketMessage);
+ Client client = globalContext.getSessions().get(session);
+ globalContext.getEventManager().emitEvent(socketMessage, client);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}