diff --git a/client/src/main/java/nl/andrewl/aos2_client/CommunicationHandler.java b/client/src/main/java/nl/andrewl/aos2_client/CommunicationHandler.java index 1b6e832..9c80b54 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/CommunicationHandler.java +++ b/client/src/main/java/nl/andrewl/aos2_client/CommunicationHandler.java @@ -55,7 +55,7 @@ public class CommunicationHandler { socket.setSoTimeout(1000); in = Net.getInputStream(socket.getInputStream()); out = Net.getOutputStream(socket.getOutputStream()); - Net.write(new ConnectRequestMessage(username), out); + Net.write(new ConnectRequestMessage(username, true), out); Message response = Net.read(in); socket.setSoTimeout(0); if (response instanceof ConnectRejectMessage rejectMessage) { diff --git a/core/src/main/java/nl/andrewl/aos_core/net/connect/ConnectRequestMessage.java b/core/src/main/java/nl/andrewl/aos_core/net/connect/ConnectRequestMessage.java index a869ee4..14a7014 100644 --- a/core/src/main/java/nl/andrewl/aos_core/net/connect/ConnectRequestMessage.java +++ b/core/src/main/java/nl/andrewl/aos_core/net/connect/ConnectRequestMessage.java @@ -2,4 +2,10 @@ package nl.andrewl.aos_core.net.connect; import nl.andrewl.record_net.Message; -public record ConnectRequestMessage(String username) implements Message {} +/** + * The first message that a client sends via TCP to the server, to indicate + * that they'd like to join. + * @param username The player's chosen username. + * @param spectator Whether the player wants to be a spectator. + */ +public record ConnectRequestMessage(String username, boolean spectator) 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 e524f56..144d054 100644 --- a/server/src/main/java/nl/andrewl/aos2_server/ClientCommunicationHandler.java +++ b/server/src/main/java/nl/andrewl/aos2_server/ClientCommunicationHandler.java @@ -111,8 +111,7 @@ public class ClientCommunicationHandler { // Try to set the TCP timeout back to 0 now that we've got the correct request. socket.setSoTimeout(0); this.clientAddress = socket.getInetAddress(); - connectionEstablished = true; - this.player = server.getPlayerManager().register(this, connectMsg.username()); + this.player = server.getPlayerManager().register(this, connectMsg.username(), connectMsg.spectator()); Net.write(new ConnectAcceptMessage(player.getId()), out); sendInitialData(); sendTcpMessage(ChatMessage.privateMessage("Welcome to the server, " + player.getUsername() + ".")); @@ -123,6 +122,7 @@ public class ClientCommunicationHandler { TcpReceiver tcpReceiver = new TcpReceiver(in, this::handleTcpMessage) .withShutdownHook(() -> server.getPlayerManager().deregister(this.player)); new Thread(tcpReceiver).start(); + connectionEstablished = true; } } catch (SocketTimeoutException e) { // Ignore this one, since this will happen if the client doesn't send data properly. @@ -231,7 +231,7 @@ public class ClientCommunicationHandler { out.writeFloat(player.getOrientation().y()); out.writeBoolean(player.isCrouching()); - out.writeInt(player.getInventory().getSelectedItemStack().getType().getId()); + out.writeInt(player.getInventory().getSelectedItemStack() == null ? -1 : player.getInventory().getSelectedItemStack().getType().getId()); out.writeByte(player.getInventory().getSelectedBlockValue()); out.writeInt(player.getMode().ordinal()); } 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 0817161..4529a3a 100644 --- a/server/src/main/java/nl/andrewl/aos2_server/PlayerManager.java +++ b/server/src/main/java/nl/andrewl/aos2_server/PlayerManager.java @@ -29,15 +29,18 @@ public class PlayerManager { this.server = server; } - public synchronized ServerPlayer register(ClientCommunicationHandler handler, String username) { - Team team = findBestTeamForNewPlayer(); - ServerPlayer player = new ServerPlayer(nextClientId++, username, team, PlayerMode.NORMAL); - var inv = player.getInventory(); - inv.getItemStacks().add(new GunItemStack(ItemTypes.RIFLE)); - inv.getItemStacks().add(new GunItemStack(ItemTypes.AK_47)); - inv.getItemStacks().add(new GunItemStack(ItemTypes.WINCHESTER)); - inv.getItemStacks().add(new BlockItemStack(ItemTypes.BLOCK, 50, (byte) 1)); - inv.setSelectedIndex(0); + public synchronized ServerPlayer register(ClientCommunicationHandler handler, String username, boolean spectator) { + PlayerMode mode = spectator ? PlayerMode.SPECTATOR : PlayerMode.NORMAL; + Team team = mode != PlayerMode.NORMAL ? null : findBestTeamForNewPlayer(); + ServerPlayer player = new ServerPlayer(nextClientId++, username, team, mode); + if (player.getMode() == PlayerMode.NORMAL || player.getMode() == PlayerMode.CREATIVE) { + var inv = player.getInventory(); + inv.getItemStacks().add(new GunItemStack(ItemTypes.RIFLE)); + inv.getItemStacks().add(new GunItemStack(ItemTypes.AK_47)); + inv.getItemStacks().add(new GunItemStack(ItemTypes.WINCHESTER)); + inv.getItemStacks().add(new BlockItemStack(ItemTypes.BLOCK, 50, (byte) 1)); + inv.setSelectedIndex(0); + } System.out.printf("Registered player \"%s\" with id %d.%n", player.getUsername(), player.getId()); players.put(player.getId(), player); @@ -57,11 +60,13 @@ public class PlayerManager { player.getVelocity().x(), player.getVelocity().y(), player.getVelocity().z(), player.getOrientation().x(), player.getOrientation().y(), player.isCrouching(), - player.getInventory().getSelectedItemStack().getType().getId(), + player.getInventory().getSelectedItemStack() == null ? -1 : player.getInventory().getSelectedItemStack().getType().getId(), player.getInventory().getSelectedBlockValue(), player.getMode() ), player); - broadcastTcpMessageToAllBut(ChatMessage.announce(joinMessage), player); + if (player.getMode() != PlayerMode.SPECTATOR) { + broadcastTcpMessageToAllBut(ChatMessage.announce(joinMessage), player); + } return player; }