From 7f381c7a1fe7b8bdbc067aa2afa744f40aaf33e8 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 20 Nov 2020 11:50:24 +0300 Subject: [PATCH] Updated block selection display and added block placing - Packaged everything related to block selection into Selection class - Selection box is a bit less obnoxious - Added the ability to place Test:Stone blocks - This is technically a Minecraft clone now. I don't know how to feel about this tbh --- .../client/graphics/world/LayerWorld.java | 45 ++++++++++-- .../client/graphics/world/LocalPlayer.java | 44 ++---------- .../client/graphics/world/Selection.java | 72 +++++++++++++++++++ .../progressia/common/world/BlockRay.java | 35 +++++++-- .../progressia/common/world/WorldData.java | 11 +++ .../common/world/block/BlockFace.java | 25 +++++-- .../test/ControlPlaceBlockData.java | 22 ++++++ .../windcorp/progressia/test/TestContent.java | 47 +++++++++--- 8 files changed, 237 insertions(+), 64 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java create mode 100644 src/main/java/ru/windcorp/progressia/test/ControlPlaceBlockData.java diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java index 2e4b6be..1533246 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java @@ -20,6 +20,8 @@ package ru.windcorp.progressia.client.graphics.world; import java.util.ArrayList; import java.util.List; +import glm.mat._4.Mat4; +import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.Client; import ru.windcorp.progressia.client.ClientState; @@ -28,9 +30,15 @@ import ru.windcorp.progressia.client.graphics.Layer; import ru.windcorp.progressia.client.graphics.backend.FaceCulling; import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; import ru.windcorp.progressia.client.graphics.input.bus.Input; +import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; +import ru.windcorp.progressia.client.graphics.model.Shapes.PppBuilder; +import ru.windcorp.progressia.client.graphics.model.StaticModel; +import ru.windcorp.progressia.client.graphics.texture.Texture; import ru.windcorp.progressia.common.Units; import ru.windcorp.progressia.common.collision.Collideable; import ru.windcorp.progressia.common.collision.colliders.Collider; +import ru.windcorp.progressia.common.util.FloatMathUtils; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.test.CollisionModelRenderer; import ru.windcorp.progressia.test.TestPlayerControls; @@ -127,19 +135,48 @@ public class LayerWorld extends Layer { tmp_colliderWorkspace ); } + + private static final Renderable SELECTION_BOX = tmp_createSelectionBox(); private void tmp_drawSelectionBox() { LocalPlayer player = client.getLocalPlayer(); if (player == null) return; - Vec3i lookingAt = player.getLookingAt(); - if (lookingAt == null) return; + Vec3i selection = player.getSelection().getBlock(); + if (selection == null) return; - helper.pushTransform().translate(lookingAt.x, lookingAt.y, lookingAt.z).scale(1.1f); - CollisionModelRenderer.renderCollisionModel(client.getWorld().getData().getCollisionModelOfBlock(lookingAt), helper); + helper.pushTransform().translate(selection.x, selection.y, selection.z); + SELECTION_BOX.render(helper); helper.popTransform(); } + private static Renderable tmp_createSelectionBox() { + StaticModel.Builder b = StaticModel.builder(); + ShapeRenderProgram p = WorldRenderProgram.getDefault(); + + final float f = 1e-2f; + final float scale = 1 - f/2; + final Vec3 color = new Vec3(1, 1, 1).mul(0); + + for (float phi = 0; phi < 2*FloatMathUtils.PI_F; phi += FloatMathUtils.PI_F/2) { + Mat4 rot = new Mat4().identity().rotateZ(phi).scale(scale); + + b.addPart(new PppBuilder(p, (Texture) null).setOrigin( + new Vec3(-f - 0.5f, -f - 0.5f, -f - 0.5f) + ).setSize(f, f, 2*f + 1).setColorMultiplier(color).create(), rot); + + b.addPart(new PppBuilder(p, (Texture) null).setOrigin( + new Vec3(-f - 0.5f, - 0.5f, -f - 0.5f) + ).setSize(f, 1, f).setColorMultiplier(color).create(), rot); + + b.addPart(new PppBuilder(p, (Texture) null).setOrigin( + new Vec3(-f - 0.5f, - 0.5f, + 0.5f) + ).setSize(f, 1, f).setColorMultiplier(color).create(), rot); + } + + return new StaticModel(b); + } + private void tmp_applyFriction(EntityData entity) { final float frictionCoeff = 1 - 1e-5f; entity.getVelocity().mul(frictionCoeff); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java index 5df2b84..9179bc4 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java @@ -1,60 +1,24 @@ package ru.windcorp.progressia.client.graphics.world; -import glm.vec._3.Vec3; -import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.world.WorldRender; import ru.windcorp.progressia.client.world.entity.EntityRenderable; -import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.BlockRay; import ru.windcorp.progressia.common.world.Player; import ru.windcorp.progressia.common.world.entity.EntityData; public class LocalPlayer extends Player { - private Vec3i lookingAt = new Vec3i(); - private boolean isLookingAtBlock = false; - - private BlockRay lookingAtRay = new BlockRay(); + private final Selection selection = new Selection(); public LocalPlayer(EntityData entity) { super(entity); } - public Vec3i getLookingAt() { - return isLookingAtBlock ? lookingAt : null; + public Selection getSelection() { + return selection; } public void update(WorldRender world) { - updateLookingAt(world); - } - - private void updateLookingAt(WorldRender world) { - Vec3 direction = Vectors.grab3(); - Vec3 start = Vectors.grab3(); - - BlockRay ray = lookingAtRay; - EntityData player = getEntity(); - - player.getLookingAtVector(direction); - world.getEntityRenderable(player).getViewPoint(start); - start.add(player.getPosition()); - - isLookingAtBlock = false; - - for (ray.start(start, direction); ray.getDistance() < 6; ray.next()) { - Vec3i blockInWorld = ray.current(); - - if (world.getData().getCollisionModelOfBlock(blockInWorld) != null) { - isLookingAtBlock = true; - lookingAt.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); - break; - } - } - - ray.end(); - - Vectors.release(direction); - Vectors.release(start); + getSelection().update(world, getEntity()); } public EntityRenderable getRenderable(WorldRender world) { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java new file mode 100644 index 0000000..3627e3c --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java @@ -0,0 +1,72 @@ +package ru.windcorp.progressia.client.graphics.world; + +import glm.vec._2.Vec2; +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.client.world.WorldRender; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.BlockRay; +import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.entity.EntityData; + +public class Selection { + + private final Vec3i block = new Vec3i(); + private BlockFace surface = null; + private final Vec2 pointOnSurface = new Vec2(0.5f, 0.5f); + private final Vec3 point = new Vec3(); + + private boolean exists = false; + + private BlockRay ray = new BlockRay(); + + public void update(WorldRender world, EntityData player) { + Vec3 direction = Vectors.grab3(); + Vec3 start = Vectors.grab3(); + + player.getLookingAtVector(direction); + world.getEntityRenderable(player).getViewPoint(start); + start.add(player.getPosition()); + + exists = false; + + for (ray.start(start, direction); ray.getDistance() < 6; ray.next()) { + Vec3i blockInWorld = ray.current(); + + if (world.getData().getCollisionModelOfBlock(blockInWorld) != null) { + exists = true; + block.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); + ray.getPoint(point); + surface = ray.getCurrentFace(); + // TODO selectedPointOnSurface + break; + } + } + + ray.end(); + + Vectors.release(direction); + Vectors.release(start); + } + + public Vec3i getBlock() { + return exists ? block : null; + } + + public Vec3 getPoint() { + return exists ? point : null; + } + + public BlockFace getSurface() { + return exists ? surface : null; + } + + public Vec2 getPointOnSurface() { + return exists ? pointOnSurface : null; + } + + public boolean exists() { + return exists; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java b/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java index 158a1fc..ab4dbf7 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java +++ b/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java @@ -4,6 +4,7 @@ import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.VectorUtil.Axis; +import ru.windcorp.progressia.common.world.block.BlockFace; import static java.lang.Math.*; @@ -15,6 +16,7 @@ public class BlockRay { private float distance; private final Vec3i block = new Vec3i(); + private BlockFace currentFace = null; private boolean isValid = false; @@ -65,11 +67,8 @@ public class BlockRay { // position.(axis) = round(position.(axis)) VectorUtil.set(position, axis, round(VectorUtil.get(position, axis))); - return block; - } - - public Vec3i current() { - checkState(); + this.currentFace = computeCurrentFace(axis, (int) signum(VectorUtil.get(direction, axis))); + return block; } @@ -87,6 +86,32 @@ public class BlockRay { return (edge - c) / dir; } + private BlockFace computeCurrentFace(Axis axis, int sign) { + if (sign == 0) throw new IllegalStateException("sign is zero"); + + switch (axis) { + case X: return sign > 0 ? BlockFace.SOUTH : BlockFace.NORTH; + case Y: return sign > 0 ? BlockFace.EAST : BlockFace.WEST; + default: + case Z: return sign > 0 ? BlockFace.BOTTOM : BlockFace.TOP; + } + } + + public Vec3i current() { + checkState(); + return block; + } + + public Vec3 getPoint(Vec3 output) { + output.set(position); + output.add(0.5f); // Make sure we're in the block-center coordinate system + return output; + } + + public BlockFace getCurrentFace() { + return currentFace; + } + public float getDistance() { checkState(); return distance; diff --git a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java index 6584884..a8a4966 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java @@ -88,6 +88,17 @@ public class WorldData { return result; } + public BlockData getBlock(Vec3i blockInWorld) { + ChunkData chunk = getChunkByBlock(blockInWorld); + if (chunk == null) return null; + + Vec3i blockInChunk = Vectors.grab3i(); + Coordinates.convertInWorldToInChunk(blockInWorld, blockInChunk); + BlockData result = chunk.getBlock(blockInChunk); + + return result; + } + public Collection getChunks() { return chunks; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/BlockFace.java b/src/main/java/ru/windcorp/progressia/common/world/block/BlockFace.java index f33f8d7..461429e 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/BlockFace.java +++ b/src/main/java/ru/windcorp/progressia/common/world/block/BlockFace.java @@ -25,12 +25,12 @@ import glm.vec._3.i.Vec3i; public final class BlockFace extends BlockRelation { public static final BlockFace - TOP = new BlockFace( 0, 0, +1, true), - BOTTOM = new BlockFace( 0, 0, -1, false), - NORTH = new BlockFace(+1, 0, 0, true), - SOUTH = new BlockFace(-1, 0, 0, false), - WEST = new BlockFace( 0, +1, 0, false), - EAST = new BlockFace( 0, -1, 0, true); + TOP = new BlockFace( 0, 0, +1, true, "TOP"), + BOTTOM = new BlockFace( 0, 0, -1, false, "BOTTOM"), + NORTH = new BlockFace(+1, 0, 0, true, "NORTH"), + SOUTH = new BlockFace(-1, 0, 0, false, "SOUTH"), + WEST = new BlockFace( 0, +1, 0, false, "WEST"), + EAST = new BlockFace( 0, -1, 0, true, "EAST"); private static final ImmutableList ALL_FACES = ImmutableList.of(TOP, BOTTOM, NORTH, SOUTH, WEST, EAST); @@ -77,15 +77,21 @@ public final class BlockFace extends BlockRelation { private static int nextId = 0; private final int id; + private final String name; private BlockFace counterFace; private final boolean isPrimary; - private BlockFace(int x, int y, int z, boolean isPrimary) { + private BlockFace(int x, int y, int z, boolean isPrimary, String name) { super(x, y, z); this.id = nextId++; this.isPrimary = isPrimary; + this.name = name; } + public String getName() { + return name; + } + public boolean isPrimary() { return isPrimary; } @@ -132,5 +138,10 @@ public final class BlockFace extends BlockRelation { public int getManhattanDistance() { return 1; } + + @Override + public String toString() { + return getName(); + } } diff --git a/src/main/java/ru/windcorp/progressia/test/ControlPlaceBlockData.java b/src/main/java/ru/windcorp/progressia/test/ControlPlaceBlockData.java new file mode 100644 index 0000000..82dc80b --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/ControlPlaceBlockData.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 ControlPlaceBlockData extends ControlData { + + private final Vec3i blockInWorld = new Vec3i(); + + public ControlPlaceBlockData(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 57d2a72..a7a5027 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -13,6 +13,7 @@ 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.graphics.world.Selection; import ru.windcorp.progressia.client.world.block.*; import ru.windcorp.progressia.client.world.entity.*; import ru.windcorp.progressia.client.world.tile.*; @@ -20,10 +21,12 @@ import ru.windcorp.progressia.common.collision.AABB; import ru.windcorp.progressia.common.collision.CollisionModel; import ru.windcorp.progressia.common.comms.controls.*; import ru.windcorp.progressia.common.state.StatefulObjectRegistry.Factory; +import ru.windcorp.progressia.common.util.Vectors; 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.controls.*; import ru.windcorp.progressia.server.world.block.*; import ru.windcorp.progressia.server.world.entity.*; @@ -130,12 +133,19 @@ public class TestContent { KeyEvent.class, TestContent::onBlockBreakTrigger, KeyMatcher.of(GLFW.GLFW_MOUSE_BUTTON_LEFT).matcher(), - i -> getLookingAt() != null + i -> getSelection().exists() )); - logic.register(ControlLogic.of("Test:BreakBlock", (server, packet, client) -> { - Vec3i blockInWorld = ((ControlBreakBlockData) packet.getControl()).getBlockInWorld(); - server.getAdHocChanger().setBlock(blockInWorld, BlockDataRegistry.getInstance().get("Test:Air")); - })); + logic.register(ControlLogic.of("Test:BreakBlock", TestContent::onBlockBreakReceived)); + + data.register("Test:PlaceBlock", ControlPlaceBlockData::new); + triggers.register(ControlTriggers.of( + "Test:PlaceBlock", + KeyEvent.class, + TestContent::onBlockPlaceTrigger, + KeyMatcher.of(GLFW.GLFW_MOUSE_BUTTON_RIGHT).matcher(), + i -> getSelection().exists() + )); + logic.register(ControlLogic.of("Test:PlaceBlock", TestContent::onBlockPlaceReceived)); } private static void register(BlockData x) { @@ -191,18 +201,39 @@ public class TestContent { EntityLogicRegistry.getInstance().register(x); } - private static Vec3i getLookingAt() { + private static Selection getSelection() { 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(); + return player.getSelection(); } private static void onBlockBreakTrigger(ControlData control) { - ((ControlBreakBlockData) control).setBlockInWorld(getLookingAt()); + ((ControlBreakBlockData) control).setBlockInWorld(getSelection().getBlock()); + } + + private static void onBlockBreakReceived(Server server, PacketControl packet, ru.windcorp.progressia.server.comms.Client client) { + Vec3i blockInWorld = ((ControlBreakBlockData) packet.getControl()).getBlockInWorld(); + server.getAdHocChanger().setBlock(blockInWorld, BlockDataRegistry.getInstance().get("Test:Air")); + } + + private static void onBlockPlaceTrigger(ControlData control) { + Vec3i blockInWorld = Vectors.grab3i(); + Vec3i selectedBlock = getSelection().getBlock(); + + blockInWorld.set(selectedBlock.x, selectedBlock.y, selectedBlock.z).add(getSelection().getSurface().getVector()); + + ((ControlPlaceBlockData) control).setBlockInWorld(blockInWorld); + Vectors.release(blockInWorld); + } + + private static void onBlockPlaceReceived(Server server, PacketControl packet, ru.windcorp.progressia.server.comms.Client client) { + Vec3i blockInWorld = ((ControlPlaceBlockData) packet.getControl()).getBlockInWorld(); + if (server.getWorld().getData().getChunkByBlock(blockInWorld) == null) return; + server.getAdHocChanger().setBlock(blockInWorld, BlockDataRegistry.getInstance().get("Test:Stone")); } }