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 f86a1f9..d88c571 100644 --- a/core/src/main/java/nl/andrewl/aos_core/Net.java +++ b/core/src/main/java/nl/andrewl/aos_core/Net.java @@ -1,6 +1,6 @@ package nl.andrewl.aos_core; -import nl.andrewl.aos_core.net.PlayerConnectRequestMessage; +import nl.andrewl.aos_core.net.ConnectRequestMessage; import nl.andrewl.record_net.Message; import nl.andrewl.record_net.Serializer; import nl.andrewl.record_net.util.ExtendedDataInputStream; @@ -19,7 +19,7 @@ public final class Net { private static final Serializer serializer = new Serializer(); static { - serializer.registerType(1, PlayerConnectRequestMessage.class); + serializer.registerType(1, ConnectRequestMessage.class); } public static ExtendedDataInputStream getInputStream(InputStream in) { diff --git a/core/src/main/java/nl/andrewl/aos_core/model/Player.java b/core/src/main/java/nl/andrewl/aos_core/model/Player.java new file mode 100644 index 0000000..b51ce8c --- /dev/null +++ b/core/src/main/java/nl/andrewl/aos_core/model/Player.java @@ -0,0 +1,18 @@ +package nl.andrewl.aos_core.model; + +import org.joml.Vector2f; +import org.joml.Vector3f; + +public class Player { + private final Vector3f position; + private final Vector3f velocity; + private final Vector2f orientation; + private final String username; + + public Player(String username) { + this.position = new Vector3f(); + this.velocity = new Vector3f(); + this.orientation = new Vector2f(); + this.username = username; + } +} 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 632a2a0..950b401 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 @@ -3,10 +3,13 @@ package nl.andrewl.aos_core.model; import org.joml.Vector3i; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; public class World { - Map chunkMap = new HashMap<>(); + private final Map chunkMap = new HashMap<>(); + private final Set players = new HashSet<>(); public byte getBlockAt(int x, int y, int z) { int chunkX = x / Chunk.SIZE; diff --git a/core/src/main/java/nl/andrewl/aos_core/net/ConnectAcceptMessage.java b/core/src/main/java/nl/andrewl/aos_core/net/ConnectAcceptMessage.java new file mode 100644 index 0000000..0f7f46a --- /dev/null +++ b/core/src/main/java/nl/andrewl/aos_core/net/ConnectAcceptMessage.java @@ -0,0 +1,5 @@ +package nl.andrewl.aos_core.net; + +import nl.andrewl.record_net.Message; + +public record ConnectAcceptMessage () implements Message {} diff --git a/core/src/main/java/nl/andrewl/aos_core/net/ConnectRejectMessage.java b/core/src/main/java/nl/andrewl/aos_core/net/ConnectRejectMessage.java new file mode 100644 index 0000000..5bed255 --- /dev/null +++ b/core/src/main/java/nl/andrewl/aos_core/net/ConnectRejectMessage.java @@ -0,0 +1,5 @@ +package nl.andrewl.aos_core.net; + +import nl.andrewl.record_net.Message; + +public record ConnectRejectMessage(String reason) implements Message {} diff --git a/core/src/main/java/nl/andrewl/aos_core/net/PlayerConnectRequestMessage.java b/core/src/main/java/nl/andrewl/aos_core/net/ConnectRequestMessage.java similarity index 55% rename from core/src/main/java/nl/andrewl/aos_core/net/PlayerConnectRequestMessage.java rename to core/src/main/java/nl/andrewl/aos_core/net/ConnectRequestMessage.java index 077f9fc..91d52e8 100644 --- a/core/src/main/java/nl/andrewl/aos_core/net/PlayerConnectRequestMessage.java +++ b/core/src/main/java/nl/andrewl/aos_core/net/ConnectRequestMessage.java @@ -2,7 +2,4 @@ package nl.andrewl.aos_core.net; import nl.andrewl.record_net.Message; -public record PlayerConnectRequestMessage ( - String username, - int udpPort -) implements Message {} +public record ConnectRequestMessage(String username, int udpPort) implements Message {} diff --git a/core/src/main/java/nl/andrewl/aos_core/net/PlayerConnectRejectMessage.java b/core/src/main/java/nl/andrewl/aos_core/net/PlayerConnectRejectMessage.java deleted file mode 100644 index 54f774c..0000000 --- a/core/src/main/java/nl/andrewl/aos_core/net/PlayerConnectRejectMessage.java +++ /dev/null @@ -1,5 +0,0 @@ -package nl.andrewl.aos_core.net; - -import nl.andrewl.record_net.Message; - -public record PlayerConnectRejectMessage (String reason) implements Message {} diff --git a/core/src/main/java/nl/andrewl/aos_core/net/udp/InitPacket.java b/core/src/main/java/nl/andrewl/aos_core/net/udp/DatagramInit.java similarity index 60% rename from core/src/main/java/nl/andrewl/aos_core/net/udp/InitPacket.java rename to core/src/main/java/nl/andrewl/aos_core/net/udp/DatagramInit.java index 43bb300..670c5a7 100644 --- a/core/src/main/java/nl/andrewl/aos_core/net/udp/InitPacket.java +++ b/core/src/main/java/nl/andrewl/aos_core/net/udp/DatagramInit.java @@ -2,4 +2,4 @@ package nl.andrewl.aos_core.net.udp; import nl.andrewl.record_net.Message; -public record InitPacket () implements Message {} +public record DatagramInit() implements Message {} diff --git a/design/net.md b/design/net.md index 828efdc..a50d3c8 100644 --- a/design/net.md +++ b/design/net.md @@ -8,5 +8,15 @@ When referring to the names of packets, we will assume a common package name of ### Player Connection This workflow is involved in the establishment of a connection between the client and server. -1. Player sends a `PlayerConnectRequestMessage` via TCP, immediately upon opening a socket connection. It contains the player's desired `username`, and their `udpPort` that they will use to connect. -2. The server will respond with either a `PlayerConnectRejectMessage` with a `reason` for the rejection, or a `PlayerConnectAcceptMessage`. +1. Player sends a `ConnectRequestMessage` via TCP, immediately upon opening a socket connection. It contains the player's desired `username`, and their `udpPort` that they will use to connect. +2. The server will respond with either a `ConnectRejectMessage` with a `reason` for the rejection, or a `ConnectAcceptMessage`. +3. If the player received an acceptance message, they will then send a `DatagramInit` to the server's UDP socket (on the same address/port). The player should keep sending such an init message until they receive a `DatagramInit` message echoed back as a response. The player should then stop sending init messages, and expect to begin receiving normal communication data through the datagram socket. + +### World Data +A combination of TCP and UDP communication is used to ensure that all connected clients have the latest information about the state of the world. + +Initially when the player connects to a server, the server will begin sending `ChunkDataMessage` packets via TCP to the player, with the full chunk data of an individual chunk. + +If, during the course of a game tick, a chunk is updated, at the end of the tick, a `ChunkUpdateMessage` message is sent which provides the coordinates and new block data for a block in a chunk. + +A player should regularly send a `ChunkHashMessage` to the server that contains a hash of a certain chunk, to verify that the player's chunk data matches the server's. The server will send a `ChunkDataMessage` if the player's hash is incorrect and the player should replace their chunk data. \ No newline at end of file diff --git a/server/src/main/java/nl/andrewl/aos2_server/ClientHandler.java b/server/src/main/java/nl/andrewl/aos2_server/ClientHandler.java index d471a23..15e1568 100644 --- a/server/src/main/java/nl/andrewl/aos2_server/ClientHandler.java +++ b/server/src/main/java/nl/andrewl/aos2_server/ClientHandler.java @@ -1,8 +1,8 @@ package nl.andrewl.aos2_server; import nl.andrewl.aos_core.Net; -import nl.andrewl.aos_core.net.PlayerConnectRejectMessage; -import nl.andrewl.aos_core.net.PlayerConnectRequestMessage; +import nl.andrewl.aos_core.net.ConnectRejectMessage; +import nl.andrewl.aos_core.net.ConnectRequestMessage; import nl.andrewl.record_net.Message; import nl.andrewl.record_net.util.ExtendedDataInputStream; import nl.andrewl.record_net.util.ExtendedDataOutputStream; @@ -60,16 +60,26 @@ public class ClientHandler extends Thread { } private void establishConnection() { + try { + socket.setSoTimeout(1000); + } catch (SocketException e) { + throw new RuntimeException(e); + } boolean connectionEstablished = false; int attempts = 0; while (!connectionEstablished && attempts < 100) { try { Message msg = Net.read(in); - if (msg instanceof PlayerConnectRequestMessage connectMsg) { + if (msg instanceof ConnectRequestMessage connectMsg) { this.clientAddress = socket.getInetAddress(); this.clientUdpPort = connectMsg.udpPort(); System.out.println("Player connected: " + connectMsg.username()); connectionEstablished = true; + try { + socket.setSoTimeout(0); + } catch (SocketException e) { + throw new RuntimeException(e); + } } } catch (IOException e) { e.printStackTrace(); @@ -78,7 +88,7 @@ public class ClientHandler extends Thread { } if (!connectionEstablished) { try { - Net.write(new PlayerConnectRejectMessage("Too many connect attempts failed."), out); + Net.write(new ConnectRejectMessage("Too many connect attempts failed."), out); } catch (IOException e) { e.printStackTrace(); }