diff --git a/client/pom.xml b/client/pom.xml
index 3d11303..7324c97 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -5,7 +5,7 @@
ace-of-shades
nl.andrewlalis
- 1.0
+ 2.0
4.0.0
diff --git a/client/src/main/java/nl/andrewlalis/aos_client/Client.java b/client/src/main/java/nl/andrewlalis/aos_client/Client.java
index 10837a4..62b3993 100644
--- a/client/src/main/java/nl/andrewlalis/aos_client/Client.java
+++ b/client/src/main/java/nl/andrewlalis/aos_client/Client.java
@@ -2,18 +2,17 @@ package nl.andrewlalis.aos_client;
import nl.andrewlalis.aos_client.view.GameFrame;
import nl.andrewlalis.aos_client.view.GamePanel;
+import nl.andrewlalis.aos_core.model.Player;
import nl.andrewlalis.aos_core.model.PlayerControlState;
import nl.andrewlalis.aos_core.model.World;
-import nl.andrewlalis.aos_core.net.ChatMessage;
+import nl.andrewlalis.aos_core.net.PlayerControlStateMessage;
+import nl.andrewlalis.aos_core.net.chat.ChatMessage;
+import nl.andrewlalis.aos_core.net.chat.PlayerChatMessage;
import javax.swing.*;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.ObjectOutputStream;
-import java.net.DatagramPacket;
import java.util.LinkedList;
import java.util.List;
-import java.util.concurrent.ThreadLocalRandom;
/**
* The main class for the client, which connects to a server to join and play.
@@ -21,15 +20,13 @@ import java.util.concurrent.ThreadLocalRandom;
public class Client {
public static final int MAX_CHAT_MESSAGES = 10;
- private final int udpPort;
- private DatagramReceiver datagramReceiver;
private MessageTransceiver messageTransceiver;
private int playerId;
private PlayerControlState playerControlState;
private World world;
- private final List chatMessages;
+ private final List chatMessages;
private boolean chatting = false;
private final StringBuilder chatBuffer;
@@ -37,8 +34,7 @@ public class Client {
private final GamePanel gamePanel;
private final SoundManager soundManager;
- public Client(int udpPort) {
- this.udpPort = udpPort;
+ public Client() {
this.chatMessages = new LinkedList<>();
this.chatBuffer = new StringBuilder();
this.soundManager = new SoundManager();
@@ -47,13 +43,11 @@ public class Client {
}
public void connect(String serverHost, int serverPort, String username) throws IOException, ClassNotFoundException {
- this.datagramReceiver = new DatagramReceiver(this, this.udpPort);
- this.datagramReceiver.start();
this.messageTransceiver = new MessageTransceiver(this);
- this.messageTransceiver.connectToServer(serverHost, serverPort, username, this.udpPort);
+ this.messageTransceiver.connectToServer(serverHost, serverPort, username);
this.messageTransceiver.start();
- while (this.playerControlState == null) {
+ while (this.playerControlState == null || this.world == null) {
try {
System.out.println("Waiting for server response and player registration...");
Thread.sleep(100);
@@ -62,6 +56,7 @@ public class Client {
}
}
+ System.out.println("Player and world data initialized.");
GameFrame g = new GameFrame("Ace of Shades - " + serverHost + ":" + serverPort, this, this.gamePanel);
g.setVisible(true);
this.renderer.start();
@@ -94,27 +89,24 @@ public class Client {
public void sendPlayerState() {
try {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(bos);
- oos.writeObject(this.playerControlState);
- byte[] buffer = bos.toByteArray();
- DatagramPacket packet = new DatagramPacket(buffer, buffer.length, this.messageTransceiver.getRemoteAddress(), this.messageTransceiver.getPort());
- this.datagramReceiver.getDatagramSocket().send(packet);
+ this.messageTransceiver.send(new PlayerControlStateMessage(this.playerControlState));
} catch (IOException e) {
e.printStackTrace();
}
}
- public synchronized void addChatMessage(String text) {
- this.chatMessages.add(text);
- this.soundManager.play("chat.wav");
+ public synchronized void addChatMessage(ChatMessage message) {
+ this.chatMessages.add(message);
+ if (message.getClass() == PlayerChatMessage.class) {
+ this.soundManager.play("chat.wav");
+ }
while (this.chatMessages.size() > MAX_CHAT_MESSAGES) {
this.chatMessages.remove(0);
}
}
- public String[] getLatestChatMessages() {
- return this.chatMessages.toArray(new String[0]);
+ public ChatMessage[] getLatestChatMessages() {
+ return this.chatMessages.toArray(new ChatMessage[0]);
}
public boolean isChatting() {
@@ -140,7 +132,7 @@ public class Client {
public void sendChat() {
try {
- this.messageTransceiver.send(new ChatMessage(this.chatBuffer.toString()));
+ this.messageTransceiver.send(new PlayerChatMessage(this.playerId, this.chatBuffer.toString()));
} catch (IOException e) {
e.printStackTrace();
}
@@ -152,7 +144,6 @@ public class Client {
}
public void shutdown() {
- this.datagramReceiver.shutdown();
this.messageTransceiver.shutdown();
this.renderer.shutdown();
}
@@ -160,21 +151,18 @@ public class Client {
public static void main(String[] args) {
- // Randomly choose a high-level UDP port that's probably open.
- int udpPort = 20000 + ThreadLocalRandom.current().nextInt(0, 10000);
+// String hostAndPort = JOptionPane.showInputDialog("Enter server host and port (host:port):");
+// if (hostAndPort == null) throw new IllegalArgumentException("A host and port is required.");
+// String[] parts = hostAndPort.split(":");
+// if (parts.length != 2) throw new IllegalArgumentException("Invalid host:port.");
+// String host = parts[0].trim();
+// int port = Integer.parseInt(parts[1]);
+// String username = JOptionPane.showInputDialog("Enter a username:");
+// if (username == null || username.isBlank()) throw new IllegalArgumentException("Username is required.");
- String hostAndPort = JOptionPane.showInputDialog("Enter server host and port (host:port):");
- if (hostAndPort == null) throw new IllegalArgumentException("A host and port is required.");
- String[] parts = hostAndPort.split(":");
- if (parts.length != 2) throw new IllegalArgumentException("Invalid host:port.");
- String host = parts[0].trim();
- int port = Integer.parseInt(parts[1]);
- String username = JOptionPane.showInputDialog("Enter a username:");
- if (username == null || username.isBlank()) throw new IllegalArgumentException("Username is required.");
-
- Client client = new Client(udpPort);
+ Client client = new Client();
try {
- client.connect(host, port, username);
+ client.connect("localhost", 8035, "andrew");
} catch (IOException | ClassNotFoundException e) {
client.shutdown();
e.printStackTrace();
diff --git a/client/src/main/java/nl/andrewlalis/aos_client/DatagramReceiver.java b/client/src/main/java/nl/andrewlalis/aos_client/DatagramReceiver.java
deleted file mode 100644
index 3b1bc62..0000000
--- a/client/src/main/java/nl/andrewlalis/aos_client/DatagramReceiver.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package nl.andrewlalis.aos_client;
-
-import nl.andrewlalis.aos_core.model.World;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.SocketException;
-
-public class DatagramReceiver extends Thread {
- private final DatagramSocket datagramSocket;
- private final Client client;
-
- private volatile boolean running;
-
- public DatagramReceiver(Client client, int port) throws SocketException {
- this.datagramSocket = new DatagramSocket(port);
- this.client = client;
- }
-
- public DatagramSocket getDatagramSocket() {
- return datagramSocket;
- }
-
- public void shutdown() {
- this.running = false;
- this.datagramSocket.close();
- }
-
- @Override
- public void run() {
- this.running = true;
- byte[] buffer = new byte[8192];
- DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
- while (this.running) {
- try {
- this.datagramSocket.receive(packet);
- ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(packet.getData()));
- Object obj = ois.readObject();
- if (obj instanceof World) {
- this.client.setWorld((World) obj);
- }
- } catch (IOException | ClassNotFoundException e) {
- // Ignore any receive exception.d
- }
- }
- }
-}
diff --git a/client/src/main/java/nl/andrewlalis/aos_client/MessageTransceiver.java b/client/src/main/java/nl/andrewlalis/aos_client/MessageTransceiver.java
index e8839ed..d4ac63a 100644
--- a/client/src/main/java/nl/andrewlalis/aos_client/MessageTransceiver.java
+++ b/client/src/main/java/nl/andrewlalis/aos_client/MessageTransceiver.java
@@ -1,12 +1,15 @@
package nl.andrewlalis.aos_client;
+import nl.andrewlalis.aos_core.model.World;
import nl.andrewlalis.aos_core.net.*;
+import nl.andrewlalis.aos_core.net.chat.ChatMessage;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.net.InetAddress;
+import java.io.StreamCorruptedException;
import java.net.Socket;
+import java.net.SocketException;
/**
* This thread is responsible for handling TCP message communication with the
@@ -25,11 +28,12 @@ public class MessageTransceiver extends Thread {
this.client = client;
}
- public void connectToServer(String serverHost, int serverPort, String username, int udpPort) throws IOException, ClassNotFoundException {
+ public void connectToServer(String serverHost, int serverPort, String username) throws IOException {
this.socket = new Socket(serverHost, serverPort);
this.out = new ObjectOutputStream(this.socket.getOutputStream());
this.in = new ObjectInputStream(this.socket.getInputStream());
- this.send(new IdentMessage(username, udpPort));
+ this.send(new IdentMessage(username));
+ System.out.println("Sent identification packet.");
}
public void shutdown() {
@@ -43,15 +47,8 @@ public class MessageTransceiver extends Thread {
}
}
- public InetAddress getRemoteAddress() {
- return this.socket != null ? this.socket.getInetAddress() : null;
- }
-
- public int getPort() {
- return this.socket.getPort();
- }
-
- public void send(Message message) throws IOException {
+ public synchronized void send(Message message) throws IOException {
+ this.out.reset();
this.out.writeObject(message);
}
@@ -64,10 +61,20 @@ public class MessageTransceiver extends Thread {
PlayerRegisteredMessage prm = (PlayerRegisteredMessage) msg;
this.client.initPlayerData(prm.getPlayerId());
} else if (msg.getType() == Type.CHAT) {
- this.client.addChatMessage(((ChatMessage) msg).getText());
+ this.client.addChatMessage((ChatMessage) msg);
+ } else if (msg.getType() == Type.WORLD_UPDATE) {
+ World world = ((WorldUpdateMessage) msg).getWorld();
+ this.client.setWorld(world);
+ }
+ } catch (StreamCorruptedException e) {
+ e.printStackTrace();
+ this.running = false;
+ } catch (SocketException e) {
+ if (!e.getMessage().equalsIgnoreCase("Socket closed")) {
+ e.printStackTrace();
}
} catch (IOException | ClassNotFoundException e) {
- // Ignore exceptions.
+ e.printStackTrace();
}
}
}
diff --git a/client/src/main/java/nl/andrewlalis/aos_client/view/GamePanel.java b/client/src/main/java/nl/andrewlalis/aos_client/view/GamePanel.java
index 5f073d6..3c4b313 100644
--- a/client/src/main/java/nl/andrewlalis/aos_client/view/GamePanel.java
+++ b/client/src/main/java/nl/andrewlalis/aos_client/view/GamePanel.java
@@ -2,6 +2,9 @@ package nl.andrewlalis.aos_client.view;
import nl.andrewlalis.aos_client.Client;
import nl.andrewlalis.aos_core.model.*;
+import nl.andrewlalis.aos_core.net.chat.ChatMessage;
+import nl.andrewlalis.aos_core.net.chat.PlayerChatMessage;
+import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
import javax.swing.*;
import java.awt.*;
@@ -44,7 +47,7 @@ public class GamePanel extends JPanel {
World world = client.getWorld();
if (world != null) drawWorld(g2, world);
- drawChat(g2, client.getLatestChatMessages());
+ drawChat(g2, world);
}
private void drawWorld(Graphics2D g2, World world) {
@@ -142,16 +145,35 @@ public class GamePanel extends JPanel {
}
}
- private void drawChat(Graphics2D g2, String[] messages) {
+ private void drawChat(Graphics2D g2, World world) {
int height = g2.getFontMetrics().getHeight();
int y = height;
- g2.setColor(Color.WHITE);
- for (String message : messages) {
- g2.drawString(message, 5, y);
+ for (ChatMessage message : this.client.getLatestChatMessages()) {
+ Color color = Color.WHITE;
+ String text = message.getText();
+ if (message instanceof SystemChatMessage sysMsg) {
+ if (sysMsg.getLevel() == SystemChatMessage.Level.INFO) {
+ color = Color.YELLOW;
+ } else if (sysMsg.getLevel() == SystemChatMessage.Level.WARNING) {
+ color = Color.ORANGE;
+ } else if (sysMsg.getLevel() == SystemChatMessage.Level.SEVERE) {
+ color = Color.RED;
+ }
+ } else if (message instanceof PlayerChatMessage pcm) {
+ String author = Integer.toString(pcm.getPlayerId());
+ if (world != null) {
+ Player p = world.getPlayers().get(pcm.getPlayerId());
+ if (p != null) author = p.getName();
+ }
+ text = author + ": " + text;
+ }
+ g2.setColor(color);
+ g2.drawString(text, 5, y);
y += height;
}
if (this.client.isChatting()) {
+ g2.setColor(Color.WHITE);
g2.drawString("> " + this.client.getCurrentChatBuffer(), 5, height * 11);
}
}
diff --git a/core/pom.xml b/core/pom.xml
index 821b737..a6e3e74 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -5,7 +5,7 @@
ace-of-shades
nl.andrewlalis
- 1.0
+ 2.0
4.0.0
diff --git a/core/src/main/java/module-info.java b/core/src/main/java/module-info.java
index 3ce9b66..84ddf00 100644
--- a/core/src/main/java/module-info.java
+++ b/core/src/main/java/module-info.java
@@ -3,4 +3,5 @@ module aos_core {
exports nl.andrewlalis.aos_core.net to aos_server, aos_client;
exports nl.andrewlalis.aos_core.model to aos_server, aos_client;
exports nl.andrewlalis.aos_core.geom to aos_server, aos_client;
+ exports nl.andrewlalis.aos_core.net.chat to aos_client, aos_server;
}
\ No newline at end of file
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/net/IdentMessage.java b/core/src/main/java/nl/andrewlalis/aos_core/net/IdentMessage.java
index a603834..647c865 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/net/IdentMessage.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/net/IdentMessage.java
@@ -2,19 +2,13 @@ package nl.andrewlalis.aos_core.net;
public class IdentMessage extends Message {
private final String name;
- private final int datagramPort;
- public IdentMessage(String name, int datagramPort) {
+ public IdentMessage(String name) {
super(Type.IDENT);
this.name = name;
- this.datagramPort = datagramPort;
}
public String getName() {
return name;
}
-
- public int getDatagramPort() {
- return datagramPort;
- }
}
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/net/PlayerControlStateMessage.java b/core/src/main/java/nl/andrewlalis/aos_core/net/PlayerControlStateMessage.java
new file mode 100644
index 0000000..10f3a52
--- /dev/null
+++ b/core/src/main/java/nl/andrewlalis/aos_core/net/PlayerControlStateMessage.java
@@ -0,0 +1,16 @@
+package nl.andrewlalis.aos_core.net;
+
+import nl.andrewlalis.aos_core.model.PlayerControlState;
+
+public class PlayerControlStateMessage extends Message {
+ private final PlayerControlState playerControlState;
+
+ public PlayerControlStateMessage(PlayerControlState pcs) {
+ super(Type.PLAYER_CONTROL_STATE);
+ this.playerControlState = pcs;
+ }
+
+ public PlayerControlState getPlayerControlState() {
+ return playerControlState;
+ }
+}
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/net/Type.java b/core/src/main/java/nl/andrewlalis/aos_core/net/Type.java
index e226d1e..a298e47 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/net/Type.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/net/Type.java
@@ -4,5 +4,7 @@ public enum Type {
IDENT,
ACK,
PLAYER_REGISTERED,
- CHAT
+ CHAT,
+ PLAYER_CONTROL_STATE,
+ WORLD_UPDATE
}
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/net/WorldUpdateMessage.java b/core/src/main/java/nl/andrewlalis/aos_core/net/WorldUpdateMessage.java
new file mode 100644
index 0000000..6c29931
--- /dev/null
+++ b/core/src/main/java/nl/andrewlalis/aos_core/net/WorldUpdateMessage.java
@@ -0,0 +1,15 @@
+package nl.andrewlalis.aos_core.net;
+
+import nl.andrewlalis.aos_core.model.World;
+
+public class WorldUpdateMessage extends Message {
+ private final World world;
+ public WorldUpdateMessage(World world) {
+ super(Type.WORLD_UPDATE);
+ this.world = world;
+ }
+
+ public World getWorld() {
+ return world;
+ }
+}
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/net/ChatMessage.java b/core/src/main/java/nl/andrewlalis/aos_core/net/chat/ChatMessage.java
similarity index 60%
rename from core/src/main/java/nl/andrewlalis/aos_core/net/ChatMessage.java
rename to core/src/main/java/nl/andrewlalis/aos_core/net/chat/ChatMessage.java
index 3c3f333..8fc740b 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/net/ChatMessage.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/net/chat/ChatMessage.java
@@ -1,4 +1,7 @@
-package nl.andrewlalis.aos_core.net;
+package nl.andrewlalis.aos_core.net.chat;
+
+import nl.andrewlalis.aos_core.net.Message;
+import nl.andrewlalis.aos_core.net.Type;
public class ChatMessage extends Message {
private final String text;
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/net/chat/CommandMessage.java b/core/src/main/java/nl/andrewlalis/aos_core/net/chat/CommandMessage.java
new file mode 100644
index 0000000..7a4758a
--- /dev/null
+++ b/core/src/main/java/nl/andrewlalis/aos_core/net/chat/CommandMessage.java
@@ -0,0 +1,7 @@
+package nl.andrewlalis.aos_core.net.chat;
+
+public class CommandMessage extends PlayerChatMessage {
+ public CommandMessage(int id, String text) {
+ super(id, text);
+ }
+}
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/net/chat/PlayerChatMessage.java b/core/src/main/java/nl/andrewlalis/aos_core/net/chat/PlayerChatMessage.java
new file mode 100644
index 0000000..67acafe
--- /dev/null
+++ b/core/src/main/java/nl/andrewlalis/aos_core/net/chat/PlayerChatMessage.java
@@ -0,0 +1,14 @@
+package nl.andrewlalis.aos_core.net.chat;
+
+public class PlayerChatMessage extends ChatMessage {
+ private final int playerId;
+
+ public PlayerChatMessage(int id, String text) {
+ super(text);
+ this.playerId = id;
+ }
+
+ public int getPlayerId() {
+ return playerId;
+ }
+}
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/net/chat/SystemChatMessage.java b/core/src/main/java/nl/andrewlalis/aos_core/net/chat/SystemChatMessage.java
new file mode 100644
index 0000000..4e4ece8
--- /dev/null
+++ b/core/src/main/java/nl/andrewlalis/aos_core/net/chat/SystemChatMessage.java
@@ -0,0 +1,16 @@
+package nl.andrewlalis.aos_core.net.chat;
+
+public class SystemChatMessage extends ChatMessage {
+ public enum Level {INFO, WARNING, SEVERE}
+
+ private final Level level;
+
+ public SystemChatMessage(Level level, String text) {
+ super(text);
+ this.level = level;
+ }
+
+ public Level getLevel() {
+ return level;
+ }
+}
diff --git a/pom.xml b/pom.xml
index 591d6fc..97cfe50 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
nl.andrewlalis
ace-of-shades
pom
- 1.0
+ 2.0
server
client
diff --git a/server/pom.xml b/server/pom.xml
index 9a53385..c61a47e 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -5,7 +5,7 @@
ace-of-shades
nl.andrewlalis
- 1.0
+ 2.0
4.0.0
diff --git a/server/src/main/java/nl/andrewlalis/aos_server/ClientHandler.java b/server/src/main/java/nl/andrewlalis/aos_server/ClientHandler.java
index 8fbff1d..3b6228a 100644
--- a/server/src/main/java/nl/andrewlalis/aos_server/ClientHandler.java
+++ b/server/src/main/java/nl/andrewlalis/aos_server/ClientHandler.java
@@ -1,6 +1,7 @@
package nl.andrewlalis.aos_server;
import nl.andrewlalis.aos_core.net.*;
+import nl.andrewlalis.aos_core.net.chat.ChatMessage;
import java.io.IOException;
import java.io.ObjectInputStream;
@@ -13,7 +14,6 @@ public class ClientHandler extends Thread {
private final ObjectOutputStream out;
private final ObjectInputStream in;
- private int datagramPort = -1;
private int playerId;
private volatile boolean running = true;
@@ -25,14 +25,6 @@ public class ClientHandler extends Thread {
this.in = new ObjectInputStream(socket.getInputStream());
}
- public Socket getSocket() {
- return socket;
- }
-
- public int getDatagramPort() {
- return datagramPort;
- }
-
public int getPlayerId() {
return playerId;
}
@@ -41,7 +33,8 @@ public class ClientHandler extends Thread {
this.running = false;
}
- public void send(Message message) throws IOException {
+ public synchronized void send(Message message) throws IOException {
+ this.out.reset();
this.out.writeObject(message);
}
@@ -53,12 +46,11 @@ public class ClientHandler extends Thread {
Message msg = (Message) this.in.readObject();
if (msg.getType() == Type.IDENT) {
IdentMessage ident = (IdentMessage) msg;
- int id = this.server.registerNewPlayer(ident.getName());
- this.playerId = id;
- this.datagramPort = ident.getDatagramPort();
- this.send(new PlayerRegisteredMessage(id));
+ this.playerId = this.server.registerNewPlayer(ident.getName(), this);
} else if (msg.getType() == Type.CHAT) {
this.server.broadcastPlayerChat(this.playerId, (ChatMessage) msg);
+ } else if (msg.getType() == Type.PLAYER_CONTROL_STATE) {
+ this.server.updatePlayerState(((PlayerControlStateMessage) msg).getPlayerControlState());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
@@ -67,7 +59,6 @@ public class ClientHandler extends Thread {
} catch (IOException e) {
// Ignore this exception, consider the client disconnected.
}
- this.datagramPort = -1;
try {
this.socket.close();
} catch (IOException e) {
diff --git a/server/src/main/java/nl/andrewlalis/aos_server/DatagramCommunicationThread.java b/server/src/main/java/nl/andrewlalis/aos_server/DatagramCommunicationThread.java
deleted file mode 100644
index bb7dd09..0000000
--- a/server/src/main/java/nl/andrewlalis/aos_server/DatagramCommunicationThread.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package nl.andrewlalis.aos_server;
-
-import nl.andrewlalis.aos_core.model.PlayerControlState;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.SocketException;
-
-public class DatagramCommunicationThread extends Thread {
- private final Server server;
- private final DatagramSocket socket;
-
- public DatagramCommunicationThread(Server server, int port) throws SocketException {
- this.server = server;
- this.socket = new DatagramSocket(port);
- }
-
- public DatagramSocket getSocket() {
- return socket;
- }
-
- @Override
- public void run() {
- byte[] buffer = new byte[8192];
- DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
- while (true) {
- try {
- this.socket.receive(packet);
- Object obj = new ObjectInputStream(new ByteArrayInputStream(buffer)).readObject();
- if (obj instanceof PlayerControlState) {
- this.server.updatePlayerState((PlayerControlState) obj);
- }
- } catch (IOException | ClassNotFoundException e) {
- e.printStackTrace();
- }
- }
- }
-}
diff --git a/server/src/main/java/nl/andrewlalis/aos_server/Server.java b/server/src/main/java/nl/andrewlalis/aos_server/Server.java
index 2cab056..ed58659 100644
--- a/server/src/main/java/nl/andrewlalis/aos_server/Server.java
+++ b/server/src/main/java/nl/andrewlalis/aos_server/Server.java
@@ -2,19 +2,20 @@ package nl.andrewlalis.aos_server;
import nl.andrewlalis.aos_core.geom.Vec2;
import nl.andrewlalis.aos_core.model.*;
-import nl.andrewlalis.aos_core.net.ChatMessage;
import nl.andrewlalis.aos_core.net.Message;
+import nl.andrewlalis.aos_core.net.PlayerRegisteredMessage;
+import nl.andrewlalis.aos_core.net.WorldUpdateMessage;
+import nl.andrewlalis.aos_core.net.chat.ChatMessage;
+import nl.andrewlalis.aos_core.net.chat.PlayerChatMessage;
+import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
import java.awt.*;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.ObjectOutputStream;
-import java.net.DatagramPacket;
import java.net.ServerSocket;
import java.net.Socket;
-import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ThreadLocalRandom;
public class Server {
@@ -22,14 +23,12 @@ public class Server {
private final List clientHandlers;
private final ServerSocket serverSocket;
- private final DatagramCommunicationThread datagramCommunicationThread;
private final World world;
private final WorldUpdater worldUpdater;
public Server(int port) throws IOException {
- this.clientHandlers = new ArrayList<>();
+ this.clientHandlers = new CopyOnWriteArrayList<>();
this.serverSocket = new ServerSocket(port);
- this.datagramCommunicationThread = new DatagramCommunicationThread(this, port);
this.world = new World(new Vec2(50, 70));
world.getBarricades().add(new Barricade(10, 10, 30, 5));
@@ -42,19 +41,17 @@ public class Server {
world.getTeams().add(new Team("Blue", Color.BLUE, new Vec2(world.getSize().x() - 3, world.getSize().y() - 3), new Vec2(0, -1)));
this.worldUpdater = new WorldUpdater(this, this.world);
- System.out.println("Started AOS-Server TCP/UDP on port " + port);
+ System.out.println("Started AOS-Server TCP on port " + port);
}
public void acceptClientConnection() throws IOException {
Socket socket = this.serverSocket.accept();
var t = new ClientHandler(this, socket);
t.start();
- synchronized (this.clientHandlers) {
- this.clientHandlers.add(t);
- }
+ this.clientHandlers.add(t);
}
- public int registerNewPlayer(String name) {
+ public int registerNewPlayer(String name, ClientHandler handler) {
int id = ThreadLocalRandom.current().nextInt(1, Integer.MAX_VALUE);
Team team = null;
for (Team t : this.world.getTeams()) {
@@ -65,48 +62,46 @@ public class Server {
}
}
Player p = new Player(id, name, team);
- System.out.println("Client connected: " + p.getId() + ", " + p.getName());
- this.broadcastMessage(new ChatMessage(name + " connected."));
this.world.getPlayers().put(p.getId(), p);
+ try {
+ handler.send(new PlayerRegisteredMessage(id));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ String message = p.getName() + " connected.";
+ this.broadcastMessage(new SystemChatMessage(SystemChatMessage.Level.INFO, message));
+ System.out.println(message);
p.setPosition(new Vec2(this.world.getSize().x() / 2.0, this.world.getSize().y() / 2.0));
if (team != null) {
team.getPlayers().add(p);
p.setPosition(team.getSpawnPoint());
p.setOrientation(team.getOrientation());
- this.broadcastMessage(new ChatMessage(name + " joined team " + team.getName()));
- System.out.println("Player joined team " + team.getName());
+ message = name + " joined team " + team.getName() + ".";
+ this.broadcastMessage(new SystemChatMessage(SystemChatMessage.Level.INFO, message));
}
return id;
}
public void clientDisconnected(ClientHandler clientHandler) {
Player player = this.world.getPlayers().get(clientHandler.getPlayerId());
- synchronized (this.clientHandlers) {
- this.clientHandlers.remove(clientHandler);
- clientHandler.shutdown();
- }
+ this.clientHandlers.remove(clientHandler);
+ clientHandler.shutdown();
this.world.getPlayers().remove(player.getId());
if (player.getTeam() != null) {
player.getTeam().getPlayers().remove(player);
}
- this.broadcastMessage(new ChatMessage(player.getName() + " disconnected."));
- System.out.println("Client disconnected: " + player.getId() + ", " + player.getName());
+ String message = player.getName() + " disconnected.";
+ this.broadcastMessage(new SystemChatMessage(SystemChatMessage.Level.INFO, message));
+ System.out.println(message);
}
public void sendWorldToClients() {
- try {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- new ObjectOutputStream(bos).writeObject(this.world);
- byte[] data = bos.toByteArray();
- DatagramPacket packet = new DatagramPacket(data, data.length);
- for (ClientHandler handler : this.clientHandlers) {
- if (handler.getDatagramPort() == -1) continue;
- packet.setAddress(handler.getSocket().getInetAddress());
- packet.setPort(handler.getDatagramPort());
- this.datagramCommunicationThread.getSocket().send(packet);
+ for (ClientHandler handler : this.clientHandlers) {
+ try {
+ handler.send(new WorldUpdateMessage(this.world));
+ } catch (IOException e) {
+ e.printStackTrace();
}
- } catch (Exception e) {
- e.printStackTrace();
}
}
@@ -130,7 +125,7 @@ public class Server {
public void broadcastPlayerChat(int playerId, ChatMessage msg) {
Player p = this.world.getPlayers().get(playerId);
if (p == null) return;
- this.broadcastMessage(new ChatMessage(p.getName() + ": " + msg.getText()));
+ this.broadcastMessage(new PlayerChatMessage(p.getId(), msg.getText()));
}
@@ -150,12 +145,9 @@ public class Server {
}
Server server = new Server(port);
- server.datagramCommunicationThread.start();
server.worldUpdater.start();
while (true) {
server.acceptClientConnection();
}
}
-
-
}
diff --git a/server/src/main/java/nl/andrewlalis/aos_server/WorldUpdater.java b/server/src/main/java/nl/andrewlalis/aos_server/WorldUpdater.java
index 18868d7..02e9c48 100644
--- a/server/src/main/java/nl/andrewlalis/aos_server/WorldUpdater.java
+++ b/server/src/main/java/nl/andrewlalis/aos_server/WorldUpdater.java
@@ -5,7 +5,7 @@ import nl.andrewlalis.aos_core.model.Barricade;
import nl.andrewlalis.aos_core.model.Bullet;
import nl.andrewlalis.aos_core.model.Player;
import nl.andrewlalis.aos_core.model.World;
-import nl.andrewlalis.aos_core.net.ChatMessage;
+import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
import java.util.ArrayList;
import java.util.List;
@@ -155,7 +155,7 @@ public class WorldUpdater extends Thread {
double dist = p.getPosition().dist(new Vec2(x1 + n * (x2 - x1), y1 + n * (y2 - y1)));
if (dist < Player.RADIUS) {
Player killer = this.world.getPlayers().get(b.getPlayerId());
- this.server.broadcastMessage(new ChatMessage(p.getName() + " was shot by " + killer.getName() + "."));
+ this.server.broadcastMessage(new SystemChatMessage(SystemChatMessage.Level.SEVERE, p.getName() + " was shot by " + killer.getName() + "."));
world.getSoundsToPlay().add("death.wav");
if (p.getTeam() != null) {
p.setPosition(p.getTeam().getSpawnPoint());