134 lines
4.4 KiB
Java
134 lines
4.4 KiB
Java
package nl.andrewlalis.aos_client;
|
|
|
|
import nl.andrewlalis.aos_core.net.*;
|
|
import nl.andrewlalis.aos_core.net.chat.ChatMessage;
|
|
|
|
import javax.swing.*;
|
|
import java.io.*;
|
|
import java.net.Socket;
|
|
import java.net.SocketException;
|
|
import java.nio.ByteBuffer;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.Executors;
|
|
|
|
/**
|
|
* This thread is responsible for handling TCP message communication with the
|
|
* server.
|
|
*/
|
|
public class MessageTransceiver extends Thread {
|
|
private final Client client;
|
|
|
|
private final Socket socket;
|
|
private final DataTransceiver dataTransceiver;
|
|
private final ObjectOutputStream out;
|
|
private final ObjectInputStream in;
|
|
private final ExecutorService writeService = Executors.newFixedThreadPool(1);
|
|
|
|
private volatile boolean running = true;
|
|
|
|
public MessageTransceiver(Client client, String serverHost, int serverPort, String username) throws IOException {
|
|
this.client = client;
|
|
this.socket = new Socket(serverHost, serverPort);
|
|
this.dataTransceiver = new DataTransceiver(client, this.socket.getInetAddress(), this.socket.getPort());
|
|
this.out = new ObjectOutputStream(this.socket.getOutputStream());
|
|
this.in = new ObjectInputStream(this.socket.getInputStream());
|
|
this.initializeConnection(username);
|
|
}
|
|
|
|
/**
|
|
* Initializes the TCP connection to the server. This involves sending an
|
|
* IDENT packet containing some data the server needs about this client, and
|
|
* waiting for a {@link PlayerRegisteredMessage} response from the server,
|
|
* which contains the basic data we need to start the game.
|
|
* @param username The username for this client.
|
|
* @throws IOException If the connection could not be initialized.
|
|
*/
|
|
private void initializeConnection(String username) throws IOException {
|
|
boolean established = false;
|
|
int attempts = 0;
|
|
while (!established && attempts < 100) {
|
|
this.send(new IdentMessage(username, this.dataTransceiver.getLocalPort()));
|
|
try {
|
|
Object obj = this.in.readObject();
|
|
if (obj instanceof PlayerRegisteredMessage msg) {
|
|
this.client.setPlayer(msg.getPlayer());
|
|
this.client.setWorld(msg.getWorld());
|
|
established = true;
|
|
} else if (obj instanceof ConnectionRejectedMessage msg) {
|
|
throw new IOException(msg.getMessage());
|
|
}
|
|
} catch (ClassNotFoundException e) {
|
|
e.printStackTrace();
|
|
}
|
|
attempts++;
|
|
}
|
|
if (!established) {
|
|
throw new IOException("Could not initialize connection to server in " + attempts + " attempts.");
|
|
}
|
|
}
|
|
|
|
public void shutdown() {
|
|
this.running = false;
|
|
this.dataTransceiver.shutdown();
|
|
this.writeService.shutdown();
|
|
try {
|
|
this.out.close();
|
|
this.in.close();
|
|
this.socket.close();
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
public void send(Message message) {
|
|
if (this.socket.isClosed()) return;
|
|
this.writeService.submit(() -> {
|
|
try {
|
|
this.out.reset();
|
|
this.out.writeObject(message);
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
});
|
|
}
|
|
|
|
public void sendData(byte type, int playerId, byte[] data) throws IOException {
|
|
ByteBuffer buffer = ByteBuffer.allocate(1 + Integer.BYTES + data.length);
|
|
buffer.put(type);
|
|
buffer.putInt(playerId);
|
|
buffer.put(data);
|
|
this.dataTransceiver.send(buffer.array());
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
this.dataTransceiver.start();
|
|
while (this.running) {
|
|
try {
|
|
Message msg = (Message) this.in.readObject();
|
|
if (msg.getType() == Type.CHAT) {
|
|
this.client.getChatManager().addChatMessage((ChatMessage) msg);
|
|
} else if (msg.getType() == Type.PLAYER_JOINED && this.client.getWorld() != null) {
|
|
PlayerUpdateMessage pum = (PlayerUpdateMessage) msg;
|
|
this.client.getWorld().getPlayers().put(pum.getPlayer().getId(), pum.getPlayer());
|
|
} else if (msg.getType() == Type.PLAYER_LEFT && this.client.getWorld() != null) {
|
|
PlayerUpdateMessage pum = (PlayerUpdateMessage) msg;
|
|
this.client.getWorld().getPlayers().remove(pum.getPlayer().getId());
|
|
} else if (msg.getType() == Type.SERVER_SHUTDOWN) {
|
|
this.client.shutdown();
|
|
JOptionPane.showMessageDialog(null, "Server has been shut down.", "Server Shutdown", JOptionPane.WARNING_MESSAGE);
|
|
}
|
|
} catch (StreamCorruptedException | EOFException e) {
|
|
this.shutdown();
|
|
} catch (SocketException e) {
|
|
if (!e.getMessage().equalsIgnoreCase("Socket closed")) {
|
|
e.printStackTrace();
|
|
}
|
|
this.shutdown();
|
|
} catch (IOException | ClassNotFoundException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
}
|