From cf18da83508345a015d101a0883cfcb294045957 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Tue, 17 Nov 2020 22:53:56 +0300 Subject: [PATCH] Added block breaking and refactored Controls - Blocks can be broken by pointing at them at pressing LMB - Rewritten ControlTriggers - Rewritten KeyMatcher - CollisionPathComputer now has a 0.5 margin --- .../comms/controls/ControlTriggerLambda.java | 48 +++++ .../controls/ControlTriggerOnKeyPress.java | 40 ---- .../comms/controls/ControlTriggers.java | 176 ++++++++++++++++++ .../client/graphics/input/KeyMatcher.java | 82 ++++---- .../collision/CollisionPathComputer.java | 14 +- .../comms/controls/ControlDataRegistry.java | 4 +- .../server/comms/controls/ControlLogic.java | 18 ++ .../test/ControlBreakBlockData.java | 22 +++ .../windcorp/progressia/test/TestContent.java | 75 +++++--- 9 files changed, 378 insertions(+), 101 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLambda.java delete mode 100644 src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerOnKeyPress.java create mode 100644 src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggers.java create mode 100644 src/main/java/ru/windcorp/progressia/test/ControlBreakBlockData.java diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLambda.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLambda.java new file mode 100644 index 0000000..d2a0d69 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLambda.java @@ -0,0 +1,48 @@ +package ru.windcorp.progressia.client.comms.controls; + +import java.util.function.BiConsumer; +import java.util.function.Predicate; + +import ru.windcorp.progressia.client.graphics.input.InputEvent; +import ru.windcorp.progressia.common.comms.controls.ControlData; +import ru.windcorp.progressia.common.comms.controls.ControlDataRegistry; +import ru.windcorp.progressia.common.comms.controls.PacketControl; +import ru.windcorp.progressia.common.util.namespaces.NamespacedUtil; + +public class ControlTriggerLambda extends ControlTriggerInputBased { + + private final String packetId; + private final Predicate predicate; + private final BiConsumer dataWriter; + + public ControlTriggerLambda( + String id, + Predicate predicate, + BiConsumer dataWriter + ) { + super(id); + + this.packetId = NamespacedUtil.getId( + NamespacedUtil.getNamespace(id), + "ControlKeyPress" + NamespacedUtil.getName(id) + ); + + this.predicate = predicate; + this.dataWriter = dataWriter; + } + + @Override + public PacketControl onInputEvent(InputEvent event) { + if (!predicate.test(event)) return null; + + PacketControl packet = new PacketControl( + packetId, + ControlDataRegistry.getInstance().create(getId()) + ); + + dataWriter.accept(event, packet.getControl()); + + return packet; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerOnKeyPress.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerOnKeyPress.java deleted file mode 100644 index 746cb9f..0000000 --- a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerOnKeyPress.java +++ /dev/null @@ -1,40 +0,0 @@ -package ru.windcorp.progressia.client.comms.controls; - -import java.util.function.Predicate; - -import ru.windcorp.progressia.client.graphics.input.InputEvent; -import ru.windcorp.progressia.client.graphics.input.KeyEvent; -import ru.windcorp.progressia.common.comms.controls.ControlDataRegistry; -import ru.windcorp.progressia.common.comms.controls.PacketControl; -import ru.windcorp.progressia.common.util.namespaces.NamespacedUtil; - -public class ControlTriggerOnKeyPress extends ControlTriggerInputBased { - - private final Predicate predicate; - private final PacketControl packet; - - public ControlTriggerOnKeyPress( - String id, - Predicate predicate - ) { - super(id); - this.predicate = predicate; - this.packet = new PacketControl( - NamespacedUtil.getId(getNamespace(), "ControlKeyPress" + getName()), - ControlDataRegistry.getInstance().get(getId()) - ); - } - - @Override - public PacketControl onInputEvent(InputEvent event) { - if (!(event instanceof KeyEvent)) return null; - - KeyEvent keyEvent = (KeyEvent) event; - - if (!keyEvent.isPress()) return null; - if (!predicate.test(keyEvent)) return null; - - return packet; - } - -} diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggers.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggers.java new file mode 100644 index 0000000..5930ee6 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggers.java @@ -0,0 +1,176 @@ +package ru.windcorp.progressia.client.comms.controls; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Predicate; + +import ru.windcorp.progressia.client.graphics.input.InputEvent; +import ru.windcorp.progressia.common.comms.controls.ControlData; + +public class ControlTriggers { + + public static ControlTriggerInputBased of( + String id, + BiConsumer dataWriter, + Predicate predicate + ) { + return new ControlTriggerLambda(id, predicate, dataWriter); + } + + public static ControlTriggerInputBased of( + String id, + Consumer dataWriter, + Predicate predicate + ) { + return of( + id, + (input, control) -> dataWriter.accept(control), + predicate + ); + } + + public static ControlTriggerInputBased of( + String id, + Predicate predicate + ) { + return of( + id, + (input, control) -> {}, + predicate + ); + } + + @SafeVarargs + public static ControlTriggerInputBased of( + String id, + Class inputType, + BiConsumer dataWriter, + Predicate... predicates + ) { + return of( + id, + createCheckedDataWriter(inputType, dataWriter), + createCheckedCompoundPredicate(inputType, predicates) + ); + } + + @SafeVarargs + public static ControlTriggerInputBased of( + String id, + Class inputType, + Consumer dataWriter, + Predicate... predicates + ) { + return of( + id, + inputType, + (input, control) -> dataWriter.accept(control), + predicates + ); + } + + @SafeVarargs + public static ControlTriggerInputBased of( + String id, + Class inputType, + Predicate... predicates + ) { + return of( + id, + (input, control) -> {}, + createCheckedCompoundPredicate(inputType, predicates) + ); + } + + @SafeVarargs + public static ControlTriggerInputBased of( + String id, + BiConsumer dataWriter, + Predicate... predicates + ) { + return of( + id, + InputEvent.class, + dataWriter, + predicates + ); + } + + @SafeVarargs + public static ControlTriggerInputBased of( + String id, + Consumer dataWriter, + Predicate... predicates + ) { + return of( + id, + (input, control) -> dataWriter.accept(control), + predicates + ); + } + + @SafeVarargs + public static ControlTriggerInputBased of( + String id, + Predicate... predicates + ) { + return of( + id, + InputEvent.class, + (input, control) -> {}, + predicates + ); + } + + private static + + BiConsumer + createCheckedDataWriter( + Class inputType, + BiConsumer dataWriter + ) { + return (inputEvent, control) -> dataWriter.accept(inputType.cast(inputEvent), control); + } + + private static + + Predicate + createCheckedCompoundPredicate( + Class inputType, + Predicate[] predicates + ) { + return new CompoundCastPredicate<>(inputType, predicates); + } + + private static class CompoundCastPredicate implements Predicate { + + private final Class inputType; + private final Predicate[] predicates; + + public CompoundCastPredicate(Class inputType, Predicate[] predicates) { + this.inputType = inputType; + this.predicates = predicates; + } + + @Override + public boolean test(InputEvent inputEvent) { + if (!inputType.isInstance(inputEvent)) { + return false; + } + + I castEvent = inputType.cast(inputEvent); + + for (Predicate predicate : predicates) { + if (!predicate.test(castEvent)) { + return false; + } + } + + return true; + } + + } + + private ControlTriggers() {} + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyMatcher.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyMatcher.java index 4943b96..df6c7a8 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyMatcher.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyMatcher.java @@ -17,46 +17,24 @@ *******************************************************************************/ package ru.windcorp.progressia.client.graphics.input; -import gnu.trove.set.TIntSet; -import ru.windcorp.progressia.client.graphics.backend.InputTracker; +import java.util.function.Predicate; + +import org.lwjgl.glfw.GLFW; public class KeyMatcher { - + private final int key; - private final int[] additionalKeys; private final int mods; - public KeyMatcher(int key, int[] additionalKeys, int mods) { + protected KeyMatcher(int key, int mods) { this.key = key; - this.additionalKeys = additionalKeys; this.mods = mods; } - - public KeyMatcher(KeyEvent template, int... additionalKeys) { - this(template.getKey(), additionalKeys, template.getMods()); - } - - public static KeyMatcher createKeyMatcher(KeyEvent template) { - return new KeyMatcher( - template, - InputTracker.getPressedKeys().toArray() - ); - } public boolean matches(KeyEvent event) { if (!event.isPress()) return false; if (event.getKey() != getKey()) return false; - if (event.getMods() != getMods()) return false; - - TIntSet pressedKeys = InputTracker.getPressedKeys(); - - if (pressedKeys.size() != additionalKeys.length) return false; - - for (int additionalKey : additionalKeys) { - if (!pressedKeys.contains(additionalKey)) { - return false; - } - } + if ((event.getMods() & getMods()) != getMods()) return false; return true; } @@ -65,12 +43,52 @@ public class KeyMatcher { return key; } - public int[] getAdditionalKeys() { - return additionalKeys; - } - public int getMods() { return mods; } + + public static KeyMatcher.Builder of(int key) { + return new KeyMatcher.Builder(key); + } + + public static class Builder { + + private final int key; + private int mods = 0; + + public Builder(int key) { + this.key = key; + } + + public Builder with(int modifier) { + this.mods += modifier; + return this; + } + + public Builder withShift() { + return with(GLFW.GLFW_MOD_SHIFT); + } + + public Builder withCtrl() { + return with(GLFW.GLFW_MOD_CONTROL); + } + + public Builder withAlt() { + return with(GLFW.GLFW_MOD_ALT); + } + + public Builder withSuper() { + return with(GLFW.GLFW_MOD_SUPER); + } + + public KeyMatcher build() { + return new KeyMatcher(key, mods); + } + + public Predicate matcher() { + return build()::matches; + } + + } } diff --git a/src/main/java/ru/windcorp/progressia/common/collision/CollisionPathComputer.java b/src/main/java/ru/windcorp/progressia/common/collision/CollisionPathComputer.java index eda8e47..dd752dd 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/CollisionPathComputer.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/CollisionPathComputer.java @@ -10,6 +10,8 @@ import static java.lang.Math.*; public class CollisionPathComputer { + private static final float PADDING = 0.5f; + public static void forEveryBlockInCollisionPath( Collideable coll, float maxTime, @@ -52,18 +54,18 @@ public class CollisionPathComputer { Vec3i pos = Vectors.grab3i(); for ( - pos.x = (int) floor(origin.x + min(0, size.x) + min(0, displacement.x)); - pos.x <= (int) ceil(origin.x + max(0, size.x) + max(0, displacement.x)); + pos.x = (int) floor(origin.x + min(0, size.x) + min(0, displacement.x) - PADDING); + pos.x <= (int) ceil(origin.x + max(0, size.x) + max(0, displacement.x) + PADDING); pos.x += 1 ) { for ( - pos.y = (int) floor(origin.y + min(0, size.y) + min(0, displacement.y)); - pos.y <= (int) ceil(origin.y + max(0, size.y) + max(0, displacement.y)); + pos.y = (int) floor(origin.y + min(0, size.y) + min(0, displacement.y) - PADDING); + pos.y <= (int) ceil(origin.y + max(0, size.y) + max(0, displacement.y) + PADDING); pos.y += 1 ) { for ( - pos.z = (int) floor(origin.z + min(0, size.z) + min(0, displacement.z)); - pos.z <= (int) ceil(origin.z + max(0, size.z) + max(0, displacement.z)); + pos.z = (int) floor(origin.z + min(0, size.z) + min(0, displacement.z) - PADDING); + pos.z <= (int) ceil(origin.z + max(0, size.z) + max(0, displacement.z) + PADDING); pos.z += 1 ) { action.accept(pos); diff --git a/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlDataRegistry.java b/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlDataRegistry.java index eb787b3..5e38b90 100644 --- a/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlDataRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlDataRegistry.java @@ -1,8 +1,8 @@ package ru.windcorp.progressia.common.comms.controls; -import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; +import ru.windcorp.progressia.common.util.namespaces.NamespacedFactoryRegistry; -public class ControlDataRegistry extends NamespacedInstanceRegistry { +public class ControlDataRegistry extends NamespacedFactoryRegistry { private static final ControlDataRegistry INSTANCE = new ControlDataRegistry(); diff --git a/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogic.java b/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogic.java index ae708a2..28aca40 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogic.java @@ -6,6 +6,15 @@ import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.comms.Client; public abstract class ControlLogic extends Namespaced { + + @FunctionalInterface + public static interface Lambda { + void apply( + Server server, + PacketControl packet, + Client client + ); + } public ControlLogic(String id) { super(id); @@ -16,5 +25,14 @@ public abstract class ControlLogic extends Namespaced { PacketControl packet, Client client ); + + public static ControlLogic of(String id, Lambda logic) { + return new ControlLogic(id) { + @Override + public void apply(Server server, PacketControl packet, Client client) { + logic.apply(server, packet, client); + } + }; + } } diff --git a/src/main/java/ru/windcorp/progressia/test/ControlBreakBlockData.java b/src/main/java/ru/windcorp/progressia/test/ControlBreakBlockData.java new file mode 100644 index 0000000..23761e5 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/ControlBreakBlockData.java @@ -0,0 +1,22 @@ +package ru.windcorp.progressia.test; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.comms.controls.ControlData; + +public class ControlBreakBlockData extends ControlData { + + private final Vec3i blockInWorld = new Vec3i(); + + public ControlBreakBlockData(String id) { + super(id); + } + + public Vec3i getBlockInWorld() { + return blockInWorld; + } + + public void setBlockInWorld(Vec3i blockInWorld) { + this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index ffe6d1b..57d2a72 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -8,8 +8,11 @@ import java.util.function.Consumer; import org.lwjgl.glfw.GLFW; import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.client.ClientState; import ru.windcorp.progressia.client.comms.controls.*; +import ru.windcorp.progressia.client.graphics.input.KeyEvent; import ru.windcorp.progressia.client.graphics.input.KeyMatcher; +import ru.windcorp.progressia.client.graphics.world.LocalPlayer; import ru.windcorp.progressia.client.world.block.*; import ru.windcorp.progressia.client.world.entity.*; import ru.windcorp.progressia.client.world.tile.*; @@ -21,8 +24,6 @@ import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.block.*; import ru.windcorp.progressia.common.world.entity.*; import ru.windcorp.progressia.common.world.tile.*; -import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.comms.Client; import ru.windcorp.progressia.server.comms.controls.*; import ru.windcorp.progressia.server.world.block.*; import ru.windcorp.progressia.server.world.entity.*; @@ -88,7 +89,7 @@ public class TestContent { private static void registerEntities() { float scale = 1.8f / 8; - registerEntityData("Test:Player", e -> e.setCollisionModel(new AABB(0, 0, 4*scale, 0.75f, 0.75f, 1.8f))); + registerEntityData("Test:Player", e -> e.setCollisionModel(new AABB(0, 0, 4*scale, 0.8f, 0.8f, 1.8f))); register(new TestEntityRenderHuman("Test:Player")); register(new EntityLogic("Test:Player")); @@ -98,25 +99,43 @@ public class TestContent { } private static void regsiterControls() { - ControlDataRegistry.getInstance().register(new ControlData("Test:Switch000")); - ControlTriggerRegistry.getInstance().register(new ControlTriggerOnKeyPress("Test:Switch000", new KeyMatcher(GLFW.GLFW_KEY_H, new int[0], 0)::matches)); - ControlLogicRegistry.getInstance().register(new ControlLogic("Test:Switch000") { - @Override - public void apply(Server server, PacketControl packet, Client client) { - Vec3i z000 = new Vec3i(0, 0, 0); - - ChunkData data = server.getWorld().getChunk(z000).getData(); - - BlockData block; - if (data.getBlock(z000).getId().equals("Test:Stone")) { - block = BlockDataRegistry.getInstance().get("Test:Glass"); - } else { - block = BlockDataRegistry.getInstance().get("Test:Stone"); - } - - server.getAdHocChanger().setBlock(z000, block); + ControlDataRegistry data = ControlDataRegistry.getInstance(); + ControlTriggerRegistry triggers = ControlTriggerRegistry.getInstance(); + ControlLogicRegistry logic = ControlLogicRegistry.getInstance(); + + data.register("Test:Switch000", ControlData::new); + triggers.register(ControlTriggers.of( + "Test:Switch000", + KeyEvent.class, + KeyMatcher.of(GLFW.GLFW_KEY_H).matcher() + )); + logic.register(ControlLogic.of("Test:Switch000", (server, packet, client) -> { + Vec3i z000 = new Vec3i(0, 0, 0); + + ChunkData chunk = server.getWorld().getChunk(z000).getData(); + + BlockData block; + if (chunk.getBlock(z000).getId().equals("Test:Stone")) { + block = BlockDataRegistry.getInstance().get("Test:Glass"); + } else { + block = BlockDataRegistry.getInstance().get("Test:Stone"); } - }); + + server.getAdHocChanger().setBlock(z000, block); + })); + + data.register("Test:BreakBlock", ControlBreakBlockData::new); + triggers.register(ControlTriggers.of( + "Test:BreakBlock", + KeyEvent.class, + TestContent::onBlockBreakTrigger, + KeyMatcher.of(GLFW.GLFW_MOUSE_BUTTON_LEFT).matcher(), + i -> getLookingAt() != null + )); + logic.register(ControlLogic.of("Test:BreakBlock", (server, packet, client) -> { + Vec3i blockInWorld = ((ControlBreakBlockData) packet.getControl()).getBlockInWorld(); + server.getAdHocChanger().setBlock(blockInWorld, BlockDataRegistry.getInstance().get("Test:Air")); + })); } private static void register(BlockData x) { @@ -171,5 +190,19 @@ public class TestContent { private static void register(EntityLogic x) { EntityLogicRegistry.getInstance().register(x); } + + private static Vec3i getLookingAt() { + ru.windcorp.progressia.client.Client client = ClientState.getInstance(); + if (client == null) return null; + + LocalPlayer player = client.getLocalPlayer(); + if (player == null) return null; + + return player.getLookingAt(); + } + + private static void onBlockBreakTrigger(ControlData control) { + ((ControlBreakBlockData) control).setBlockInWorld(getLookingAt()); + } }