diff --git a/core/src/main/java/nl/andrewl/aos_core/Directions.java b/core/src/main/java/nl/andrewl/aos_core/Directions.java new file mode 100644 index 0000000..f5efcd7 --- /dev/null +++ b/core/src/main/java/nl/andrewl/aos_core/Directions.java @@ -0,0 +1,13 @@ +package nl.andrewl.aos_core; + +import org.joml.Vector3i; +import org.joml.Vector3ic; + +public class Directions { + public static final Vector3ic UP = new Vector3i(0, 1, 0); + public static final Vector3ic DOWN = new Vector3i(0, -1, 0); + public static final Vector3ic NEGATIVE_X = new Vector3i(-1, 0, 0); + public static final Vector3ic POSITIVE_X = new Vector3i(1, 0, 0); + public static final Vector3ic NEGATIVE_Z = new Vector3i(0, 0, -1); + public static final Vector3ic POSITIVE_Z = new Vector3i(0, 0, 1); +} diff --git a/core/src/main/java/nl/andrewl/aos_core/model/Hit.java b/core/src/main/java/nl/andrewl/aos_core/model/Hit.java new file mode 100644 index 0000000..5b2201a --- /dev/null +++ b/core/src/main/java/nl/andrewl/aos_core/model/Hit.java @@ -0,0 +1,13 @@ +package nl.andrewl.aos_core.model; + +import org.joml.Vector3i; +import org.joml.Vector3ic; + +/** + * Represents the point at which a ray hits a block, often used when casting a + * ray from a player's location to see if they break or place a block. + */ +public record Hit ( + Vector3i pos, + Vector3ic norm +) {} diff --git a/core/src/main/java/nl/andrewl/aos_core/model/World.java b/core/src/main/java/nl/andrewl/aos_core/model/World.java index a3d5ca4..6cec009 100644 --- a/core/src/main/java/nl/andrewl/aos_core/model/World.java +++ b/core/src/main/java/nl/andrewl/aos_core/model/World.java @@ -1,5 +1,6 @@ package nl.andrewl.aos_core.model; +import nl.andrewl.aos_core.Directions; import org.joml.Math; import org.joml.Vector3f; import org.joml.Vector3i; @@ -95,7 +96,7 @@ public class World { * @return The location of the block that is looked at, or null if none * could be found. */ - public Vector3i getLookingAtPos(Vector3f eyePos, Vector3f eyeDir, float limit) { + public Hit getLookingAtPos(Vector3f eyePos, Vector3f eyeDir, float limit) { if (eyeDir.lengthSquared() == 0 || limit <= 0) return null; Vector3f pos = new Vector3f(eyePos); Vector3f movement = new Vector3f(); // Pre-allocate this vector. @@ -120,11 +121,22 @@ public class World { movement.set(eyeDir).mul(minFactor); pos.add(movement); if (getBlockAt(pos) > 0) { - return new Vector3i( + Vector3f prevPos = new Vector3f(pos).sub(movement); + Vector3i hitPos = new Vector3i( (int) Math.floor(pos.x), (int) Math.floor(pos.y), (int) Math.floor(pos.z) ); + Vector3ic hitNorm = null; + + if (prevPos.y > hitPos.y + 1) hitNorm = Directions.UP; + else if (prevPos.y < hitPos.y) hitNorm = Directions.DOWN; + else if (prevPos.x > hitPos.x + 1) hitNorm = Directions.POSITIVE_X; + else if (prevPos.x < hitPos.x) hitNorm = Directions.NEGATIVE_X; + else if (prevPos.z > hitPos.z + 1) hitNorm = Directions.POSITIVE_Z; + else if (prevPos.z < hitPos.z) hitNorm = Directions.NEGATIVE_Z; + + return new Hit(hitPos, hitNorm); } } return null; diff --git a/core/src/main/java/nl/andrewl/aos_core/net/udp/ChunkUpdateMessage.java b/core/src/main/java/nl/andrewl/aos_core/net/udp/ChunkUpdateMessage.java index e5b4750..2796b7c 100644 --- a/core/src/main/java/nl/andrewl/aos_core/net/udp/ChunkUpdateMessage.java +++ b/core/src/main/java/nl/andrewl/aos_core/net/udp/ChunkUpdateMessage.java @@ -1,6 +1,8 @@ package nl.andrewl.aos_core.net.udp; +import nl.andrewl.aos_core.model.World; import nl.andrewl.record_net.Message; +import org.joml.Vector3i; /** * A message that's sent to clients when a block in a chunk is updated. @@ -16,4 +18,14 @@ public record ChunkUpdateMessage( int cx, int cy, int cz, int lx, int ly, int lz, byte newBlock -) implements Message {} +) implements Message { + public static ChunkUpdateMessage fromWorld(Vector3i worldPos, World world) { + Vector3i chunkPos = World.getChunkPosAt(worldPos); + Vector3i localPos = World.getLocalPosAt(worldPos); + return new ChunkUpdateMessage( + chunkPos.x, chunkPos.y, chunkPos.z, + localPos.x, localPos.y, localPos.z, + world.getBlockAt(worldPos.x, worldPos.y, worldPos.z) + ); + } +} diff --git a/server/src/main/java/nl/andrewl/aos2_server/ServerPlayer.java b/server/src/main/java/nl/andrewl/aos2_server/ServerPlayer.java index 60c0551..1e1e753 100644 --- a/server/src/main/java/nl/andrewl/aos2_server/ServerPlayer.java +++ b/server/src/main/java/nl/andrewl/aos2_server/ServerPlayer.java @@ -1,6 +1,5 @@ package nl.andrewl.aos2_server; -import nl.andrewl.aos_core.model.Chunk; import nl.andrewl.aos_core.model.Player; import nl.andrewl.aos_core.model.World; import nl.andrewl.aos_core.net.udp.ChunkUpdateMessage; @@ -63,18 +62,25 @@ public class ServerPlayer extends Player { if (lastInputState.hitting() && now - lastBlockRemovedAt > BLOCK_REMOVE_COOLDOWN) { Vector3f eyePos = new Vector3f(position); eyePos.y += getEyeHeight(); - Vector3i targetPos = world.getLookingAtPos(eyePos, viewVector, 10); - System.out.println(targetPos); - if (targetPos != null) { - Vector3i chunkPos = World.getChunkPosAt(targetPos); - Vector3i localPos = World.getLocalPosAt(targetPos); - world.setBlockAt(targetPos.x, targetPos.y, targetPos.z, (byte) 0); + var hit = world.getLookingAtPos(eyePos, viewVector, 10); + System.out.println(hit); + if (hit != null) { + world.setBlockAt(hit.pos().x, hit.pos().y, hit.pos().z, (byte) 0); lastBlockRemovedAt = now; - server.getPlayerManager().broadcastUdpMessage(new ChunkUpdateMessage( - chunkPos.x, chunkPos.y, chunkPos.z, - localPos.x, localPos.y, localPos.z, - (byte) 0 - )); + server.getPlayerManager().broadcastUdpMessage(ChunkUpdateMessage.fromWorld(hit.pos(), world)); + } + } + if (lastInputState.interacting() && now - lastBlockRemovedAt > BLOCK_REMOVE_COOLDOWN) { + Vector3f eyePos = new Vector3f(position); + eyePos.y += getEyeHeight(); + var hit = world.getLookingAtPos(eyePos, viewVector, 10); + System.out.println(hit); + if (hit != null) { + Vector3i placePos = new Vector3i(hit.pos()); + placePos.add(hit.norm()); + world.setBlockAt(placePos.x, placePos.y, placePos.z, (byte) 1); + lastBlockRemovedAt = now; + server.getPlayerManager().broadcastUdpMessage(ChunkUpdateMessage.fromWorld(placePos, world)); } } tickMovement(dt, world);