diff --git a/client/src/main/java/nl/andrewl/aos2_client/Client.java b/client/src/main/java/nl/andrewl/aos2_client/Client.java index 96fce21..c1a9bf6 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/Client.java +++ b/client/src/main/java/nl/andrewl/aos2_client/Client.java @@ -4,8 +4,10 @@ import nl.andrewl.aos2_client.control.PlayerInputKeyCallback; import nl.andrewl.aos2_client.control.PlayerViewCursorCallback; import nl.andrewl.aos2_client.render.GameRenderer; import nl.andrewl.aos_core.model.Chunk; +import nl.andrewl.aos_core.model.ColorPalette; import nl.andrewl.aos_core.model.World; import nl.andrewl.aos_core.net.ChunkDataMessage; +import nl.andrewl.aos_core.net.WorldInfoMessage; import nl.andrewl.aos_core.net.udp.PlayerUpdateMessage; import nl.andrewl.record_net.Message; import org.slf4j.Logger; @@ -74,6 +76,9 @@ public class Client implements Runnable { } public void onMessageReceived(Message msg) { + if (msg instanceof WorldInfoMessage worldInfo) { + world.setPalette(ColorPalette.fromArray(worldInfo.palette())); + } if (msg instanceof ChunkDataMessage chunkDataMessage) { Chunk chunk = chunkDataMessage.toChunk(); world.addChunk(chunk); @@ -81,7 +86,8 @@ public class Client implements Runnable { } if (msg instanceof PlayerUpdateMessage playerUpdate) { if (playerUpdate.clientId() == clientId) { - gameRenderer.getCamera().setPosition(playerUpdate.px(), playerUpdate.py() + 1.8f, playerUpdate.pz()); + float eyeHeight = playerUpdate.crouching() ? 1.1f : 1.7f; + gameRenderer.getCamera().setPosition(playerUpdate.px(), playerUpdate.py() + eyeHeight, playerUpdate.pz()); gameRenderer.getCamera().setVelocity(playerUpdate.vx(), playerUpdate.vy(), playerUpdate.vz()); // TODO: Unload far away chunks and request close chunks we don't have. } diff --git a/core/src/main/java/nl/andrewl/aos_core/Net.java b/core/src/main/java/nl/andrewl/aos_core/Net.java index d2151e2..c1dbf3c 100644 --- a/core/src/main/java/nl/andrewl/aos_core/Net.java +++ b/core/src/main/java/nl/andrewl/aos_core/Net.java @@ -32,6 +32,7 @@ public final class Net { serializer.registerType(10, PlayerUpdateMessage.class); serializer.registerType(11, PlayerJoinMessage.class); serializer.registerType(12, PlayerLeaveMessage.class); + serializer.registerType(13, WorldInfoMessage.class); } public static ExtendedDataInputStream getInputStream(InputStream in) { diff --git a/core/src/main/java/nl/andrewl/aos_core/model/ColorPalette.java b/core/src/main/java/nl/andrewl/aos_core/model/ColorPalette.java index 2c42fc3..0c1a0ff 100644 --- a/core/src/main/java/nl/andrewl/aos_core/model/ColorPalette.java +++ b/core/src/main/java/nl/andrewl/aos_core/model/ColorPalette.java @@ -28,6 +28,24 @@ public class ColorPalette { colors[value - 1].set(r, g, b); } + public float[] toArray() { + float[] array = new float[3 * MAX_COLORS]; + for (int i = 0; i < MAX_COLORS; i++) { + array[i * 3] = colors[i].x; + array[i * 3 + 1] = colors[i].y; + array[i * 3 + 2] = colors[i].z; + } + return array; + } + + public static ColorPalette fromArray(float[] array) { + ColorPalette palette = new ColorPalette(); + for (int i = 0; i < array.length / 3; i++) { + palette.colors[i].set(array[i * 3], array[i * 3 + 1], array[i * 3 + 2]); + } + return palette; + } + public static ColorPalette grayscale() { ColorPalette palette = new ColorPalette(); for (int i = 0; i < MAX_COLORS; i++) { diff --git a/core/src/main/java/nl/andrewl/aos_core/model/Iterator3D.java b/core/src/main/java/nl/andrewl/aos_core/model/Iterator3D.java new file mode 100644 index 0000000..d6df8c4 --- /dev/null +++ b/core/src/main/java/nl/andrewl/aos_core/model/Iterator3D.java @@ -0,0 +1,5 @@ +package nl.andrewl.aos_core.model; + +public interface Iterator3D { + void doAction(int x, int y, int z); +} 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 e88da01..97d79fa 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 @@ -5,8 +5,7 @@ import org.joml.Vector3f; import org.joml.Vector3i; import org.joml.Vector3ic; -import java.util.HashMap; -import java.util.Map; +import java.util.*; /** * A world is just a collection of chunks that together form the environment @@ -14,7 +13,20 @@ import java.util.Map; */ public class World { protected final Map chunkMap = new HashMap<>(); - protected final ColorPalette palette = ColorPalette.rainbow(); + protected ColorPalette palette; + + public World(ColorPalette palette, Collection chunks) { + this.palette = palette; + for (var chunk : chunks) addChunk(chunk); + } + + public World(ColorPalette palette) { + this(palette, Collections.emptyList()); + } + + public World() { + this(ColorPalette.rainbow()); + } public void addChunk(Chunk chunk) { chunkMap.put(chunk.getPosition(), chunk); @@ -32,6 +44,10 @@ public class World { return palette; } + public void setPalette(ColorPalette palette) { + this.palette = palette; + } + public byte getBlockAt(Vector3f pos) { return getBlockAt(pos, new Vector3i()); } @@ -62,6 +78,10 @@ public class World { chunk.setBlockAt(blockPos.x, blockPos.y, blockPos.z, block); } + public void setBlockAt(int x, int y, int z, byte block) { + setBlockAt(new Vector3f(x, y, z), block); + } + // public byte getBlockAt(int x, int y, int z) { //// int chunkX = x / Chunk.SIZE; //// int localX = x % Chunk.SIZE; diff --git a/core/src/main/java/nl/andrewl/aos_core/model/Worlds.java b/core/src/main/java/nl/andrewl/aos_core/model/Worlds.java new file mode 100644 index 0000000..387d64c --- /dev/null +++ b/core/src/main/java/nl/andrewl/aos_core/model/Worlds.java @@ -0,0 +1,127 @@ +package nl.andrewl.aos_core.model; + +import org.joml.Vector3i; + +import java.util.Collections; + +/** + * Simple container for a bunch of static methods for creating pre-made worlds + * for when you don't want to spend time on that yourself. + */ +public final class Worlds { + private Worlds() {} + + /** + * A world consisting of a single chunk, with blocks from y = 0 to y = 8. + * @return The world. + */ + public static World smallCube() { + Chunk chunk = new Chunk(0, 0, 0); + for (int x = 0; x < Chunk.SIZE; x++) { + for (int z = 0; z < Chunk.SIZE; z++) { + for (int y = 0; y < Chunk.SIZE / 2; y++) { + chunk.setBlockAt(x, y, z, (byte) 40); + } + } + } + return new World(ColorPalette.rainbow(), Collections.singleton(chunk)); + } + + /** + * A 3x3 chunk world consisting of various structures and areas that are + * ideal for testing the game. + * @return The world. + */ + public static World testingWorld() { + ColorPalette palette = new ColorPalette(); + palette.setColor((byte) 1, 0.610f, 0.604f, 0.494f);// light brown + palette.setColor((byte) 9, 0.610f, 0.604f, 0.2f);// light brown + palette.setColor((byte) 2, 1, 1, 1);// white + palette.setColor((byte) 3, 0, 0, 0);// black + + palette.setColor((byte) 4, 1, 0, 0);// red + palette.setColor((byte) 5, 0, 1, 0);// green + palette.setColor((byte) 6, 0, 0, 1);// blue + palette.setColor((byte) 7, 1, 1, 0);// yellow + palette.setColor((byte) 8, 1, 0, 0);// magenta + + World world = new World(palette); + for (int x = -1; x < 2; x++) { + for (int z = -1; z < 2; z++) { + for (int y = -1; y < 2; y++) { + world.addChunk(new Chunk(x, y, z)); + } + } + } + Vector3i min = new Vector3i(-1 * Chunk.SIZE); + Vector3i max = new Vector3i(2 * Chunk.SIZE - 1); + int groundLevel = 0; + for (int x = min.x; x <= max.x; x++) { + for (int z = min.z; z <= max.z; z++) { + for (int y = min.y; y < groundLevel; y++) { + byte color; + if (x % 2 == 0 && z % 2 == 0) { + color = 1; + } else { + color = 9; + } + world.setBlockAt(x, y, z, color); + } + } + } + + // -Z axis + for (int z = min.z; z < 0; z++) { + world.setBlockAt(0, -1, z, (byte) 4); + } + // +Z axis + for (int z = 0; z <= max.z; z++) { + world.setBlockAt(0, -1, z, (byte) 6); + } + // -X axis + for (int x = min.x; x < 0; x++) { + world.setBlockAt(x, -1, 0, (byte) 5); + } + // +X axis + for (int x = 0; x <= max.x; x++) { + world.setBlockAt(x, -1, 0, (byte) 7); + } + // Draw a '+' in the + side of the world. + world.setBlockAt(10, -1, 10, (byte) 3); + world.setBlockAt(11, -1, 10, (byte) 3); + world.setBlockAt(12, -1, 10, (byte) 3); + world.setBlockAt(9, -1, 10, (byte) 3); + world.setBlockAt(8, -1, 10, (byte) 3); + world.setBlockAt(10, -1, 9, (byte) 3); + world.setBlockAt(10, -1, 8, (byte) 3); + world.setBlockAt(10, -1, 11, (byte) 3); + world.setBlockAt(10, -1, 12, (byte) 3); + // Draw a '-' in the - side of the world. + world.setBlockAt(-7, -1, -8, (byte) 3); + world.setBlockAt(-8, -1, -8, (byte) 3); + world.setBlockAt(-9, -1, -8, (byte) 3); + world.setBlockAt(-10, -1, -8, (byte) 3); + world.setBlockAt(-11, -1, -8, (byte) 3); + + // Draw a '+' shaped wall. + for (int x = 16; x < 26; x++) { + world.setBlockAt(x, 0, 16, (byte) 1); + world.setBlockAt(x, 1, 16, (byte) 1); + world.setBlockAt(x, 2, 16, (byte) 1); + } + for (int z = 16; z < 26; z++) { + world.setBlockAt(16, 0, z, (byte) 1); + world.setBlockAt(16, 1, z, (byte) 1); + world.setBlockAt(16, 2, z, (byte) 1); + } + // Add a small staircase. + world.setBlockAt(14, 0, 20, (byte) 1); + world.setBlockAt(14, 0, 21, (byte) 1); + world.setBlockAt(14, 0, 22, (byte) 1); + world.setBlockAt(15, 1, 20, (byte) 1); + world.setBlockAt(15, 1, 21, (byte) 1); + world.setBlockAt(15, 1, 22, (byte) 1); + + return world; + } +} diff --git a/core/src/main/java/nl/andrewl/aos_core/net/WorldInfoMessage.java b/core/src/main/java/nl/andrewl/aos_core/net/WorldInfoMessage.java new file mode 100644 index 0000000..f95cbf6 --- /dev/null +++ b/core/src/main/java/nl/andrewl/aos_core/net/WorldInfoMessage.java @@ -0,0 +1,16 @@ +package nl.andrewl.aos_core.net; + +import nl.andrewl.aos_core.model.World; +import nl.andrewl.record_net.Message; + +/** + * Message that the server sends to connecting clients with some metadata about + * the world. + */ +public record WorldInfoMessage( + float[] palette +) implements Message { + public WorldInfoMessage(World world) { + this(world.getPalette().toArray()); + } +} diff --git a/core/src/main/java/nl/andrewl/aos_core/net/udp/PlayerUpdateMessage.java b/core/src/main/java/nl/andrewl/aos_core/net/udp/PlayerUpdateMessage.java index 86f4a4f..9584fc0 100644 --- a/core/src/main/java/nl/andrewl/aos_core/net/udp/PlayerUpdateMessage.java +++ b/core/src/main/java/nl/andrewl/aos_core/net/udp/PlayerUpdateMessage.java @@ -1,6 +1,5 @@ package nl.andrewl.aos_core.net.udp; -import nl.andrewl.aos_core.model.Player; import nl.andrewl.record_net.Message; /** @@ -11,14 +10,6 @@ public record PlayerUpdateMessage( int clientId, float px, float py, float pz, float vx, float vy, float vz, - float ox, float oy -) implements Message { - public PlayerUpdateMessage(Player player) { - this( - player.getId(), - player.getPosition().x, player.getPosition().y, player.getPosition().z, - player.getVelocity().x, player.getVelocity().y, player.getVelocity().z, - player.getOrientation().x, player.getOrientation().y - ); - } -} + float ox, float oy, + boolean crouching +) implements Message {} diff --git a/server/src/main/java/nl/andrewl/aos2_server/ClientCommunicationHandler.java b/server/src/main/java/nl/andrewl/aos2_server/ClientCommunicationHandler.java index 0758a65..ae9d2ac 100644 --- a/server/src/main/java/nl/andrewl/aos2_server/ClientCommunicationHandler.java +++ b/server/src/main/java/nl/andrewl/aos2_server/ClientCommunicationHandler.java @@ -90,6 +90,7 @@ public class ClientCommunicationHandler { Net.write(new ConnectAcceptMessage(player.getId()), out); log.debug("Sent connect accept message."); + sendTcpMessage(new WorldInfoMessage(server.getWorld())); for (var chunk : server.getWorld().getChunkMap().values()) { sendTcpMessage(new ChunkDataMessage(chunk)); } diff --git a/server/src/main/java/nl/andrewl/aos2_server/PlayerManager.java b/server/src/main/java/nl/andrewl/aos2_server/PlayerManager.java index 3648b7a..842e81f 100644 --- a/server/src/main/java/nl/andrewl/aos2_server/PlayerManager.java +++ b/server/src/main/java/nl/andrewl/aos2_server/PlayerManager.java @@ -31,8 +31,14 @@ public class PlayerManager { clientHandlers.put(player.getId(), handler); log.info("Registered player \"{}\" with id {}", player.getUsername(), player.getId()); player.setPosition(new Vector3f(0, 64, 0)); - broadcastTcpMessage(new PlayerJoinMessage(player)); - broadcastUdpMessage(new PlayerUpdateMessage(player)); + broadcastTcpMessageToAllBut(new PlayerJoinMessage(player), player); + broadcastUdpMessage(new PlayerUpdateMessage( + player.getId(), + player.getPosition().x, player.getPosition().y, player.getPosition().z, + player.getVelocity().x, player.getVelocity().y, player.getVelocity().z, + player.getOrientation().x, player.getOrientation().y, + player.getLastInputState().crouching() + )); return player; } @@ -83,6 +89,14 @@ public class PlayerManager { } } + public void broadcastTcpMessageToAllBut(Message msg, ServerPlayer player) { + for (var entry : clientHandlers.entrySet()) { + if (entry.getKey() != player.getId()) { + entry.getValue().sendTcpMessage(msg); + } + } + } + public void broadcastUdpMessage(Message msg) { try { byte[] data = Net.write(msg); diff --git a/server/src/main/java/nl/andrewl/aos2_server/Server.java b/server/src/main/java/nl/andrewl/aos2_server/Server.java index be44a59..59477af 100644 --- a/server/src/main/java/nl/andrewl/aos2_server/Server.java +++ b/server/src/main/java/nl/andrewl/aos2_server/Server.java @@ -1,22 +1,18 @@ package nl.andrewl.aos2_server; -import nl.andrewl.aos_core.model.Chunk; import nl.andrewl.aos_core.model.World; -import nl.andrewl.aos_core.model.WorldIO; +import nl.andrewl.aos_core.model.Worlds; import nl.andrewl.aos_core.net.UdpReceiver; import nl.andrewl.aos_core.net.udp.ClientInputState; import nl.andrewl.aos_core.net.udp.ClientOrientationState; import nl.andrewl.aos_core.net.udp.DatagramInit; import nl.andrewl.aos_core.net.udp.PlayerUpdateMessage; import nl.andrewl.record_net.Message; -import org.joml.Vector3f; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.*; -import java.nio.file.Path; -import java.util.Random; import java.util.concurrent.ForkJoinPool; public class Server implements Runnable { @@ -31,65 +27,13 @@ public class Server implements Runnable { private final WorldUpdater worldUpdater; public Server() throws IOException { - this.serverSocket = new ServerSocket(24464, 5); + this.serverSocket = new ServerSocket(25565, 5); this.serverSocket.setReuseAddress(true); - this.datagramSocket = new DatagramSocket(24464); + this.datagramSocket = new DatagramSocket(25565); this.datagramSocket.setReuseAddress(true); this.playerManager = new PlayerManager(); this.worldUpdater = new WorldUpdater(this, 20); - - // Generate world. TODO: do this elsewhere. - Random rand = new Random(1); - this.world = new World(); - for (int x = -5; x <= 5; x++) { - for (int y = 0; y <= 5; y++) { - for (int z = -3; z <= 3; z++) { - Chunk chunk = new Chunk(x, y, z); - if (y <= 3) { - for (int i = 0; i < Chunk.TOTAL_SIZE; i++) { - chunk.getBlocks()[i] = (byte) rand.nextInt(20, 40); - } - } - world.addChunk(chunk); - } - } - } - world.setBlockAt(new Vector3f(5, 64, 5), (byte) 50); - world.setBlockAt(new Vector3f(5, 64, 6), (byte) 50); - world.setBlockAt(new Vector3f(5, 64, 7), (byte) 50); - world.setBlockAt(new Vector3f(5, 65, 6), (byte) 50); - world.setBlockAt(new Vector3f(5, 66, 7), (byte) 50); - world.setBlockAt(new Vector3f(5, 65, 7), (byte) 50); - world.setBlockAt(new Vector3f(5, 67, 8), (byte) 50); - world.setBlockAt(new Vector3f(6, 67, 8), (byte) 50); - world.setBlockAt(new Vector3f(7, 67, 8), (byte) 50); - world.setBlockAt(new Vector3f(5, 67, 9), (byte) 50); - world.setBlockAt(new Vector3f(6, 67, 9), (byte) 50); - world.setBlockAt(new Vector3f(7, 67, 9), (byte) 50); - - for (int z = 0; z > -20; z--) { - world.setBlockAt(new Vector3f(0, 63, z), (byte) 120); - } - - for (int x = 0; x < 10; x++) { - world.setBlockAt(new Vector3f(x - 5, 64, 3), (byte) 80); - world.setBlockAt(new Vector3f(x - 5, 65, 3), (byte) 80); - world.setBlockAt(new Vector3f(x - 5, 66, 3), (byte) 80); - } - - for (int z = 0; z < 10; z++) { - world.setBlockAt(new Vector3f(20, 64, z), (byte) 80); - world.setBlockAt(new Vector3f(20, 65, z), (byte) 80); - world.setBlockAt(new Vector3f(20, 66, z), (byte) 80); - } - world.setBlockAt(new Vector3f(21, 64, 6), (byte) 1); - - for (int x = 0; x < 127; x++) { - world.setBlockAt(new Vector3f(x - 50, 63, -15), (byte) x); - } - - WorldIO.write(world, Path.of("testworld")); -// this.world = WorldIO.read(Path.of("testworld")); + this.world = Worlds.testingWorld(); } @Override @@ -118,12 +62,25 @@ public class Server implements Runnable { ServerPlayer player = playerManager.getPlayer(inputState.clientId()); if (player != null) { player.setLastInputState(inputState); + playerManager.broadcastUdpMessage(new PlayerUpdateMessage( + player.getId(), + player.getPosition().x, player.getPosition().y, player.getPosition().z, + player.getVelocity().x, player.getVelocity().y, player.getVelocity().z, + player.getOrientation().x, player.getOrientation().y, + player.getLastInputState().crouching() + )); } } else if (msg instanceof ClientOrientationState orientationState) { ServerPlayer player = playerManager.getPlayer(orientationState.clientId()); if (player != null) { player.setOrientation(orientationState.x(), orientationState.y()); - playerManager.broadcastUdpMessageToAllBut(new PlayerUpdateMessage(player), player); + playerManager.broadcastUdpMessageToAllBut(new PlayerUpdateMessage( + player.getId(), + player.getPosition().x, player.getPosition().y, player.getPosition().z, + player.getVelocity().x, player.getVelocity().y, player.getVelocity().z, + player.getOrientation().x, player.getOrientation().y, + player.getLastInputState().crouching() + ), player); } } } 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 7f6e96e..d4f05a8 100644 --- a/server/src/main/java/nl/andrewl/aos2_server/ServerPlayer.java +++ b/server/src/main/java/nl/andrewl/aos2_server/ServerPlayer.java @@ -51,13 +51,11 @@ public class ServerPlayer extends Player { } public void tick(float dt, World world) { -// log.info("Ticking player " + id); updated = false; // Reset the updated flag. This will be set to true if the player was updated in this tick. checkBlockCollisions(dt, world); if (isGrounded(world)) { -// System.out.println("g"); tickHorizontalVelocity(); if (lastInputState.jumping()) velocity.y = JUMP_SPEED; } else { @@ -71,8 +69,6 @@ public class ServerPlayer extends Player { position.add(scaledVelocity); updated = true; } - -// System.out.printf("pos: [%.3f, %.3f, %.3f]%n", position.x, position.y, position.z); } private void tickHorizontalVelocity() { @@ -152,45 +148,42 @@ public class ServerPlayer extends Player { // Check if the player is about to hit a wall. // -Z - if ( - world.getBlockAt(nextTickPosition.x(), nextTickPosition.y(), minZNextTick) != 0 && - world.getBlockAt(nextTickPosition.x(), nextTickPosition.y() + 1, minZNextTick) != 0 - ) { + if (world.getBlockAt(nextTickPosition.x(), nextTickPosition.y() + 1, minZNextTick) != 0) { System.out.println("wall -z"); position.z = ((float) minZNextTick) + RADIUS + 0.001f; velocity.z = 0; updated = true; } // +Z - if ( - world.getBlockAt(nextTickPosition.x(), nextTickPosition.y(), maxZNextTick) != 0 && - world.getBlockAt(nextTickPosition.x(), nextTickPosition.y() + 1, maxZNextTick) != 0 - ) { - System.out.println("wall +z"); - position.z = ((float) maxZNextTick) - RADIUS - 0.001f; - velocity.z = 0; - updated = true; - } - // -X - if ( - world.getBlockAt(minXNextTick, nextTickPosition.y(), nextTickPosition.z()) != 0 && - world.getBlockAt(minXNextTick, nextTickPosition.y() + 1, nextTickPosition.z()) != 0 - ) { - System.out.println("wall -x"); - position.x = ((float) minXNextTick) + RADIUS + 0.001f; - velocity.x = 0; - updated = true; - } - // +X - if ( - world.getBlockAt(maxXNextTick, nextTickPosition.y(), nextTickPosition.z()) != 0 && - world.getBlockAt(maxXNextTick, nextTickPosition.y() + 1, nextTickPosition.z()) != 0 - ) { - System.out.println("wall +x"); - position.x = ((float) maxXNextTick) - RADIUS - 0.001f; - velocity.x = 0; - updated = true; - } +// if ( +// world.getBlockAt(nextTickPosition.x(), nextTickPosition.y(), maxZNextTick) != 0 && +// world.getBlockAt(nextTickPosition.x(), nextTickPosition.y() + 1, maxZNextTick) != 0 +// ) { +// System.out.println("wall +z"); +// position.z = ((float) maxZNextTick) - RADIUS - 0.001f; +// velocity.z = 0; +// updated = true; +// } +// // -X +// if ( +// world.getBlockAt(minXNextTick, nextTickPosition.y(), nextTickPosition.z()) != 0 && +// world.getBlockAt(minXNextTick, nextTickPosition.y() + 1, nextTickPosition.z()) != 0 +// ) { +// System.out.println("wall -x"); +// position.x = ((float) minXNextTick) + RADIUS + 0.001f; +// velocity.x = 0; +// updated = true; +// } +// // +X +// if ( +// world.getBlockAt(maxXNextTick, nextTickPosition.y(), nextTickPosition.z()) != 0 && +// world.getBlockAt(maxXNextTick, nextTickPosition.y() + 1, nextTickPosition.z()) != 0 +// ) { +// System.out.println("wall +x"); +// position.x = ((float) maxXNextTick) - RADIUS - 0.001f; +// velocity.x = 0; +// updated = true; +// } // Check if the player is going to hit a ceiling on the next tick, and cancel velocity and set position. final float nextTickHeadY = nextTickPosition.y() + (lastInputState.crouching() ? HEIGHT_CROUCH : HEIGHT); diff --git a/server/src/main/java/nl/andrewl/aos2_server/WorldUpdater.java b/server/src/main/java/nl/andrewl/aos2_server/WorldUpdater.java index a78e114..1546f7f 100644 --- a/server/src/main/java/nl/andrewl/aos2_server/WorldUpdater.java +++ b/server/src/main/java/nl/andrewl/aos2_server/WorldUpdater.java @@ -57,100 +57,13 @@ public class WorldUpdater implements Runnable { private void tick() { for (var player : server.getPlayerManager().getPlayers()) { player.tick(secondsPerTick, server.getWorld()); - if (player.isUpdated()) server.getPlayerManager().broadcastUdpMessage(new PlayerUpdateMessage(player)); - } - } - - private void updatePlayerMovement(ServerPlayer player) { - boolean updated = false; - var v = player.getVelocity(); - var hv = new Vector3f(v.x, 0, v.z); - var p = player.getPosition(); - - // Check if we have a negative velocity that will cause us to fall through a block next tick. - float nextTickY = p.y + v.y * secondsPerTick; - if (server.getWorld().getBlockAt(new Vector3f(p.x, nextTickY, p.z)) != 0) { - // Find the first block we'll hit and set the player down on that. - int floorY = (int) Math.floor(p.y) - 1; - while (true) { - if (server.getWorld().getBlockAt(new Vector3f(p.x, floorY, p.z)) != 0) { - p.y = floorY + 1f; - v.y = 0; - break; - } else { - floorY--; - } - } - } - - // Check if the player is on the ground. - boolean grounded = (Math.floor(p.y) == p.y && server.getWorld().getBlockAt(new Vector3f(p.x, p.y - 0.0001f, p.z)) != 0); - - if (!grounded) { - v.y -= 9.81f * secondsPerTick; - } - - // Apply horizontal deceleration to the player before computing any input-derived acceleration. - if (grounded && hv.length() > 0) { - Vector3f deceleration = new Vector3f(hv).negate().normalize().mul(Math.min(hv.length(), 2f)); - hv.add(deceleration); - if (hv.length() < 0.1f) { - hv.set(0); - } - v.x = hv.x; - v.z = hv.z; - updated = true; - } - - Vector3f a = new Vector3f(); - var inputState = player.getLastInputState(); - if (inputState.jumping() && grounded) { - v.y = 15f; - } - - final float horizontalAcceleration = 5; - // Compute horizontal motion separately. - if (grounded) { - if (inputState.forward()) a.z -= 1; - if (inputState.backward()) a.z += 1; - if (inputState.left()) a.x -= 1; - if (inputState.right()) a.x += 1; -// if (inputState.crouching()) a.y -= 1; // TODO: do crouching instead of down. - if (a.lengthSquared() > 0) { - a.normalize(); - Matrix4f moveTransform = new Matrix4f(); - moveTransform.rotate(player.getOrientation().x, new Vector3f(0, 1, 0)); - moveTransform.transformDirection(a); - a.mul(horizontalAcceleration); - hv.add(a); - - final float maxSpeed; - if (inputState.crouching()) { - maxSpeed = 2.5f; - } else if (inputState.sprinting()) { - maxSpeed = 10f; - } else { - maxSpeed = 6f; - } - if (hv.length() > maxSpeed) { - hv.normalize(maxSpeed); - } - v.x = hv.x; - v.z = hv.z; - updated = true; - } - } - - // Apply velocity to the player's position. - if (v.lengthSquared() > 0) { - Vector3f scaledVelocity = new Vector3f(v); - scaledVelocity.mul(secondsPerTick); - p.add(scaledVelocity); - updated = true; - } - - if (updated) { - server.getPlayerManager().broadcastUdpMessage(new PlayerUpdateMessage(player)); + if (player.isUpdated()) server.getPlayerManager().broadcastUdpMessage(new PlayerUpdateMessage( + player.getId(), + player.getPosition().x, player.getPosition().y, player.getPosition().z, + player.getVelocity().x, player.getVelocity().y, player.getVelocity().z, + player.getOrientation().x, player.getOrientation().y, + player.getLastInputState().crouching() + )); } } }