2022-07-05 19:49:04 +00:00
|
|
|
package nl.andrewl.aos2_server;
|
|
|
|
|
2022-07-09 14:10:19 +00:00
|
|
|
import nl.andrewl.aos_core.model.Chunk;
|
2022-07-06 22:55:26 +00:00
|
|
|
import nl.andrewl.aos_core.model.World;
|
2022-07-07 19:28:37 +00:00
|
|
|
import nl.andrewl.aos_core.model.WorldIO;
|
2022-07-06 18:20:15 +00:00
|
|
|
import nl.andrewl.aos_core.net.UdpReceiver;
|
2022-07-07 14:51:29 +00:00
|
|
|
import nl.andrewl.aos_core.net.udp.ClientInputState;
|
|
|
|
import nl.andrewl.aos_core.net.udp.ClientOrientationState;
|
2022-07-06 18:20:15 +00:00
|
|
|
import nl.andrewl.aos_core.net.udp.DatagramInit;
|
2022-07-07 14:51:29 +00:00
|
|
|
import nl.andrewl.aos_core.net.udp.PlayerUpdateMessage;
|
2022-07-06 18:20:15 +00:00
|
|
|
import nl.andrewl.record_net.Message;
|
2022-07-09 14:10:19 +00:00
|
|
|
import org.joml.Vector3f;
|
2022-07-07 14:51:29 +00:00
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
2022-07-06 18:20:15 +00:00
|
|
|
|
2022-07-05 19:49:04 +00:00
|
|
|
import java.io.IOException;
|
2022-07-06 18:20:15 +00:00
|
|
|
import java.net.*;
|
2022-07-07 19:28:37 +00:00
|
|
|
import java.nio.file.Path;
|
2022-07-09 14:10:19 +00:00
|
|
|
import java.util.Random;
|
2022-07-06 22:55:26 +00:00
|
|
|
import java.util.concurrent.ForkJoinPool;
|
2022-07-05 19:49:04 +00:00
|
|
|
|
|
|
|
public class Server implements Runnable {
|
2022-07-07 14:51:29 +00:00
|
|
|
private static final Logger log = LoggerFactory.getLogger(Server.class);
|
|
|
|
|
2022-07-05 19:49:04 +00:00
|
|
|
private final ServerSocket serverSocket;
|
|
|
|
private final DatagramSocket datagramSocket;
|
|
|
|
private volatile boolean running;
|
|
|
|
|
2022-07-07 14:51:29 +00:00
|
|
|
private final PlayerManager playerManager;
|
2022-07-06 22:55:26 +00:00
|
|
|
private final World world;
|
2022-07-07 14:51:29 +00:00
|
|
|
private final WorldUpdater worldUpdater;
|
2022-07-05 19:49:04 +00:00
|
|
|
|
|
|
|
public Server() throws IOException {
|
|
|
|
this.serverSocket = new ServerSocket(24464, 5);
|
|
|
|
this.serverSocket.setReuseAddress(true);
|
|
|
|
this.datagramSocket = new DatagramSocket(24464);
|
|
|
|
this.datagramSocket.setReuseAddress(true);
|
2022-07-07 14:51:29 +00:00
|
|
|
this.playerManager = new PlayerManager();
|
|
|
|
this.worldUpdater = new WorldUpdater(this, 20);
|
2022-07-06 22:55:26 +00:00
|
|
|
|
|
|
|
// Generate world. TODO: do this elsewhere.
|
2022-07-09 14:10:19 +00:00
|
|
|
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"));
|
2022-07-05 19:49:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
running = true;
|
2022-07-06 18:20:15 +00:00
|
|
|
new Thread(new UdpReceiver(datagramSocket, this::handleUdpMessage)).start();
|
2022-07-07 14:51:29 +00:00
|
|
|
new Thread(worldUpdater).start();
|
|
|
|
log.info("Started AoS2 Server on TCP/UDP port {}; now accepting connections.", serverSocket.getLocalPort());
|
2022-07-05 19:49:04 +00:00
|
|
|
while (running) {
|
|
|
|
acceptClientConnection();
|
|
|
|
}
|
2022-07-07 14:51:29 +00:00
|
|
|
playerManager.deregisterAll();
|
|
|
|
worldUpdater.shutdown();
|
|
|
|
datagramSocket.close(); // Shuts down the UdpReceiver.
|
2022-07-06 22:55:26 +00:00
|
|
|
try {
|
|
|
|
serverSocket.close();
|
|
|
|
} catch (IOException e) {
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
}
|
2022-07-06 18:20:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void handleUdpMessage(Message msg, DatagramPacket packet) {
|
|
|
|
if (msg instanceof DatagramInit init) {
|
2022-07-07 14:51:29 +00:00
|
|
|
playerManager.handleUdpInit(init, packet);
|
|
|
|
} else if (msg instanceof ClientInputState inputState) {
|
|
|
|
ServerPlayer player = playerManager.getPlayer(inputState.clientId());
|
|
|
|
if (player != null) {
|
|
|
|
player.setLastInputState(inputState);
|
|
|
|
}
|
|
|
|
} else if (msg instanceof ClientOrientationState orientationState) {
|
|
|
|
ServerPlayer player = playerManager.getPlayer(orientationState.clientId());
|
|
|
|
if (player != null) {
|
|
|
|
player.setOrientation(orientationState.x(), orientationState.y());
|
2022-07-09 14:10:19 +00:00
|
|
|
playerManager.broadcastUdpMessageToAllBut(new PlayerUpdateMessage(player), player);
|
2022-07-06 18:20:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-05 19:49:04 +00:00
|
|
|
private void acceptClientConnection() {
|
|
|
|
try {
|
|
|
|
Socket clientSocket = serverSocket.accept();
|
2022-07-06 22:55:26 +00:00
|
|
|
var handler = new ClientCommunicationHandler(this, clientSocket, datagramSocket);
|
2022-07-07 14:51:29 +00:00
|
|
|
// Establish the connection in a separate thread so that we can continue accepting clients.
|
2022-07-06 22:55:26 +00:00
|
|
|
ForkJoinPool.commonPool().submit(() -> {
|
|
|
|
try {
|
|
|
|
handler.establishConnection();
|
|
|
|
} catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
});
|
2022-07-05 19:49:04 +00:00
|
|
|
} catch (IOException e) {
|
|
|
|
if (e instanceof SocketException && !this.running && e.getMessage().equalsIgnoreCase("Socket closed")) {
|
|
|
|
return; // Ignore this exception, since it is expected on shutdown.
|
|
|
|
}
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
2022-07-06 18:20:15 +00:00
|
|
|
|
2022-07-07 14:51:29 +00:00
|
|
|
public World getWorld() {
|
|
|
|
return world;
|
|
|
|
}
|
|
|
|
|
|
|
|
public PlayerManager getPlayerManager() {
|
|
|
|
return playerManager;
|
|
|
|
}
|
|
|
|
|
2022-07-06 18:20:15 +00:00
|
|
|
public static void main(String[] args) throws IOException {
|
|
|
|
new Server().run();
|
|
|
|
}
|
2022-07-05 19:49:04 +00:00
|
|
|
}
|