From 10a2e402b772c25fc9ac5cc8c36b671a6758e188 Mon Sep 17 00:00:00 2001 From: jzitnik-dev Date: Thu, 11 Dec 2025 16:38:08 +0100 Subject: [PATCH] chore: Scaffolding of the project --- .gitignore | 39 +++++ .idea/.gitignore | 3 + .idea/encodings.xml | 7 + .idea/misc.xml | 14 ++ .idea/vcs.xml | 6 + pom.xml | 143 ++++++++++++++++++ src/main/java/cz/jzitnik/Cli.java | 53 +++++++ src/main/java/cz/jzitnik/Game.java | 13 ++ src/main/java/cz/jzitnik/Main.java | 7 + .../java/cz/jzitnik/annotations/Config.java | 11 ++ .../cz/jzitnik/annotations/Dependency.java | 13 ++ .../cz/jzitnik/annotations/EventHandler.java | 14 ++ .../java/cz/jzitnik/annotations/State.java | 11 ++ .../annotations/injectors/InjectConfig.java | 11 ++ .../injectors/InjectDependency.java | 11 ++ .../annotations/injectors/InjectState.java | 11 ++ .../java/cz/jzitnik/events/ExitEvent.java | 7 + .../cz/jzitnik/events/KeyboardPressEvent.java | 12 ++ .../java/cz/jzitnik/events/MouseAction.java | 15 ++ .../events/handlers/ExitEventHandler.java | 22 +++ .../handlers/KeyboardPressEventHandler.java | 38 +++++ .../handlers/MouseActionEventHandler.java | 18 +++ .../java/cz/jzitnik/states/RunningState.java | 10 ++ .../cz/jzitnik/utils/DependencyManager.java | 142 +++++++++++++++++ .../java/cz/jzitnik/utils/StateManager.java | 38 +++++ .../utils/events/AbstractEventHandler.java | 13 ++ .../java/cz/jzitnik/utils/events/Event.java | 4 + .../cz/jzitnik/utils/events/EventManager.java | 74 +++++++++ 28 files changed, 760 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/encodings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/vcs.xml create mode 100644 pom.xml create mode 100644 src/main/java/cz/jzitnik/Cli.java create mode 100644 src/main/java/cz/jzitnik/Game.java create mode 100644 src/main/java/cz/jzitnik/Main.java create mode 100644 src/main/java/cz/jzitnik/annotations/Config.java create mode 100644 src/main/java/cz/jzitnik/annotations/Dependency.java create mode 100644 src/main/java/cz/jzitnik/annotations/EventHandler.java create mode 100644 src/main/java/cz/jzitnik/annotations/State.java create mode 100644 src/main/java/cz/jzitnik/annotations/injectors/InjectConfig.java create mode 100644 src/main/java/cz/jzitnik/annotations/injectors/InjectDependency.java create mode 100644 src/main/java/cz/jzitnik/annotations/injectors/InjectState.java create mode 100644 src/main/java/cz/jzitnik/events/ExitEvent.java create mode 100644 src/main/java/cz/jzitnik/events/KeyboardPressEvent.java create mode 100644 src/main/java/cz/jzitnik/events/MouseAction.java create mode 100644 src/main/java/cz/jzitnik/events/handlers/ExitEventHandler.java create mode 100644 src/main/java/cz/jzitnik/events/handlers/KeyboardPressEventHandler.java create mode 100644 src/main/java/cz/jzitnik/events/handlers/MouseActionEventHandler.java create mode 100644 src/main/java/cz/jzitnik/states/RunningState.java create mode 100644 src/main/java/cz/jzitnik/utils/DependencyManager.java create mode 100644 src/main/java/cz/jzitnik/utils/StateManager.java create mode 100644 src/main/java/cz/jzitnik/utils/events/AbstractEventHandler.java create mode 100644 src/main/java/cz/jzitnik/utils/events/Event.java create mode 100644 src/main/java/cz/jzitnik/utils/events/EventManager.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..480bdf5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,39 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ +.kotlin + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..039a9d1 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..f547023 --- /dev/null +++ b/pom.xml @@ -0,0 +1,143 @@ + + + 4.0.0 + + cz.jzitnik + game + 1.0-SNAPSHOT + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + + + org.projectlombok + lombok + 1.18.38 + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.1 + + + package + + shade + + + + + + + cz.jzitnik.Main + + + false + false + + + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + + + java + + + + + cz.jzitnik.Main + compile + + + + + + + + 22 + 22 + UTF-8 + + + + + org.projectlombok + lombok + 1.18.38 + provided + + + org.junit.jupiter + junit-jupiter + 5.8.2 + + + + org.reflections + reflections + 0.10.2 + + + + com.google.guava + guava + 31.1-jre + + + + com.fasterxml.jackson.core + jackson-databind + 2.18.2 + + + + junit + junit + 4.13.2 + test + + + + org.slf4j + slf4j-api + 2.0.17 + + + ch.qos.logback + logback-classic + 1.5.18 + + + com.github.trilarion + java-vorbis-support + 1.2.1 + + + com.esotericsoftware + kryo + 5.6.2 + + + + com.googlecode.lanterna + lanterna + 3.1.3 + + + \ No newline at end of file diff --git a/src/main/java/cz/jzitnik/Cli.java b/src/main/java/cz/jzitnik/Cli.java new file mode 100644 index 0000000..121b049 --- /dev/null +++ b/src/main/java/cz/jzitnik/Cli.java @@ -0,0 +1,53 @@ +package cz.jzitnik; + +import com.googlecode.lanterna.input.KeyStroke; +import com.googlecode.lanterna.screen.TerminalScreen; +import com.googlecode.lanterna.terminal.DefaultTerminalFactory; +import com.googlecode.lanterna.terminal.MouseCaptureMode; +import cz.jzitnik.annotations.Dependency; +import cz.jzitnik.annotations.injectors.InjectDependency; +import cz.jzitnik.events.KeyboardPressEvent; +import cz.jzitnik.events.MouseAction; +import cz.jzitnik.states.RunningState; +import cz.jzitnik.utils.StateManager; +import cz.jzitnik.utils.events.EventManager; +import lombok.SneakyThrows; + +@Dependency +public class Cli implements Runnable { + @InjectDependency + private EventManager eventManager; + + @InjectDependency + private StateManager stateManager; + + @SneakyThrows // I know deal with it + @Override + public void run() { + eventManager.start(); // Start event manager thread + + TerminalScreen terminal = new DefaultTerminalFactory() + .setMouseCaptureMode(MouseCaptureMode.CLICK_RELEASE_DRAG_MOVE) + .createScreen(); + + terminal.setCursorPosition(null); + terminal.doResizeIfNecessary(); + terminal.getTerminal().enterPrivateMode(); + + RunningState runningState = stateManager.getOrThrow(RunningState.class); + while (runningState.isRunning()) { + KeyStroke keyStroke = terminal.pollInput(); + if (keyStroke != null) { + if (keyStroke instanceof com.googlecode.lanterna.input.MouseAction mouse) { + eventManager.emitEvent(new MouseAction(mouse)); + continue; + } + + eventManager.emitEvent(new KeyboardPressEvent(keyStroke)); + } + Thread.sleep(50); + } + + terminal.close(); + } +} diff --git a/src/main/java/cz/jzitnik/Game.java b/src/main/java/cz/jzitnik/Game.java new file mode 100644 index 0000000..57420ff --- /dev/null +++ b/src/main/java/cz/jzitnik/Game.java @@ -0,0 +1,13 @@ +package cz.jzitnik; + +import cz.jzitnik.utils.DependencyManager; +import org.reflections.Reflections; + +public class Game { + private final DependencyManager dependencyManager = new DependencyManager(new Reflections("cz.jzitnik")); + + public void start() { + Cli cli = dependencyManager.getDependencyOrThrow(Cli.class); + cli.run(); + } +} diff --git a/src/main/java/cz/jzitnik/Main.java b/src/main/java/cz/jzitnik/Main.java new file mode 100644 index 0000000..884a74a --- /dev/null +++ b/src/main/java/cz/jzitnik/Main.java @@ -0,0 +1,7 @@ +package cz.jzitnik; + +public class Main { + public static void main(String[] args) { + new Game().start(); + } +} \ No newline at end of file diff --git a/src/main/java/cz/jzitnik/annotations/Config.java b/src/main/java/cz/jzitnik/annotations/Config.java new file mode 100644 index 0000000..b9e1667 --- /dev/null +++ b/src/main/java/cz/jzitnik/annotations/Config.java @@ -0,0 +1,11 @@ +package cz.jzitnik.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Config { +} diff --git a/src/main/java/cz/jzitnik/annotations/Dependency.java b/src/main/java/cz/jzitnik/annotations/Dependency.java new file mode 100644 index 0000000..87ed5a5 --- /dev/null +++ b/src/main/java/cz/jzitnik/annotations/Dependency.java @@ -0,0 +1,13 @@ +package cz.jzitnik.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Dependency { + /** Custom alias **/ + Class value() default Object.class; +} \ No newline at end of file diff --git a/src/main/java/cz/jzitnik/annotations/EventHandler.java b/src/main/java/cz/jzitnik/annotations/EventHandler.java new file mode 100644 index 0000000..e9c7d2c --- /dev/null +++ b/src/main/java/cz/jzitnik/annotations/EventHandler.java @@ -0,0 +1,14 @@ +package cz.jzitnik.annotations; + +import cz.jzitnik.utils.events.Event; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface EventHandler { + Class value(); +} diff --git a/src/main/java/cz/jzitnik/annotations/State.java b/src/main/java/cz/jzitnik/annotations/State.java new file mode 100644 index 0000000..bf23ec3 --- /dev/null +++ b/src/main/java/cz/jzitnik/annotations/State.java @@ -0,0 +1,11 @@ +package cz.jzitnik.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface State { +} diff --git a/src/main/java/cz/jzitnik/annotations/injectors/InjectConfig.java b/src/main/java/cz/jzitnik/annotations/injectors/InjectConfig.java new file mode 100644 index 0000000..b95916e --- /dev/null +++ b/src/main/java/cz/jzitnik/annotations/injectors/InjectConfig.java @@ -0,0 +1,11 @@ +package cz.jzitnik.annotations.injectors; + +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.FIELD}) +public @interface InjectConfig { +} diff --git a/src/main/java/cz/jzitnik/annotations/injectors/InjectDependency.java b/src/main/java/cz/jzitnik/annotations/injectors/InjectDependency.java new file mode 100644 index 0000000..5c6fd13 --- /dev/null +++ b/src/main/java/cz/jzitnik/annotations/injectors/InjectDependency.java @@ -0,0 +1,11 @@ +package cz.jzitnik.annotations.injectors; + +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.FIELD}) +public @interface InjectDependency { +} diff --git a/src/main/java/cz/jzitnik/annotations/injectors/InjectState.java b/src/main/java/cz/jzitnik/annotations/injectors/InjectState.java new file mode 100644 index 0000000..d01eaa7 --- /dev/null +++ b/src/main/java/cz/jzitnik/annotations/injectors/InjectState.java @@ -0,0 +1,11 @@ +package cz.jzitnik.annotations.injectors; + +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.FIELD}) +public @interface InjectState { +} diff --git a/src/main/java/cz/jzitnik/events/ExitEvent.java b/src/main/java/cz/jzitnik/events/ExitEvent.java new file mode 100644 index 0000000..1649807 --- /dev/null +++ b/src/main/java/cz/jzitnik/events/ExitEvent.java @@ -0,0 +1,7 @@ +package cz.jzitnik.events; + +import cz.jzitnik.utils.events.Event; + +/** Custom event without any handler **/ +public class ExitEvent implements Event { +} diff --git a/src/main/java/cz/jzitnik/events/KeyboardPressEvent.java b/src/main/java/cz/jzitnik/events/KeyboardPressEvent.java new file mode 100644 index 0000000..52ec8ae --- /dev/null +++ b/src/main/java/cz/jzitnik/events/KeyboardPressEvent.java @@ -0,0 +1,12 @@ +package cz.jzitnik.events; + +import com.googlecode.lanterna.input.KeyStroke; +import cz.jzitnik.utils.events.Event; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class KeyboardPressEvent implements Event { + private KeyStroke keyStroke; +} diff --git a/src/main/java/cz/jzitnik/events/MouseAction.java b/src/main/java/cz/jzitnik/events/MouseAction.java new file mode 100644 index 0000000..6959efc --- /dev/null +++ b/src/main/java/cz/jzitnik/events/MouseAction.java @@ -0,0 +1,15 @@ +package cz.jzitnik.events; + +import com.googlecode.lanterna.TerminalPosition; +import com.googlecode.lanterna.input.MouseActionType; +import cz.jzitnik.utils.events.Event; + +public class MouseAction extends com.googlecode.lanterna.input.MouseAction implements Event { + public MouseAction(MouseActionType actionType, int button, TerminalPosition position) { + super(actionType, button, position); + } + + public MouseAction(com.googlecode.lanterna.input.MouseAction mouseAction) { + this(mouseAction.getActionType(), mouseAction.getButton(), mouseAction.getPosition()); + } +} diff --git a/src/main/java/cz/jzitnik/events/handlers/ExitEventHandler.java b/src/main/java/cz/jzitnik/events/handlers/ExitEventHandler.java new file mode 100644 index 0000000..9149ffe --- /dev/null +++ b/src/main/java/cz/jzitnik/events/handlers/ExitEventHandler.java @@ -0,0 +1,22 @@ +package cz.jzitnik.events.handlers; + +import cz.jzitnik.annotations.EventHandler; +import cz.jzitnik.events.ExitEvent; +import cz.jzitnik.states.RunningState; +import cz.jzitnik.utils.DependencyManager; +import cz.jzitnik.utils.StateManager; +import cz.jzitnik.utils.events.AbstractEventHandler; + +@EventHandler(ExitEvent.class) +public class ExitEventHandler extends AbstractEventHandler { + public ExitEventHandler(DependencyManager dm) { + super(dm); + } + + @Override + public void handle(ExitEvent event) { + StateManager stateManager = dm.getDependencyOrThrow(StateManager.class); + RunningState runningState = stateManager.getOrThrow(RunningState.class); + runningState.setRunning(false); + } +} diff --git a/src/main/java/cz/jzitnik/events/handlers/KeyboardPressEventHandler.java b/src/main/java/cz/jzitnik/events/handlers/KeyboardPressEventHandler.java new file mode 100644 index 0000000..ea6f0ef --- /dev/null +++ b/src/main/java/cz/jzitnik/events/handlers/KeyboardPressEventHandler.java @@ -0,0 +1,38 @@ +package cz.jzitnik.events.handlers; + +import com.googlecode.lanterna.input.KeyStroke; +import cz.jzitnik.annotations.EventHandler; +import cz.jzitnik.events.ExitEvent; +import cz.jzitnik.events.KeyboardPressEvent; +import cz.jzitnik.utils.DependencyManager; +import cz.jzitnik.utils.events.AbstractEventHandler; +import cz.jzitnik.utils.events.EventManager; + +@EventHandler(KeyboardPressEvent.class) +public class KeyboardPressEventHandler extends AbstractEventHandler { + public KeyboardPressEventHandler(DependencyManager dm) { + super(dm); + } + + @Override + public void handle(KeyboardPressEvent event) { + EventManager eventManager = dm.getDependencyOrThrow(EventManager.class); + + KeyStroke keyStroke = event.getKeyStroke(); + + switch (keyStroke.getKeyType()) { + case Escape: + eventManager.emitEvent(new ExitEvent()); + break; + case ArrowUp: + System.out.println("Up arrow pressed"); + break; + case Character: + System.out.println("Key pressed: " + keyStroke.getCharacter()); + break; + default: + System.out.println("IDK: " + keyStroke.getKeyType()); + break; + } + } +} diff --git a/src/main/java/cz/jzitnik/events/handlers/MouseActionEventHandler.java b/src/main/java/cz/jzitnik/events/handlers/MouseActionEventHandler.java new file mode 100644 index 0000000..6b4fee1 --- /dev/null +++ b/src/main/java/cz/jzitnik/events/handlers/MouseActionEventHandler.java @@ -0,0 +1,18 @@ +package cz.jzitnik.events.handlers; + +import cz.jzitnik.annotations.EventHandler; +import cz.jzitnik.events.MouseAction; +import cz.jzitnik.utils.DependencyManager; +import cz.jzitnik.utils.events.AbstractEventHandler; + +@EventHandler(MouseAction.class) +public class MouseActionEventHandler extends AbstractEventHandler { + public MouseActionEventHandler(DependencyManager dm) { + super(dm); + } + + @Override + public void handle(MouseAction event) { + System.out.println("ACTION: " + event); + } +} diff --git a/src/main/java/cz/jzitnik/states/RunningState.java b/src/main/java/cz/jzitnik/states/RunningState.java new file mode 100644 index 0000000..0333c74 --- /dev/null +++ b/src/main/java/cz/jzitnik/states/RunningState.java @@ -0,0 +1,10 @@ +package cz.jzitnik.states; + +import cz.jzitnik.annotations.State; +import lombok.Data; + +@Data +@State +public class RunningState { + private boolean running = true; +} diff --git a/src/main/java/cz/jzitnik/utils/DependencyManager.java b/src/main/java/cz/jzitnik/utils/DependencyManager.java new file mode 100644 index 0000000..1ff7234 --- /dev/null +++ b/src/main/java/cz/jzitnik/utils/DependencyManager.java @@ -0,0 +1,142 @@ +package cz.jzitnik.utils; + +import cz.jzitnik.annotations.Config; +import cz.jzitnik.annotations.Dependency; +import cz.jzitnik.annotations.injectors.InjectConfig; +import cz.jzitnik.annotations.injectors.InjectDependency; +import cz.jzitnik.annotations.injectors.InjectState; +import lombok.extern.slf4j.Slf4j; +import org.reflections.Reflections; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Optional; +import java.util.Set; + +@Slf4j +public class DependencyManager { + private final HashMap, Object> configs = new HashMap<>(); + private final HashMap, Object> data = new HashMap<>(); + + public T getDependencyOrThrow(Class clazz) { + T instance = get(clazz); + + if (instance == null) { + throw new RuntimeException("Class was not found!"); + } + + return instance; + } + + public Optional getDependency(Class clazz) { + return Optional.ofNullable(get(clazz)); + } + + @SuppressWarnings("unchecked") + private T get(Class clazz) { + return (T) data.get(clazz); + } + + public DependencyManager(Reflections reflections) { + Set> configClasses = reflections.getTypesAnnotatedWith(Config.class); + for (Class configClass : configClasses) { + try { + Constructor constructor = configClass.getDeclaredConstructor(); + var instance = constructor.newInstance(); + configs.put(configClass, instance); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | + IllegalAccessException _) { + } + } + + Set> classes = reflections.getTypesAnnotatedWith(Dependency.class); + + // Construct all classes + for (Class clazz : classes) { + for (var constructor : clazz.getDeclaredConstructors()) { + var paramTypes = constructor.getParameterTypes(); + var params = new Object[paramTypes.length]; + boolean suitable = true; + + for (int i = 0; i < paramTypes.length; i++) { + Class type = paramTypes[i]; + if (configs.containsKey(type)) + params[i] = configs.get(type); + else if (type == getClass()) + params[i] = this; + else if (type == Reflections.class) + params[i] = reflections; + else { + suitable = false; + break; + } + } + + if (!suitable) continue; + + constructor.setAccessible(true); + try { + Object instance = constructor.newInstance(params); + Dependency annotation = clazz.getAnnotation(Dependency.class); + + if (annotation.value() != Object.class) { + data.put(annotation.value(), instance); + } else { + data.put(clazz, instance); + } + } catch (InstantiationException | InvocationTargetException | IllegalAccessException e) { + throw new RuntimeException(e); + } + break; // Found a matching constructor, go to next class + } + } + + StateManager stateManager = (StateManager) data.get(StateManager.class); + for (Object instance: data.values()) { + Class clazz = instance.getClass(); + + for (Field field : clazz.getDeclaredFields()) { + if (field.isAnnotationPresent(InjectDependency.class)) { + field.setAccessible(true); + + if (!data.containsKey(field.getType())) continue; + + Object dependency = data.get(field.getType()); + + if (!field.getType().isAssignableFrom(dependency.getClass())) continue; + + try { + field.set(instance, dependency); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } else if (field.isAnnotationPresent(InjectState.class)) { + field.setAccessible(true); + + Optional stateOptional = stateManager.get(field.getType()); + + if (stateOptional.isEmpty()) continue; + + try { + field.set(instance, stateOptional.get()); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } else if (field.isAnnotationPresent(InjectConfig.class)) { + field.setAccessible(true); + Optional config = Optional.ofNullable(configs.get(field.getType())); + + if (config.isEmpty()) continue; + + try { + field.set(instance, config.get()); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + } + } +} diff --git a/src/main/java/cz/jzitnik/utils/StateManager.java b/src/main/java/cz/jzitnik/utils/StateManager.java new file mode 100644 index 0000000..9bd10e5 --- /dev/null +++ b/src/main/java/cz/jzitnik/utils/StateManager.java @@ -0,0 +1,38 @@ +// NOTE: [StateManager] cannot use injectors like @InjectDependency or @InjectState +package cz.jzitnik.utils; + +import cz.jzitnik.annotations.Dependency; +import cz.jzitnik.annotations.State; +import org.reflections.Reflections; + +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Optional; + +@Dependency +public class StateManager { + private final HashMap, Object> data = new HashMap<>(); + + public StateManager(Reflections reflections) { + var classes = reflections.getTypesAnnotatedWith(State.class); + + for (Class clazz : classes) { + try { + var instance = clazz.getDeclaredConstructor().newInstance(); + data.put(clazz, instance); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | + NoSuchMethodException _) { + } + } + } + + @SuppressWarnings("unchecked") + public Optional get(Class clazz) { + return Optional.ofNullable((T) data.get(clazz)); + } + + @SuppressWarnings("unchecked") + public T getOrThrow(Class clazz) { + return (T) data.get(clazz); + } +} diff --git a/src/main/java/cz/jzitnik/utils/events/AbstractEventHandler.java b/src/main/java/cz/jzitnik/utils/events/AbstractEventHandler.java new file mode 100644 index 0000000..42a9b57 --- /dev/null +++ b/src/main/java/cz/jzitnik/utils/events/AbstractEventHandler.java @@ -0,0 +1,13 @@ +package cz.jzitnik.utils.events; + +import cz.jzitnik.utils.DependencyManager; + +public abstract class AbstractEventHandler { + protected final DependencyManager dm; + + public AbstractEventHandler(DependencyManager dm) { + this.dm = dm; + } + + public abstract void handle(T event); +} diff --git a/src/main/java/cz/jzitnik/utils/events/Event.java b/src/main/java/cz/jzitnik/utils/events/Event.java new file mode 100644 index 0000000..f184fa6 --- /dev/null +++ b/src/main/java/cz/jzitnik/utils/events/Event.java @@ -0,0 +1,4 @@ +package cz.jzitnik.utils.events; + +public interface Event { +} diff --git a/src/main/java/cz/jzitnik/utils/events/EventManager.java b/src/main/java/cz/jzitnik/utils/events/EventManager.java new file mode 100644 index 0000000..cb5dce3 --- /dev/null +++ b/src/main/java/cz/jzitnik/utils/events/EventManager.java @@ -0,0 +1,74 @@ +package cz.jzitnik.utils.events; + +import cz.jzitnik.annotations.Dependency; +import cz.jzitnik.annotations.EventHandler; +import cz.jzitnik.annotations.injectors.InjectState; +import cz.jzitnik.states.RunningState; +import cz.jzitnik.utils.DependencyManager; +import org.reflections.Reflections; + +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +@Dependency +public class EventManager extends Thread { + @InjectState + private RunningState runningState; + + private final HashMap, AbstractEventHandler> handlers = new HashMap<>(); + private final BlockingQueue eventQueue = new LinkedBlockingQueue<>(); + + @SuppressWarnings("unchecked") + private AbstractEventHandler getHandler(Class type) { + return (AbstractEventHandler) handlers.get(type); + } + + public void emitEvent(Event event) { + eventQueue.add(event); + } + + public EventManager(Reflections reflections, DependencyManager dependencyManager) { + setDaemon(true); + + var classes = reflections.getTypesAnnotatedWith(EventHandler.class); + + for (var clazz : classes) { + EventHandler eventHandler = clazz.getAnnotation(EventHandler.class); + try { + var instance = (AbstractEventHandler) clazz.getDeclaredConstructor(DependencyManager.class).newInstance(dependencyManager); + handlers.put(eventHandler.value(), instance); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | + NoSuchMethodException e) { + } + } + + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @Override + public void run() { + while (runningState.isRunning()) { + try { + Event event = eventQueue.take(); + handleEvent(event); + } catch (InterruptedException e) { + // Program stops + } + } + } + + @SuppressWarnings("unchecked") + private void handleEvent(Event event) { + T typedEvent = (T) event; // safe because handler is keyed by event.getClass() + AbstractEventHandler handler = getHandler((Class) event.getClass()); + Thread thread = new Thread(() -> handler.handle(typedEvent)); + thread.setDaemon(true); + thread.start(); + } +}