feat: Multiplayer #2
14
.idea/FuzzierSettings.xml
generated
Normal file
14
.idea/FuzzierSettings.xml
generated
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="com.mituuz.fuzzier.FuzzierSettings">
|
||||||
|
<option name="modules">
|
||||||
|
<map>
|
||||||
|
<entry key="common" value="$PROJECT_DIR$" />
|
||||||
|
<entry key="game" value="$PROJECT_DIR$" />
|
||||||
|
<entry key="game (1)" value="$PROJECT_DIR$" />
|
||||||
|
<entry key="server" value="$PROJECT_DIR$" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
<option name="recentlySearchedFiles" value="rO0ABXNyABxqYXZheC5zd2luZy5EZWZhdWx0TGlzdE1vZGVsBgfGCGLvV2ICAAFMAAhkZWxlZ2F0ZXQAEkxqYXZhL3V0aWwvVmVjdG9yO3hyAB1qYXZheC5zd2luZy5BYnN0cmFjdExpc3RNb2RlbFrW+oYSs63tAgABTAAMbGlzdGVuZXJMaXN0dAAlTGphdmF4L3N3aW5nL2V2ZW50L0V2ZW50TGlzdGVuZXJMaXN0O3hwc3IAI2phdmF4LnN3aW5nLmV2ZW50LkV2ZW50TGlzdGVuZXJMaXN0kUjMLXPfDt4DAAB4cHB4c3IAEGphdmEudXRpbC5WZWN0b3LZl31bgDuvAQMAA0kAEWNhcGFjaXR5SW5jcmVtZW50SQAMZWxlbWVudENvdW50WwALZWxlbWVudERhdGF0ABNbTGphdmEvbGFuZy9PYmplY3Q7eHAAAAAAAAAAAXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAApzcgBIY29tLm1pdHV1ei5mdXp6aWVyLmVudGl0aWVzLkZ1enp5TWF0Y2hDb250YWluZXIkU2VyaWFsaXplZE1hdGNoQ29udGFpbmVy2S8sP5uny74CAARMAAhmaWxlUGF0aHQAEkxqYXZhL2xhbmcvU3RyaW5nO0wACGZpbGVuYW1lcQB+AA1MAA5tb2R1bGVCYXNlUGF0aHEAfgANTAAFc2NvcmV0ADxMY29tL21pdHV1ei9mdXp6aWVyL2VudGl0aWVzL0Z1enp5TWF0Y2hDb250YWluZXIkRnV6enlTY29yZTt4cHQARC9nYW1lL3NyYy9tYWluL2phdmEvY3ovanppdG5pay9jbGllbnQvdXRpbHMvZXZlbnRzL0V2ZW50TWFuYWdlci5qYXZhdAARRXZlbnRNYW5hZ2VyLmphdmF0ABYvaG9tZS9rdWJhL0NvZGluZy9nYW1lc3IAOmNvbS5taXR1dXouZnV6emllci5lbnRpdGllcy5GdXp6eU1hdGNoQ29udGFpbmVyJEZ1enp5U2NvcmUvP9P07ROG2QIABUkADWZpbGVuYW1lU2NvcmVJAA9tdWx0aU1hdGNoU2NvcmVJABBwYXJ0aWFsUGF0aFNjb3JlSQALc3RyZWFrU2NvcmVMABNoaWdobGlnaHRDaGFyYWN0ZXJzdAAPTGphdmEvdXRpbC9TZXQ7eHAAAAAIAAAAAAAAAAAAAAADc3IAEWphdmEudXRpbC5IYXNoU2V0ukSFlZa4tzQDAAB4cHcMAAAAED9AAAAAAAAIc3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAAABzcQB+ABgAAAABc3EAfgAYAAAAAnNxAH4AGAAAAANzcQB+ABgAAAAEc3EAfgAYAAAABXNxAH4AGAAAAAZzcQB+ABgAAAAHeHBwcHBwcHBwcHg=" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
1
.idea/compiler.xml
generated
1
.idea/compiler.xml
generated
@@ -2,6 +2,7 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="CompilerConfiguration">
|
<component name="CompilerConfiguration">
|
||||||
<annotationProcessing>
|
<annotationProcessing>
|
||||||
|
<profile default="true" name="Default" enabled="true" />
|
||||||
<profile name="Maven default annotation processors profile" enabled="true">
|
<profile name="Maven default annotation processors profile" enabled="true">
|
||||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||||
|
|||||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -8,5 +8,5 @@
|
|||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_25" default="true" project-jdk-name="openjdk-25" project-jdk-type="JavaSDK" />
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_X" default="true" project-jdk-name="openjdk-25" project-jdk-type="JavaSDK" />
|
||||||
</project>
|
</project>
|
||||||
@@ -24,5 +24,12 @@
|
|||||||
<artifactId>jackson-dataformat-yaml</artifactId>
|
<artifactId>jackson-dataformat-yaml</artifactId>
|
||||||
<version>3.0.4</version>
|
<version>3.0.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.42</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package cz.jzitnik.common.socket;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public interface SocketMessage extends Serializable {
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package cz.jzitnik.common.socket.messages;
|
||||||
|
|
||||||
|
import cz.jzitnik.common.socket.SocketMessage;
|
||||||
|
|
||||||
|
public class Test implements SocketMessage {
|
||||||
|
}
|
||||||
6
game/.idea/encodings.xml
generated
6
game/.idea/encodings.xml
generated
@@ -1,6 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="Encoding">
|
<component name="Encoding">
|
||||||
|
<file url="file://$PROJECT_DIR$/common/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/common/src/main/resources" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/game/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/game/src/main/resources" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/server/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/server/src/main/resources" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
16
game/.idea/misc.xml
generated
16
game/.idea/misc.xml
generated
@@ -1,17 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="EntryPointsManager">
|
|
||||||
<list size="3">
|
|
||||||
<item index="0" class="java.lang.String" itemvalue="cz.jzitnik.annotations.EventHandler" />
|
|
||||||
<item index="1" class="java.lang.String" itemvalue="cz.jzitnik.annotations.ui.KeyboardPressHandler" />
|
|
||||||
<item index="2" class="java.lang.String" itemvalue="cz.jzitnik.annotations.ui.MouseHandler" />
|
|
||||||
</list>
|
|
||||||
<writeAnnotations>
|
|
||||||
<writeAnnotation name="cz.jzitnik.annotations.injectors.InjectConfig" />
|
|
||||||
<writeAnnotation name="cz.jzitnik.annotations.injectors.InjectDependency" />
|
|
||||||
<writeAnnotation name="cz.jzitnik.annotations.injectors.InjectState" />
|
|
||||||
</writeAnnotations>
|
|
||||||
</component>
|
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="MavenProjectsManager">
|
<component name="MavenProjectsManager">
|
||||||
<option name="originalFiles">
|
<option name="originalFiles">
|
||||||
@@ -20,7 +8,5 @@
|
|||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_25" default="true" project-jdk-name="openjdk-25" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_X" default="true" project-jdk-name="openjdk-25" project-jdk-type="JavaSDK" />
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
|
||||||
</component>
|
|
||||||
</project>
|
</project>
|
||||||
@@ -179,5 +179,11 @@
|
|||||||
<artifactId>jvm</artifactId>
|
<artifactId>jvm</artifactId>
|
||||||
<version>2.5</version>
|
<version>2.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.tyrus.bundles</groupId>
|
||||||
|
<artifactId>tyrus-standalone-client</artifactId>
|
||||||
|
<version>2.2.2</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import cz.jzitnik.client.annotations.injectors.InjectState;
|
|||||||
import cz.jzitnik.client.events.KeyboardPressEvent;
|
import cz.jzitnik.client.events.KeyboardPressEvent;
|
||||||
import cz.jzitnik.client.events.MouseAction;
|
import cz.jzitnik.client.events.MouseAction;
|
||||||
import cz.jzitnik.client.events.TerminalResizeEvent;
|
import cz.jzitnik.client.events.TerminalResizeEvent;
|
||||||
|
import cz.jzitnik.client.socket.SocketEventManager;
|
||||||
import cz.jzitnik.client.states.RunningState;
|
import cz.jzitnik.client.states.RunningState;
|
||||||
import cz.jzitnik.client.states.TerminalState;
|
import cz.jzitnik.client.states.TerminalState;
|
||||||
import cz.jzitnik.client.utils.events.EventManager;
|
import cz.jzitnik.client.utils.events.EventManager;
|
||||||
@@ -23,6 +24,9 @@ public class Cli implements Runnable {
|
|||||||
@InjectDependency
|
@InjectDependency
|
||||||
private EventManager eventManager;
|
private EventManager eventManager;
|
||||||
|
|
||||||
|
@InjectDependency
|
||||||
|
private SocketEventManager socketEventManager;
|
||||||
|
|
||||||
@InjectState
|
@InjectState
|
||||||
private TerminalState terminalState;
|
private TerminalState terminalState;
|
||||||
|
|
||||||
@@ -31,7 +35,9 @@ public class Cli implements Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
eventManager.start(); // Start event manager thread
|
// Start event manager thread
|
||||||
|
eventManager.start();
|
||||||
|
socketEventManager.start();
|
||||||
|
|
||||||
try (TerminalScreen terminal = new DefaultTerminalFactory()
|
try (TerminalScreen terminal = new DefaultTerminalFactory()
|
||||||
.setMouseCaptureMode(MouseCaptureMode.CLICK_RELEASE_DRAG_MOVE)
|
.setMouseCaptureMode(MouseCaptureMode.CLICK_RELEASE_DRAG_MOVE)
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ package cz.jzitnik.client;
|
|||||||
|
|
||||||
import cz.jzitnik.client.annotations.injectors.InjectDependency;
|
import cz.jzitnik.client.annotations.injectors.InjectDependency;
|
||||||
import cz.jzitnik.client.game.setup.GameSetup;
|
import cz.jzitnik.client.game.setup.GameSetup;
|
||||||
|
import cz.jzitnik.client.socket.Client;
|
||||||
import cz.jzitnik.client.utils.DependencyManager;
|
import cz.jzitnik.client.utils.DependencyManager;
|
||||||
import cz.jzitnik.client.utils.GlobalIOHandlerRepository;
|
import cz.jzitnik.client.utils.GlobalIOHandlerRepository;
|
||||||
import cz.jzitnik.client.utils.ScheduledTaskManager;
|
import cz.jzitnik.client.utils.ScheduledTaskManager;
|
||||||
import cz.jzitnik.client.utils.ThreadManager;
|
import cz.jzitnik.client.utils.ThreadManager;
|
||||||
|
import jakarta.websocket.DeploymentException;
|
||||||
import org.reflections.Reflections;
|
import org.reflections.Reflections;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -23,15 +25,23 @@ public class Game {
|
|||||||
private ScheduledTaskManager scheduledTaskManager;
|
private ScheduledTaskManager scheduledTaskManager;
|
||||||
@InjectDependency
|
@InjectDependency
|
||||||
private GlobalIOHandlerRepository globalIOHandlerRepository;
|
private GlobalIOHandlerRepository globalIOHandlerRepository;
|
||||||
|
@InjectDependency
|
||||||
|
private Client client;
|
||||||
|
|
||||||
public void start() throws IOException {
|
public void start() throws IOException {
|
||||||
dependencyManager.inject(this);
|
dependencyManager.inject(this);
|
||||||
|
|
||||||
gameSetup.setup();
|
try {
|
||||||
threadManager.startAll();
|
client.connect();
|
||||||
scheduledTaskManager.startAll();
|
|
||||||
globalIOHandlerRepository.setup();
|
|
||||||
|
|
||||||
cli.run();
|
gameSetup.setup();
|
||||||
|
threadManager.startAll();
|
||||||
|
scheduledTaskManager.startAll();
|
||||||
|
globalIOHandlerRepository.setup();
|
||||||
|
|
||||||
|
cli.run();
|
||||||
|
} catch (DeploymentException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package cz.jzitnik.client.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 SocketEventHandler {
|
||||||
|
Class<? extends SocketMessage> value();
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package cz.jzitnik.client.events;
|
||||||
|
|
||||||
|
import cz.jzitnik.client.utils.events.Event;
|
||||||
|
import cz.jzitnik.common.socket.SocketMessage;
|
||||||
|
|
||||||
|
public record SendSocketMessageEvent(SocketMessage message) implements Event {
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package cz.jzitnik.client.events.handlers;
|
||||||
|
|
||||||
|
import cz.jzitnik.client.annotations.EventHandler;
|
||||||
|
import cz.jzitnik.client.annotations.injectors.InjectDependency;
|
||||||
|
import cz.jzitnik.client.events.SendSocketMessageEvent;
|
||||||
|
import cz.jzitnik.client.socket.Client;
|
||||||
|
import cz.jzitnik.client.utils.events.AbstractEventHandler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@EventHandler(SendSocketMessageEvent.class)
|
||||||
|
public class SendSocketMessageEventHandler extends AbstractEventHandler<SendSocketMessageEvent> {
|
||||||
|
@InjectDependency
|
||||||
|
private Client client;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(SendSocketMessageEvent event) {
|
||||||
|
try {
|
||||||
|
client.send(event.message());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package cz.jzitnik.client.socket;
|
||||||
|
|
||||||
|
import cz.jzitnik.common.socket.SocketMessage;
|
||||||
|
|
||||||
|
public abstract class AbstractSocketEventHandler<T extends SocketMessage> {
|
||||||
|
public abstract void handle(T event);
|
||||||
|
}
|
||||||
50
game/src/main/java/cz/jzitnik/client/socket/Client.java
Normal file
50
game/src/main/java/cz/jzitnik/client/socket/Client.java
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package cz.jzitnik.client.socket;
|
||||||
|
|
||||||
|
import cz.jzitnik.client.annotations.Dependency;
|
||||||
|
import cz.jzitnik.client.annotations.injectors.InjectDependency;
|
||||||
|
import cz.jzitnik.common.socket.SocketMessage;
|
||||||
|
import jakarta.websocket.*;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Dependency
|
||||||
|
@ClientEndpoint
|
||||||
|
public class Client {
|
||||||
|
private Session session;
|
||||||
|
|
||||||
|
@InjectDependency
|
||||||
|
private SocketEventManager socketEventManager;
|
||||||
|
|
||||||
|
@OnOpen
|
||||||
|
public void onOpen(Session session) {
|
||||||
|
this.session = session;
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnMessage
|
||||||
|
public void onMessage(ByteBuffer buffer) {
|
||||||
|
try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(buffer.array()))) {
|
||||||
|
SocketMessage message = (SocketMessage) ois.readObject();
|
||||||
|
socketEventManager.emitEvent(message);
|
||||||
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(SocketMessage message) throws IOException {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||||
|
oos.writeObject(message);
|
||||||
|
oos.flush();
|
||||||
|
|
||||||
|
session.getBasicRemote().sendBinary(ByteBuffer.wrap(baos.toByteArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect() throws DeploymentException, IOException {
|
||||||
|
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
|
||||||
|
container.connectToServer(this, URI.create("ws://localhost:8025/ws"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package cz.jzitnik.client.socket;
|
||||||
|
|
||||||
|
import cz.jzitnik.client.annotations.Dependency;
|
||||||
|
import cz.jzitnik.client.annotations.SocketEventHandler;
|
||||||
|
import cz.jzitnik.client.annotations.injectors.InjectConfig;
|
||||||
|
import cz.jzitnik.client.annotations.injectors.InjectState;
|
||||||
|
import cz.jzitnik.client.config.ThreadPoolConfig;
|
||||||
|
import cz.jzitnik.client.states.RunningState;
|
||||||
|
import cz.jzitnik.client.utils.DependencyManager;
|
||||||
|
import cz.jzitnik.common.socket.SocketMessage;
|
||||||
|
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
|
||||||
|
@Dependency
|
||||||
|
public class SocketEventManager extends Thread {
|
||||||
|
private final DependencyManager dependencyManager;
|
||||||
|
|
||||||
|
private ExecutorService eventExecutor;
|
||||||
|
private final HashMap<Class<? extends SocketMessage>, AbstractSocketEventHandler<?>> handlers = new HashMap<>();
|
||||||
|
private final BlockingQueue<SocketMessage> eventQueue = new LinkedBlockingQueue<>();
|
||||||
|
|
||||||
|
@InjectConfig
|
||||||
|
private ThreadPoolConfig threadPoolConfig;
|
||||||
|
|
||||||
|
@InjectState
|
||||||
|
private RunningState runningState;
|
||||||
|
|
||||||
|
public void emitEvent(SocketMessage event) {
|
||||||
|
eventQueue.add(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketEventManager(Reflections reflections, DependencyManager dependencyManager) {
|
||||||
|
this.dependencyManager = dependencyManager;
|
||||||
|
setDaemon(true);
|
||||||
|
|
||||||
|
var classes = reflections.getTypesAnnotatedWith(SocketEventHandler.class);
|
||||||
|
|
||||||
|
for (var clazz : classes) {
|
||||||
|
SocketEventHandler eventHandler = clazz.getAnnotation(SocketEventHandler.class);
|
||||||
|
try {
|
||||||
|
var instance = (AbstractSocketEventHandler<?>) clazz.getDeclaredConstructor().newInstance();
|
||||||
|
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() {
|
||||||
|
for (Object instance : handlers.values()) {
|
||||||
|
dependencyManager.inject(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
eventExecutor = Executors.newFixedThreadPool(threadPoolConfig.eventThreadCount());
|
||||||
|
while (runningState.isRunning()) {
|
||||||
|
try {
|
||||||
|
SocketMessage event = eventQueue.take();
|
||||||
|
handleEvent(event);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// The game is shutting down.
|
||||||
|
eventExecutor.shutdownNow();
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eventExecutor.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T extends SocketMessage> AbstractSocketEventHandler<T> getHandler(Class<T> type) {
|
||||||
|
return (AbstractSocketEventHandler<T>) handlers.get(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void handleEvent(SocketMessage event) {
|
||||||
|
eventExecutor.submit(() -> {
|
||||||
|
try {
|
||||||
|
AbstractSocketEventHandler<SocketMessage> handler = getHandler((Class<SocketMessage>) event.getClass());
|
||||||
|
handler.handle(event);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package cz.jzitnik.client.socket.events;
|
||||||
|
|
||||||
|
import cz.jzitnik.client.annotations.SocketEventHandler;
|
||||||
|
import cz.jzitnik.client.socket.AbstractSocketEventHandler;
|
||||||
|
import cz.jzitnik.common.socket.messages.Test;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@SocketEventHandler(Test.class)
|
||||||
|
public class TestHandler extends AbstractSocketEventHandler<Test> {
|
||||||
|
@Override
|
||||||
|
public void handle(Test event) {
|
||||||
|
log.debug("Got test: {}", event);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
package cz.jzitnik.client.utils.events;
|
package cz.jzitnik.client.utils.events;
|
||||||
|
|
||||||
public abstract class AbstractEventHandler<T> {
|
public abstract class AbstractEventHandler<T extends Event> {
|
||||||
public abstract void handle(T event);
|
public abstract void handle(T event);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class EventManager extends Thread {
|
|||||||
private ThreadPoolConfig threadPoolConfig;
|
private ThreadPoolConfig threadPoolConfig;
|
||||||
|
|
||||||
private ExecutorService eventExecutor;
|
private ExecutorService eventExecutor;
|
||||||
private final HashMap<Class<? extends Event>, AbstractEventHandler<? extends Event>> handlers = new HashMap<>();
|
private final HashMap<Class<? extends Event>, AbstractEventHandler<?>> handlers = new HashMap<>();
|
||||||
private final BlockingQueue<EventRecord> eventQueue = new LinkedBlockingQueue<>();
|
private final BlockingQueue<EventRecord> eventQueue = new LinkedBlockingQueue<>();
|
||||||
private final DependencyManager dependencyManager;
|
private final DependencyManager dependencyManager;
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ public class EventManager extends Thread {
|
|||||||
for (var clazz : classes) {
|
for (var clazz : classes) {
|
||||||
EventHandler eventHandler = clazz.getAnnotation(EventHandler.class);
|
EventHandler eventHandler = clazz.getAnnotation(EventHandler.class);
|
||||||
try {
|
try {
|
||||||
var instance = (AbstractEventHandler<? extends Event>) clazz.getDeclaredConstructor().newInstance();
|
var instance = (AbstractEventHandler<?>) clazz.getDeclaredConstructor().newInstance();
|
||||||
handlers.put(eventHandler.value(), instance);
|
handlers.put(eventHandler.value(), instance);
|
||||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
|
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
|
||||||
NoSuchMethodException e) {
|
NoSuchMethodException e) {
|
||||||
|
|||||||
@@ -18,5 +18,49 @@
|
|||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.42</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.websocket</groupId>
|
||||||
|
<artifactId>jakarta.websocket-api</artifactId>
|
||||||
|
<version>2.3.0-M2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.tyrus</groupId>
|
||||||
|
<artifactId>tyrus-server</artifactId>
|
||||||
|
<version>2.2.2</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.tyrus</groupId>
|
||||||
|
<artifactId>tyrus-container-grizzly-server</artifactId>
|
||||||
|
<version>2.2.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.tyrus</groupId>
|
||||||
|
<artifactId>tyrus-client</artifactId>
|
||||||
|
<version>2.2.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>2.0.17</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>1.5.25</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,7 +1,18 @@
|
|||||||
package cz.jzitnik.server;
|
package cz.jzitnik.server;
|
||||||
|
|
||||||
public class Main {
|
import jakarta.websocket.DeploymentException;
|
||||||
static void main() {
|
import org.glassfish.tyrus.server.Server;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
static void main() throws DeploymentException {
|
||||||
|
Map<String, Object> properties = new HashMap<>();
|
||||||
|
Server server = new Server("localhost", 8025, "/", properties, WebSocket.class);
|
||||||
|
|
||||||
|
server.start();
|
||||||
|
new Scanner(System.in).nextLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
53
server/src/main/java/cz/jzitnik/server/WebSocket.java
Normal file
53
server/src/main/java/cz/jzitnik/server/WebSocket.java
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package cz.jzitnik.server;
|
||||||
|
|
||||||
|
import cz.jzitnik.common.socket.SocketMessage;
|
||||||
|
import cz.jzitnik.common.socket.messages.Test;
|
||||||
|
import jakarta.websocket.*;
|
||||||
|
import jakarta.websocket.server.ServerEndpoint;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@ServerEndpoint("/ws")
|
||||||
|
public class WebSocket {
|
||||||
|
|
||||||
|
@OnOpen
|
||||||
|
public void onOpen(Session session) {
|
||||||
|
log.debug("Client connected: " + session.getId());
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClose
|
||||||
|
public void onClose(Session session, CloseReason reason) {
|
||||||
|
System.out.println("Connection closed: " + reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnError
|
||||||
|
public void onError(Session session, Throwable throwable) {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user