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
This commit is contained in:
parent
a7eb90865f
commit
7f381c7a1f
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
@ -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<ChunkData> getChunks() {
|
||||
return chunks;
|
||||
}
|
||||
|
@ -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<BlockFace> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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"));
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user