From 898bcc809cd2d0d67a415c4f4031c7def9f26de4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Przemys=C5=82aw=20Pluta?= Date: Tue, 6 Apr 2021 11:57:11 +0200 Subject: [PATCH] Implement event system scaffolding --- .../base/api/entity/Entity.java | 3 +- .../base/api/entity/EntityStepInListener.java | 7 --- .../api/entity/EntityStepOutListener.java | 7 --- .../bartlomiejpluta/base/api/event/Event.java | 5 ++ .../base/api/event/EventType.java | 10 ++++ .../base/api/event/Reactive.java | 11 ++++ .../api/map/layer/object/ObjectLayer.java | 6 +- .../base/api/move/EntityMovement.java | 4 +- .../base/api/move/MoveEvent.java | 23 ++++++++ .../base/lib/entity/EntityDelegate.java | 18 ++++++ .../world/entity/model/DefaultEntity.java | 45 +++++++++++++- .../map/layer/object/DefaultObjectLayer.java | 58 ++++--------------- 12 files changed, 125 insertions(+), 72 deletions(-) delete mode 100644 api/src/main/java/com/bartlomiejpluta/base/api/entity/EntityStepInListener.java delete mode 100644 api/src/main/java/com/bartlomiejpluta/base/api/entity/EntityStepOutListener.java create mode 100644 api/src/main/java/com/bartlomiejpluta/base/api/event/Event.java create mode 100644 api/src/main/java/com/bartlomiejpluta/base/api/event/EventType.java create mode 100644 api/src/main/java/com/bartlomiejpluta/base/api/event/Reactive.java create mode 100644 api/src/main/java/com/bartlomiejpluta/base/api/move/MoveEvent.java 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 64b923a8..738a8c7c 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,7 @@ package com.bartlomiejpluta.base.api.entity; import com.bartlomiejpluta.base.api.animation.Animated; +import com.bartlomiejpluta.base.api.event.Reactive; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.Movable; @@ -9,7 +10,7 @@ import com.bartlomiejpluta.base.internal.render.Renderable; import java.util.concurrent.CompletableFuture; -public interface Entity extends Movable, Animated, Renderable, Updatable { +public interface Entity extends Reactive, Movable, Animated, Renderable, Updatable { Direction getFaceDirection(); diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/entity/EntityStepInListener.java b/api/src/main/java/com/bartlomiejpluta/base/api/entity/EntityStepInListener.java deleted file mode 100644 index 53a1da67..00000000 --- a/api/src/main/java/com/bartlomiejpluta/base/api/entity/EntityStepInListener.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.bartlomiejpluta.base.api.entity; - -import com.bartlomiejpluta.base.api.move.Movement; - -public interface EntityStepInListener extends Entity { - void onEntityStepIn(Movement movement, Entity entity); -} diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/entity/EntityStepOutListener.java b/api/src/main/java/com/bartlomiejpluta/base/api/entity/EntityStepOutListener.java deleted file mode 100644 index 2ef69cb5..00000000 --- a/api/src/main/java/com/bartlomiejpluta/base/api/entity/EntityStepOutListener.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.bartlomiejpluta.base.api.entity; - -import com.bartlomiejpluta.base.api.move.Movement; - -public interface EntityStepOutListener extends Entity { - void onEntityStepOut(Movement movement, Entity entity); -} 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 new file mode 100644 index 00000000..5b13d3d7 --- /dev/null +++ b/api/src/main/java/com/bartlomiejpluta/base/api/event/Event.java @@ -0,0 +1,5 @@ +package com.bartlomiejpluta.base.api.event; + +public interface Event { + EventType getType(); +} diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/event/EventType.java b/api/src/main/java/com/bartlomiejpluta/base/api/event/EventType.java new file mode 100644 index 00000000..5bf6281b --- /dev/null +++ b/api/src/main/java/com/bartlomiejpluta/base/api/event/EventType.java @@ -0,0 +1,10 @@ +package com.bartlomiejpluta.base.api.event; + +import lombok.EqualsAndHashCode; +import lombok.RequiredArgsConstructor; + +@EqualsAndHashCode +@RequiredArgsConstructor +public final class EventType { + private final String type; +} 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 new file mode 100644 index 00000000..8fcc3ad4 --- /dev/null +++ b/api/src/main/java/com/bartlomiejpluta/base/api/event/Reactive.java @@ -0,0 +1,11 @@ +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/map/layer/object/ObjectLayer.java b/api/src/main/java/com/bartlomiejpluta/base/api/map/layer/object/ObjectLayer.java index ca8de37c..54e9134d 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,6 +1,7 @@ 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.map.layer.base.Layer; import com.bartlomiejpluta.base.api.move.Movement; import org.joml.Vector2ic; @@ -24,8 +25,5 @@ public interface ObjectLayer extends Layer { void pushMovement(Movement movement); - // Notifiers - void notifyEntityStepIn(Movement movement, Entity entity); - - void notifyEntityStepOut(Movement movement, Entity entity); + 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 c9aab208..f40d33d0 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().notifyEntityStepOut(this, object); + object.getLayer().fireEvent(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().notifyEntityStepIn(this, object); + object.getLayer().fireEvent(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 new file mode 100644 index 00000000..80183fd0 --- /dev/null +++ b/api/src/main/java/com/bartlomiejpluta/base/api/move/MoveEvent.java @@ -0,0 +1,23 @@ +package com.bartlomiejpluta.base.api.move; + +import com.bartlomiejpluta.base.api.event.Event; +import com.bartlomiejpluta.base.api.event.EventType; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public final class MoveEvent implements Event { + public enum Action {BEGIN, END} + + private final Action action; + private final Movable movable; + private final Movement movement; + + @Override + public EventType getType() { + return TYPE; + } + + public static EventType TYPE = new EventType<>("MOVE_EVENT"); +} diff --git a/api/src/main/java/com/bartlomiejpluta/base/lib/entity/EntityDelegate.java b/api/src/main/java/com/bartlomiejpluta/base/lib/entity/EntityDelegate.java index 14beebda..1819e0a4 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/lib/entity/EntityDelegate.java +++ b/api/src/main/java/com/bartlomiejpluta/base/lib/entity/EntityDelegate.java @@ -2,6 +2,8 @@ package com.bartlomiejpluta.base.lib.entity; 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.event.EventType; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.EntityMovement; @@ -14,6 +16,7 @@ import org.joml.Vector2fc; import org.joml.Vector2ic; import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; public abstract class EntityDelegate implements Entity { protected final Entity entity; @@ -267,6 +270,21 @@ public abstract class EntityDelegate implements Entity { entity.setZIndex(zIndex); } + @Override + public void handleEvent(E event) { + entity.handleEvent(event); + } + + @Override + public void addEventListener(EventType type, Consumer listener) { + entity.addEventListener(type, listener); + } + + @Override + public void removeEventListener(EventType type, Consumer listener) { + entity.removeEventListener(type, listener); + } + @Override public CompletableFuture performInstantAnimation() { return entity.performInstantAnimation(); 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 3849d62f..cde2f636 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 @@ -1,6 +1,8 @@ package com.bartlomiejpluta.base.engine.world.entity.model; import com.bartlomiejpluta.base.api.entity.Entity; +import com.bartlomiejpluta.base.api.event.Event; +import com.bartlomiejpluta.base.api.event.EventType; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.EntityMovement; @@ -17,10 +19,9 @@ import org.joml.Vector2f; import org.joml.Vector2fc; import org.joml.Vector2i; -import java.util.LinkedList; -import java.util.Map; -import java.util.Queue; +import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; import static java.util.Objects.requireNonNull; @@ -33,6 +34,8 @@ 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<>(); + @Getter @Setter private int zIndex = 0; @@ -233,6 +236,42 @@ 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); + } + } + } + + @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); + } + } + + @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); + } + } + } + @Override public void update(float dt) { super.update(dt); 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 12af2002..0e1ff4a9 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 @@ -3,8 +3,7 @@ package com.bartlomiejpluta.base.engine.world.map.layer.object; 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.entity.EntityStepInListener; -import com.bartlomiejpluta.base.api.entity.EntityStepOutListener; +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.map.layer.object.ObjectLayer; @@ -20,7 +19,6 @@ import org.joml.Vector2ic; import java.util.ArrayList; import java.util.LinkedList; -import java.util.List; import java.util.Queue; import static java.lang.Float.compare; @@ -31,10 +29,6 @@ public class DefaultObjectLayer extends BaseLayer implements ObjectLayer, KeyEve @Getter private final ArrayList entities = new ArrayList<>(); - private final List stepInListeners = new ArrayList<>(); - private final List stepOutListeners = new ArrayList<>(); - private final List keyEventHandlers = new ArrayList<>(); - @Getter private final PassageAbility[][] passageMap; @@ -58,18 +52,6 @@ public class DefaultObjectLayer extends BaseLayer implements ObjectLayer, KeyEve layer.entities.remove(entity); } - if (entity instanceof EntityStepInListener) { - stepInListeners.add((EntityStepInListener) entity); - } - - if (entity instanceof EntityStepOutListener) { - stepOutListeners.add((EntityStepOutListener) entity); - } - - if (entity instanceof KeyEventHandler) { - keyEventHandlers.add((KeyEventHandler) entity); - } - entity.setStepSize(stepSize.x(), stepSize.y()); entities.add(entity); @@ -80,18 +62,6 @@ public class DefaultObjectLayer extends BaseLayer implements ObjectLayer, KeyEve public void removeEntity(Entity entity) { entities.remove(entity); - if (entity instanceof EntityStepInListener) { - stepInListeners.remove(entity); - } - - if (entity instanceof EntityStepOutListener) { - stepOutListeners.remove(entity); - } - - if (entity instanceof KeyEventHandler) { - keyEventHandlers.remove(entity); - } - entity.onRemove(this); } @@ -149,7 +119,6 @@ public class DefaultObjectLayer extends BaseLayer implements ObjectLayer, KeyEve while (!movements.isEmpty()) { var movement = movements.poll(); - var from = movement.getFrom(); var to = movement.getTo(); if (isTileReachable(to)) { movement.perform(); @@ -189,26 +158,19 @@ public class DefaultObjectLayer extends BaseLayer implements ObjectLayer, KeyEve @Override public void handleKeyEvent(KeyEvent event) { - for (var handler : keyEventHandlers) { - if (event.isConsumed()) { - return; - } - handler.handleKeyEvent(event); - } } + @SuppressWarnings("ForLoopReplaceableByForEach") @Override - public void notifyEntityStepIn(Movement movement, Entity entity) { - for (var listener : stepInListeners) { - listener.onEntityStepIn(movement, entity); - } - } - - @Override - public void notifyEntityStepOut(Movement movement, Entity entity) { - for (var listener : stepOutListeners) { - listener.onEntityStepOut(movement, entity); + public void fireEvent(Event event) { + // Disclaimer + // For the sake of an easy adding and removing + // entities from the entity.update() method inside + // the loop, the loop itself has been implemented + // as plain old C-style for loop. + for (int i = 0; i < entities.size(); ++i) { + entities.get(i).handleEvent(event); } } }