diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/entity/Entity.java b/api/src/main/java/com/bartlomiejpluta/base/api/entity/Entity.java index 738a8c7c..4191be55 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/entity/Entity.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/entity/Entity.java @@ -1,6 +1,8 @@ package com.bartlomiejpluta.base.api.entity; import com.bartlomiejpluta.base.api.animation.Animated; +import com.bartlomiejpluta.base.api.event.Event; +import com.bartlomiejpluta.base.api.event.EventType; import com.bartlomiejpluta.base.api.event.Reactive; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.move.Direction; @@ -9,6 +11,7 @@ import com.bartlomiejpluta.base.internal.logic.Updatable; import com.bartlomiejpluta.base.internal.render.Renderable; import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; public interface Entity extends Reactive, Movable, Animated, Renderable, Updatable { @@ -39,4 +42,8 @@ public interface Entity extends Reactive, Movable, Animated, Renderable, Updatab void setZIndex(int zIndex); CompletableFuture performInstantAnimation(); + + void addEventListener(EventType type, Consumer listener); + + void removeEventListener(EventType type, Consumer listener); } diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/event/Event.java b/api/src/main/java/com/bartlomiejpluta/base/api/event/Event.java index 5b13d3d7..6dc7e6e1 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/event/Event.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/event/Event.java @@ -2,4 +2,8 @@ package com.bartlomiejpluta.base.api.event; public interface Event { EventType getType(); + + boolean isConsumed(); + + void consume(); } diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/event/Reactive.java b/api/src/main/java/com/bartlomiejpluta/base/api/event/Reactive.java index 8fcc3ad4..de7d7036 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/event/Reactive.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/event/Reactive.java @@ -1,11 +1,5 @@ package com.bartlomiejpluta.base.api.event; -import java.util.function.Consumer; - public interface Reactive { void handleEvent(E event); - - void addEventListener(EventType type, Consumer listener); - - void removeEventListener(EventType type, Consumer listener); } diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/gui/Widget.java b/api/src/main/java/com/bartlomiejpluta/base/api/gui/Widget.java index 7c939a23..0277f3dc 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/gui/Widget.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/gui/Widget.java @@ -1,9 +1,9 @@ package com.bartlomiejpluta.base.api.gui; -import com.bartlomiejpluta.base.api.input.KeyEventHandler; +import com.bartlomiejpluta.base.api.event.Reactive; import com.bartlomiejpluta.base.api.screen.Screen; -public interface Widget extends KeyEventHandler { +public interface Widget extends Reactive { Widget getParent(); void setParent(Widget parent); diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/gui/WindowManager.java b/api/src/main/java/com/bartlomiejpluta/base/api/gui/WindowManager.java index 0ef2dcc0..3ab54eb2 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/gui/WindowManager.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/gui/WindowManager.java @@ -62,7 +62,7 @@ public final class WindowManager extends BaseWidget { requireNonNull(window, "Window cannot be null"); if (windows.isEmpty()) { - input.addKeyEventHandler(this); + input.addKeyEventHandler(this::forwardKeyEventToTopWindow); } windows.addLast(window); @@ -70,6 +70,13 @@ public final class WindowManager extends BaseWidget { window.onOpen(this); } + private void forwardKeyEventToTopWindow(KeyEvent event) { + var topWindow = windows.peekLast(); + if (topWindow != null) { + topWindow.handleEvent(event); + } + } + public void closeAll() { // Use iterator to support removal from loop inside @@ -88,7 +95,7 @@ public final class WindowManager extends BaseWidget { window.onClose(this); if (windows.isEmpty()) { - input.removeKeyEventHandler(this); + input.removeKeyEventHandler(this::forwardKeyEventToTopWindow); } } @@ -114,14 +121,6 @@ public final class WindowManager extends BaseWidget { } } - @Override - public void handleKeyEvent(KeyEvent event) { - var topWindow = windows.peekLast(); - if (topWindow != null) { - topWindow.handleKeyEvent(event); - } - } - private void drawWindow(Screen screen, Window window, GUI gui) { switch (window.getWindowPosition()) { case TOP -> window.setPosition( diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/input/Input.java b/api/src/main/java/com/bartlomiejpluta/base/api/input/Input.java index ad06a6a9..2677e49c 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/input/Input.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/input/Input.java @@ -1,9 +1,11 @@ package com.bartlomiejpluta.base.api.input; +import java.util.function.Consumer; + public interface Input { boolean isKeyPressed(Key key); - void addKeyEventHandler(KeyEventHandler handler); + void addKeyEventHandler(Consumer handler); - void removeKeyEventHandler(KeyEventHandler handler); + void removeKeyEventHandler(Consumer handler); } diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/input/InputEvent.java b/api/src/main/java/com/bartlomiejpluta/base/api/input/InputEvent.java deleted file mode 100644 index cbb7037b..00000000 --- a/api/src/main/java/com/bartlomiejpluta/base/api/input/InputEvent.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.bartlomiejpluta.base.api.input; - -public interface InputEvent { - boolean isConsumed(); - - void consume(); -} diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/input/KeyEvent.java b/api/src/main/java/com/bartlomiejpluta/base/api/input/KeyEvent.java index 968a9020..966807b2 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/input/KeyEvent.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/input/KeyEvent.java @@ -1,7 +1,12 @@ package com.bartlomiejpluta.base.api.input; -public interface KeyEvent extends InputEvent { +import com.bartlomiejpluta.base.api.event.Event; +import com.bartlomiejpluta.base.api.event.EventType; + +public interface KeyEvent extends Event { Key getKey(); KeyAction getAction(); + + EventType TYPE = new EventType<>("KEY_EVENT"); } diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/input/KeyEventHandler.java b/api/src/main/java/com/bartlomiejpluta/base/api/input/KeyEventHandler.java deleted file mode 100644 index 410b7b3a..00000000 --- a/api/src/main/java/com/bartlomiejpluta/base/api/input/KeyEventHandler.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.bartlomiejpluta.base.api.input; - -@FunctionalInterface -public interface KeyEventHandler { - void handleKeyEvent(KeyEvent event); - - default void onKeyEventHandlerRegister() { - // do nothing - } - - default void onKeyEventHandlerUnregister() { - // do nothing - } -} diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/map/layer/object/ObjectLayer.java b/api/src/main/java/com/bartlomiejpluta/base/api/map/layer/object/ObjectLayer.java index 54e9134d..0577224f 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/map/layer/object/ObjectLayer.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/map/layer/object/ObjectLayer.java @@ -1,14 +1,14 @@ package com.bartlomiejpluta.base.api.map.layer.object; import com.bartlomiejpluta.base.api.entity.Entity; -import com.bartlomiejpluta.base.api.event.Event; +import com.bartlomiejpluta.base.api.event.Reactive; import com.bartlomiejpluta.base.api.map.layer.base.Layer; import com.bartlomiejpluta.base.api.move.Movement; import org.joml.Vector2ic; import java.util.List; -public interface ObjectLayer extends Layer { +public interface ObjectLayer extends Layer, Reactive { void addEntity(Entity entity); void removeEntity(Entity entity); @@ -24,6 +24,4 @@ public interface ObjectLayer extends Layer { boolean isTileReachable(Vector2ic tileCoordinates); void pushMovement(Movement movement); - - void fireEvent(Event event); } diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/move/EntityMovement.java b/api/src/main/java/com/bartlomiejpluta/base/api/move/EntityMovement.java index f40d33d0..d433b7bb 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/move/EntityMovement.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/move/EntityMovement.java @@ -27,7 +27,7 @@ public final class EntityMovement implements Movement { public boolean perform() { var result = object.move(this); if (result) { - object.getLayer().fireEvent(new MoveEvent(MoveEvent.Action.BEGIN, object, this)); + object.getLayer().handleEvent(new MoveEvent(MoveEvent.Action.BEGIN, object, this)); } return result; @@ -40,6 +40,6 @@ public final class EntityMovement implements Movement { @Override public void onFinish() { - object.getLayer().fireEvent(new MoveEvent(MoveEvent.Action.END, object, this)); + object.getLayer().handleEvent(new MoveEvent(MoveEvent.Action.END, object, this)); } } diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/move/MoveEvent.java b/api/src/main/java/com/bartlomiejpluta/base/api/move/MoveEvent.java index 80183fd0..854d297e 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/move/MoveEvent.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/move/MoveEvent.java @@ -2,12 +2,13 @@ package com.bartlomiejpluta.base.api.move; import com.bartlomiejpluta.base.api.event.Event; import com.bartlomiejpluta.base.api.event.EventType; +import com.bartlomiejpluta.base.lib.event.BaseEvent; import lombok.Getter; import lombok.RequiredArgsConstructor; @Getter @RequiredArgsConstructor -public final class MoveEvent implements Event { +public final class MoveEvent extends BaseEvent { public enum Action {BEGIN, END} private final Action action; diff --git a/api/src/main/java/com/bartlomiejpluta/base/lib/event/BaseEvent.java b/api/src/main/java/com/bartlomiejpluta/base/lib/event/BaseEvent.java new file mode 100644 index 00000000..1ec7a681 --- /dev/null +++ b/api/src/main/java/com/bartlomiejpluta/base/lib/event/BaseEvent.java @@ -0,0 +1,15 @@ +package com.bartlomiejpluta.base.lib.event; + +import com.bartlomiejpluta.base.api.event.Event; +import lombok.Getter; + +public abstract class BaseEvent implements Event { + + @Getter + private boolean consumed = false; + + @Override + public void consume() { + consumed = true; + } +} diff --git a/api/src/main/java/com/bartlomiejpluta/base/lib/event/EventHandler.java b/api/src/main/java/com/bartlomiejpluta/base/lib/event/EventHandler.java new file mode 100644 index 00000000..a91ac955 --- /dev/null +++ b/api/src/main/java/com/bartlomiejpluta/base/lib/event/EventHandler.java @@ -0,0 +1,52 @@ +package com.bartlomiejpluta.base.lib.event; + +import com.bartlomiejpluta.base.api.event.Event; +import com.bartlomiejpluta.base.api.event.EventType; +import com.bartlomiejpluta.base.api.event.Reactive; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +public final class EventHandler implements Reactive { + private final Map, ArrayList>> listeners = new HashMap<>(); + + @SuppressWarnings("unchecked") + @Override + public void handleEvent(E event) { + var list = listeners.get(event.getType()); + if (list != null) { + for (var i = list.size() - 1; i >= 0; --i) { + if (event.isConsumed()) { + return; + } + + ((Consumer) list.get(i)).accept(event); + } + } + } + + public void addListener(EventType type, Consumer listener) { + var list = this.listeners.get(type); + + if (list != null) { + list.add(listener); + } else { + list = new ArrayList<>(); + list.add(listener); + listeners.put(type, list); + } + } + + public void removeListener(EventType type, Consumer listener) { + var list = this.listeners.get(type); + + if (list != null) { + list.remove(listener); + if (list.isEmpty()) { + this.listeners.remove(type); + } + } + } +} diff --git a/api/src/main/java/com/bartlomiejpluta/base/lib/gui/BaseContainer.java b/api/src/main/java/com/bartlomiejpluta/base/lib/gui/BaseContainer.java index 064e8fb0..2b184e8f 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/lib/gui/BaseContainer.java +++ b/api/src/main/java/com/bartlomiejpluta/base/lib/gui/BaseContainer.java @@ -1,9 +1,9 @@ package com.bartlomiejpluta.base.lib.gui; import com.bartlomiejpluta.base.api.context.Context; +import com.bartlomiejpluta.base.api.event.Event; import com.bartlomiejpluta.base.api.gui.Component; import com.bartlomiejpluta.base.api.gui.GUI; -import com.bartlomiejpluta.base.api.input.KeyEvent; import java.util.LinkedList; import java.util.List; @@ -92,13 +92,16 @@ public abstract class BaseContainer extends BaseComponent { } @Override - public void handleKeyEvent(KeyEvent event) { + public void handleEvent(E event) { + // Populate event downstream for (var child : children) { if (event.isConsumed()) { return; } - child.handleKeyEvent(event); + child.handleEvent(event); } + + eventHandler.handleEvent(event); } } diff --git a/api/src/main/java/com/bartlomiejpluta/base/lib/gui/BaseWidget.java b/api/src/main/java/com/bartlomiejpluta/base/lib/gui/BaseWidget.java index 13ca181f..b912206c 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/lib/gui/BaseWidget.java +++ b/api/src/main/java/com/bartlomiejpluta/base/lib/gui/BaseWidget.java @@ -1,8 +1,12 @@ package com.bartlomiejpluta.base.lib.gui; +import com.bartlomiejpluta.base.api.event.Event; +import com.bartlomiejpluta.base.api.event.EventType; import com.bartlomiejpluta.base.api.gui.SizeMode; import com.bartlomiejpluta.base.api.gui.Widget; -import com.bartlomiejpluta.base.api.input.KeyEvent; +import com.bartlomiejpluta.base.lib.event.EventHandler; + +import java.util.function.Consumer; public abstract class BaseWidget implements Widget { protected Widget parent; @@ -26,6 +30,8 @@ public abstract class BaseWidget implements Widget { protected float paddingBottom; protected float paddingLeft; + protected final EventHandler eventHandler = new EventHandler(); + protected abstract float getContentWidth(); protected abstract float getContentHeight(); @@ -277,7 +283,15 @@ public abstract class BaseWidget implements Widget { } @Override - public void handleKeyEvent(KeyEvent event) { - // Designed to be overridden if needed so + public void handleEvent(E event) { + eventHandler.handleEvent(event); + } + + protected void addEventListener(EventType type, Consumer listener) { + eventHandler.addListener(type, listener); + } + + protected void removeEventListener(EventType type, Consumer listener) { + eventHandler.removeListener(type, listener); } } diff --git a/api/src/main/java/com/bartlomiejpluta/base/lib/gui/BaseWindow.java b/api/src/main/java/com/bartlomiejpluta/base/lib/gui/BaseWindow.java index 1c3f9849..fe6918f9 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/lib/gui/BaseWindow.java +++ b/api/src/main/java/com/bartlomiejpluta/base/lib/gui/BaseWindow.java @@ -1,8 +1,8 @@ package com.bartlomiejpluta.base.lib.gui; import com.bartlomiejpluta.base.api.context.Context; +import com.bartlomiejpluta.base.api.event.Event; import com.bartlomiejpluta.base.api.gui.*; -import com.bartlomiejpluta.base.api.input.KeyEvent; import com.bartlomiejpluta.base.api.screen.Screen; import static java.util.Objects.requireNonNull; @@ -59,8 +59,10 @@ public abstract class BaseWindow extends BaseWidget implements Window { } @Override - public void handleKeyEvent(KeyEvent event) { - content.handleKeyEvent(event); + public void handleEvent(E event) { + if (content != null) { + content.handleEvent(event); + } } @Override diff --git a/api/src/main/java/com/bartlomiejpluta/base/lib/gui/HOptionChoice.java b/api/src/main/java/com/bartlomiejpluta/base/lib/gui/HOptionChoice.java index 643e4a9e..843788b0 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/lib/gui/HOptionChoice.java +++ b/api/src/main/java/com/bartlomiejpluta/base/lib/gui/HOptionChoice.java @@ -1,6 +1,7 @@ package com.bartlomiejpluta.base.lib.gui; import com.bartlomiejpluta.base.api.context.Context; +import com.bartlomiejpluta.base.api.event.Event; import com.bartlomiejpluta.base.api.gui.GUI; import com.bartlomiejpluta.base.api.input.Key; import com.bartlomiejpluta.base.api.input.KeyAction; @@ -14,6 +15,7 @@ public class HOptionChoice extends HScrollableLayout { public HOptionChoice(Context context, GUI gui) { super(context, gui); + addEventListener(KeyEvent.TYPE, this::switchOption); } @Override @@ -26,16 +28,18 @@ public class HOptionChoice extends HScrollableLayout { } @Override - public void handleKeyEvent(KeyEvent event) { - if (children.isEmpty()) { - return; + public void handleEvent(E event) { + if (selected < children.size()) { + children.get(selected).handleEvent(event); } - // First we want to propagate it down tree - children.get(selected).handleKeyEvent(event); + if (!event.isConsumed()) { + eventHandler.handleEvent(event); + } + } - // If event is still not consumed, we try to consume it right here - if (event.isConsumed()) { + private void switchOption(KeyEvent event) { + if (children.isEmpty()) { return; } diff --git a/api/src/main/java/com/bartlomiejpluta/base/lib/gui/HScrollableLayout.java b/api/src/main/java/com/bartlomiejpluta/base/lib/gui/HScrollableLayout.java index 8f996534..5f3fb1de 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/lib/gui/HScrollableLayout.java +++ b/api/src/main/java/com/bartlomiejpluta/base/lib/gui/HScrollableLayout.java @@ -18,6 +18,7 @@ public class HScrollableLayout extends HLayout { public HScrollableLayout(Context context, GUI gui) { super(context, gui); + addEventListener(KeyEvent.TYPE, this::handleKeyEvent); } public float getActualScroll() { @@ -83,10 +84,7 @@ public class HScrollableLayout extends HLayout { super.setHeightMode(mode); } - @Override - public void handleKeyEvent(KeyEvent event) { - super.handleKeyEvent(event); - + private void handleKeyEvent(KeyEvent event) { if (event.isConsumed()) { return; } diff --git a/api/src/main/java/com/bartlomiejpluta/base/lib/gui/VOptionChoice.java b/api/src/main/java/com/bartlomiejpluta/base/lib/gui/VOptionChoice.java index 1e600749..9bbd4f85 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/lib/gui/VOptionChoice.java +++ b/api/src/main/java/com/bartlomiejpluta/base/lib/gui/VOptionChoice.java @@ -1,6 +1,7 @@ package com.bartlomiejpluta.base.lib.gui; import com.bartlomiejpluta.base.api.context.Context; +import com.bartlomiejpluta.base.api.event.Event; import com.bartlomiejpluta.base.api.gui.GUI; import com.bartlomiejpluta.base.api.input.Key; import com.bartlomiejpluta.base.api.input.KeyAction; @@ -14,6 +15,7 @@ public class VOptionChoice extends VScrollableLayout { public VOptionChoice(Context context, GUI gui) { super(context, gui); + addEventListener(KeyEvent.TYPE, this::switchOption); } @Override @@ -26,16 +28,18 @@ public class VOptionChoice extends VScrollableLayout { } @Override - public void handleKeyEvent(KeyEvent event) { - if (children.isEmpty()) { - return; + public void handleEvent(E event) { + if (selected < children.size()) { + children.get(selected).handleEvent(event); } - // First we want to propagate it down tree - children.get(selected).handleKeyEvent(event); + if (!event.isConsumed()) { + eventHandler.handleEvent(event); + } + } - // If event is still not consumed, we try to consume it right here - if (event.isConsumed()) { + private void switchOption(KeyEvent event) { + if (children.isEmpty()) { return; } diff --git a/api/src/main/java/com/bartlomiejpluta/base/lib/gui/VScrollableLayout.java b/api/src/main/java/com/bartlomiejpluta/base/lib/gui/VScrollableLayout.java index edb3d960..4993b7be 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/lib/gui/VScrollableLayout.java +++ b/api/src/main/java/com/bartlomiejpluta/base/lib/gui/VScrollableLayout.java @@ -18,6 +18,7 @@ public class VScrollableLayout extends VLayout { public VScrollableLayout(Context context, GUI gui) { super(context, gui); + addEventListener(KeyEvent.TYPE, this::scroll); } public float getActualScroll() { @@ -83,10 +84,7 @@ public class VScrollableLayout extends VLayout { super.setHeightMode(mode); } - @Override - public void handleKeyEvent(KeyEvent event) { - super.handleKeyEvent(event); - + private void scroll(KeyEvent event) { if (event.isConsumed()) { return; } diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/context/model/DefaultContext.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/context/model/DefaultContext.java index b71e45b8..79fa4968 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/context/model/DefaultContext.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/context/model/DefaultContext.java @@ -5,18 +5,17 @@ import com.bartlomiejpluta.base.api.audio.Sound; import com.bartlomiejpluta.base.api.camera.Camera; import com.bartlomiejpluta.base.api.context.Context; import com.bartlomiejpluta.base.api.entity.Entity; +import com.bartlomiejpluta.base.api.event.Reactive; import com.bartlomiejpluta.base.api.gui.GUI; import com.bartlomiejpluta.base.api.image.Image; import com.bartlomiejpluta.base.api.input.Input; import com.bartlomiejpluta.base.api.input.KeyEvent; -import com.bartlomiejpluta.base.api.input.KeyEventHandler; import com.bartlomiejpluta.base.api.map.handler.MapHandler; import com.bartlomiejpluta.base.api.runner.GameRunner; import com.bartlomiejpluta.base.api.screen.Screen; import com.bartlomiejpluta.base.engine.audio.manager.SoundManager; import com.bartlomiejpluta.base.engine.core.engine.GameEngine; import com.bartlomiejpluta.base.engine.database.service.DatabaseService; -import com.bartlomiejpluta.base.engine.error.AppException; import com.bartlomiejpluta.base.engine.gui.manager.FontManager; import com.bartlomiejpluta.base.engine.gui.manager.WidgetDefinitionManager; import com.bartlomiejpluta.base.engine.gui.render.NanoVGGUI; @@ -42,7 +41,7 @@ import java.util.List; @Slf4j @Builder -public class DefaultContext implements Context, KeyEventHandler { +public class DefaultContext implements Context { @NonNull private final GameEngine engine; @@ -106,11 +105,23 @@ public class DefaultContext implements Context, KeyEventHandler { this.input = input; this.camera = camera; - input.addKeyEventHandler(this); + input.addKeyEventHandler(this::populateKeyEventToObjectLayers); gameRunner.init(this); } + private void populateKeyEventToObjectLayers(KeyEvent event) { + if (map == null || event.isConsumed()) { + return; + } + + for (var layer : map.getLayers()) { + if (layer instanceof Reactive) { + ((Reactive) layer).handleEvent(event); + } + } + } + @SneakyThrows @Override public void openMap(@NonNull String mapUid) { @@ -237,24 +248,6 @@ public class DefaultContext implements Context, KeyEventHandler { } } - @Override - public void handleKeyEvent(KeyEvent event) { - if (map == null || event.isConsumed()) { - return; - } - - for (var layer : map.getLayers()) { - if (layer instanceof KeyEventHandler) { - ((KeyEventHandler) layer).handleKeyEvent(event); - } - } - } - - @Override - public void onKeyEventHandlerUnregister() { - throw new AppException("Context cannot be unregistered"); - } - @Override public void update(float dt) { gameRunner.update(dt); diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/gui/widget/ScreenWidget.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/gui/widget/ScreenWidget.java index 6e2955d2..e06eb4fd 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/gui/widget/ScreenWidget.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/gui/widget/ScreenWidget.java @@ -1,9 +1,9 @@ package com.bartlomiejpluta.base.engine.gui.widget; +import com.bartlomiejpluta.base.api.event.Event; import com.bartlomiejpluta.base.api.gui.GUI; import com.bartlomiejpluta.base.api.gui.SizeMode; import com.bartlomiejpluta.base.api.gui.Widget; -import com.bartlomiejpluta.base.api.input.KeyEvent; import com.bartlomiejpluta.base.api.screen.Screen; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -233,7 +233,7 @@ public class ScreenWidget implements Widget { } @Override - public void handleKeyEvent(KeyEvent event) { + public void handleEvent(E event) { throw new UnsupportedOperationException(); } diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/ui/event/GLFWKeyEvent.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/ui/event/GLFWKeyEvent.java index 2c2d552d..c19134ad 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/ui/event/GLFWKeyEvent.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/ui/event/GLFWKeyEvent.java @@ -1,5 +1,7 @@ package com.bartlomiejpluta.base.engine.ui.event; +import com.bartlomiejpluta.base.api.event.Event; +import com.bartlomiejpluta.base.api.event.EventType; import com.bartlomiejpluta.base.api.input.Key; import com.bartlomiejpluta.base.api.input.KeyAction; import com.bartlomiejpluta.base.api.input.KeyEvent; @@ -19,6 +21,11 @@ public class GLFWKeyEvent implements KeyEvent { private final KeyAction action; private boolean consumed; + @Override + public EventType getType() { + return KeyEvent.TYPE; + } + @Override public void consume() { consumed = true; diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/ui/model/GLFWInput.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/ui/model/GLFWInput.java index f83afb93..3f3ef6bb 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/ui/model/GLFWInput.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/ui/model/GLFWInput.java @@ -2,7 +2,7 @@ package com.bartlomiejpluta.base.engine.ui.model; import com.bartlomiejpluta.base.api.input.Input; import com.bartlomiejpluta.base.api.input.Key; -import com.bartlomiejpluta.base.api.input.KeyEventHandler; +import com.bartlomiejpluta.base.api.input.KeyEvent; import com.bartlomiejpluta.base.api.screen.Screen; import com.bartlomiejpluta.base.engine.ui.event.GLFWKeyEvent; import lombok.NonNull; @@ -10,6 +10,7 @@ import lombok.extern.slf4j.Slf4j; import java.util.Deque; import java.util.LinkedList; +import java.util.function.Consumer; import static com.bartlomiejpluta.base.engine.ui.event.GLFWKeyEvent.glfwCode; import static org.lwjgl.glfw.GLFW.*; @@ -17,7 +18,7 @@ import static org.lwjgl.glfw.GLFW.*; @Slf4j public class GLFWInput implements Input { private final long windowHandle; - private final Deque keyEventHandlers = new LinkedList<>(); + private final Deque> keyEventHandlers = new LinkedList<>(); public GLFWInput(@NonNull Screen screen) { this.windowHandle = screen.getID(); @@ -39,7 +40,7 @@ public class GLFWInput implements Input { return; } - iterator.next().handleKeyEvent(event); + iterator.next().accept(event); } }); @@ -52,14 +53,12 @@ public class GLFWInput implements Input { } @Override - public void addKeyEventHandler(@NonNull KeyEventHandler handler) { + public void addKeyEventHandler(@NonNull Consumer handler) { keyEventHandlers.addLast(handler); - handler.onKeyEventHandlerRegister(); } @Override - public void removeKeyEventHandler(@NonNull KeyEventHandler handler) { + public void removeKeyEventHandler(@NonNull Consumer handler) { keyEventHandlers.remove(handler); - handler.onKeyEventHandlerUnregister(); } } diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/entity/model/DefaultEntity.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/entity/model/DefaultEntity.java index cde2f636..f7822b67 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/entity/model/DefaultEntity.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/entity/model/DefaultEntity.java @@ -12,6 +12,7 @@ import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh; import com.bartlomiejpluta.base.engine.error.AppException; import com.bartlomiejpluta.base.engine.world.entity.manager.EntitySetManager; import com.bartlomiejpluta.base.engine.world.movement.MovableSprite; +import com.bartlomiejpluta.base.lib.event.EventHandler; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @@ -19,7 +20,9 @@ import org.joml.Vector2f; import org.joml.Vector2fc; import org.joml.Vector2i; -import java.util.*; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; @@ -34,7 +37,7 @@ public class DefaultEntity extends MovableSprite implements Entity { private final Vector2f entityScale = new Vector2f(1, 1); private Vector2fc entitySetSize; - private final Map, List>> listeners = new HashMap<>(); + private final EventHandler eventHandler = new EventHandler(); @Getter @Setter @@ -236,40 +239,19 @@ public class DefaultEntity extends MovableSprite implements Entity { return entityScale.y; } - @SuppressWarnings("unchecked") @Override public void handleEvent(E event) { - var list = listeners.get(event.getType()); - if (list != null) { - for (var listener : list) { - ((Consumer) listener).accept(event); - } - } + eventHandler.handleEvent(event); } @Override public void addEventListener(EventType type, Consumer listener) { - var list = this.listeners.get(type); - - if (list != null) { - list.add(listener); - } else { - list = new ArrayList<>(); - list.add(listener); - listeners.put(type, list); - } + eventHandler.addListener(type, listener); } @Override public void removeEventListener(EventType type, Consumer listener) { - var list = this.listeners.get(type); - - if (list != null) { - list.remove(listener); - if (list.isEmpty()) { - this.listeners.remove(type); - } - } + eventHandler.removeListener(type, listener); } @Override diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/map/layer/object/DefaultObjectLayer.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/map/layer/object/DefaultObjectLayer.java index 0e1ff4a9..5a24b107 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/map/layer/object/DefaultObjectLayer.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/map/layer/object/DefaultObjectLayer.java @@ -4,8 +4,7 @@ import com.bartlomiejpluta.base.api.ai.NPC; import com.bartlomiejpluta.base.api.camera.Camera; import com.bartlomiejpluta.base.api.entity.Entity; import com.bartlomiejpluta.base.api.event.Event; -import com.bartlomiejpluta.base.api.input.KeyEvent; -import com.bartlomiejpluta.base.api.input.KeyEventHandler; +import com.bartlomiejpluta.base.api.event.Reactive; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.map.layer.object.PassageAbility; import com.bartlomiejpluta.base.api.map.model.GameMap; @@ -24,7 +23,7 @@ import java.util.Queue; import static java.lang.Float.compare; import static java.lang.Integer.compare; -public class DefaultObjectLayer extends BaseLayer implements ObjectLayer, KeyEventHandler { +public class DefaultObjectLayer extends BaseLayer implements ObjectLayer, Reactive { @Getter private final ArrayList entities = new ArrayList<>(); @@ -156,14 +155,9 @@ public class DefaultObjectLayer extends BaseLayer implements ObjectLayer, KeyEve return z == 0 ? compare(a.getPosition().y(), b.getPosition().y()) : z; } - @Override - public void handleKeyEvent(KeyEvent event) { - - } - @SuppressWarnings("ForLoopReplaceableByForEach") @Override - public void fireEvent(Event event) { + public void handleEvent(E event) { // Disclaimer // For the sake of an easy adding and removing // entities from the entity.update() method inside