diff --git a/client/src/main/java/nl/andrewl/aos2_client/Client.java b/client/src/main/java/nl/andrewl/aos2_client/Client.java index e1632b7..5703330 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/Client.java +++ b/client/src/main/java/nl/andrewl/aos2_client/Client.java @@ -1,10 +1,12 @@ package nl.andrewl.aos2_client; +import nl.andrewl.aos2_client.config.ClientConfig; import nl.andrewl.aos2_client.control.InputHandler; import nl.andrewl.aos2_client.control.PlayerInputKeyCallback; import nl.andrewl.aos2_client.control.PlayerInputMouseClickCallback; import nl.andrewl.aos2_client.control.PlayerViewCursorCallback; import nl.andrewl.aos2_client.render.GameRenderer; +import nl.andrewl.aos_core.config.Config; import nl.andrewl.aos_core.model.world.ColorPalette; import nl.andrewl.aos_core.net.*; import nl.andrewl.aos_core.net.udp.ChunkUpdateMessage; @@ -14,16 +16,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; -import java.net.InetAddress; +import java.nio.file.Path; +import java.util.List; public class Client implements Runnable { private static final Logger log = LoggerFactory.getLogger(Client.class); public static final double FPS = 60; - private final InetAddress serverAddress; - private final int serverPort; - private final String username; - + private final ClientConfig config; private final CommunicationHandler communicationHandler; private final InputHandler inputHandler; private final GameRenderer gameRenderer; @@ -31,33 +31,31 @@ public class Client implements Runnable { private int clientId; private final ClientWorld world; - public Client(InetAddress serverAddress, int serverPort, String username) { - this.serverAddress = serverAddress; - this.serverPort = serverPort; - this.username = username; + public Client(ClientConfig config) { + this.config = config; this.communicationHandler = new CommunicationHandler(this); this.inputHandler = new InputHandler(communicationHandler); this.world = new ClientWorld(); - this.gameRenderer = new GameRenderer(world); + this.gameRenderer = new GameRenderer(config.display, world); + } + + public ClientConfig getConfig() { + return config; } @Override public void run() { try { - log.debug("Connecting to server at {}, port {}, with username \"{}\"...", serverAddress, serverPort, username); - this.clientId = communicationHandler.establishConnection(serverAddress, serverPort, username); - log.info("Established a connection to the server."); + this.clientId = communicationHandler.establishConnection(); } catch (IOException e) { log.error("Couldn't connect to the server: {}", e.getMessage()); return; } gameRenderer.setupWindow( - new PlayerViewCursorCallback(gameRenderer.getCamera(), communicationHandler), + new PlayerViewCursorCallback(config.input, gameRenderer.getCamera(), communicationHandler), new PlayerInputKeyCallback(inputHandler), - new PlayerInputMouseClickCallback(inputHandler), - false, - false + new PlayerInputMouseClickCallback(inputHandler) ); long lastFrameAt = System.currentTimeMillis(); @@ -107,11 +105,12 @@ public class Client implements Runnable { public static void main(String[] args) throws IOException { - InetAddress serverAddress = InetAddress.getByName(args[0]); - int serverPort = Integer.parseInt(args[1]); - String username = args[2].trim(); - - Client client = new Client(serverAddress, serverPort, username); + List configPaths = Config.getCommonConfigPaths(); + if (args.length > 0) { + configPaths.add(Path.of(args[0].trim())); + } + ClientConfig clientConfig = Config.loadConfig(ClientConfig.class, configPaths, new ClientConfig()); + Client client = new Client(clientConfig); client.run(); } } 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 9ae53d6..7f1c978 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/CommunicationHandler.java +++ b/client/src/main/java/nl/andrewl/aos2_client/CommunicationHandler.java @@ -33,10 +33,15 @@ public class CommunicationHandler { this.client = client; } - public int establishConnection(InetAddress address, int port, String username) throws IOException { + public int establishConnection() throws IOException { if (socket != null && !socket.isClosed()) { socket.close(); } + InetAddress address = InetAddress.getByName(client.getConfig().serverHost); + int port = client.getConfig().serverPort; + String username = client.getConfig().username; + log.info("Connecting to server at {}, port {}, with username \"{}\"...", address, port, username); + socket = new Socket(address, port); socket.setSoTimeout(1000); ExtendedDataInputStream in = Net.getInputStream(socket.getInputStream()); @@ -50,6 +55,7 @@ public class CommunicationHandler { if (response instanceof ConnectAcceptMessage acceptMessage) { this.clientId = acceptMessage.clientId(); establishDatagramConnection(); + log.info("Connection to server established. My client id is {}.", clientId); new Thread(new TcpReceiver(in, client::onMessageReceived)).start(); new Thread(new UdpReceiver(datagramSocket, (msg, packet) -> client.onMessageReceived(msg))).start(); return acceptMessage.clientId(); diff --git a/client/src/main/java/nl/andrewl/aos2_client/config/ClientConfig.java b/client/src/main/java/nl/andrewl/aos2_client/config/ClientConfig.java new file mode 100644 index 0000000..a8e62ff --- /dev/null +++ b/client/src/main/java/nl/andrewl/aos2_client/config/ClientConfig.java @@ -0,0 +1,19 @@ +package nl.andrewl.aos2_client.config; + +public class ClientConfig { + public String serverHost = "localhost"; + public int serverPort = 25565; + public String username = "player"; + public InputConfig input = new InputConfig(); + public DisplayConfig display = new DisplayConfig(); + + public static class InputConfig { + public float mouseSensitivity = 0.005f; + } + + public static class DisplayConfig { + public boolean fullscreen = false; + public boolean captureCursor = true; + public float fov = 70; + } +} diff --git a/client/src/main/java/nl/andrewl/aos2_client/control/PlayerViewCursorCallback.java b/client/src/main/java/nl/andrewl/aos2_client/control/PlayerViewCursorCallback.java index 579c0da..24f6919 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/control/PlayerViewCursorCallback.java +++ b/client/src/main/java/nl/andrewl/aos2_client/control/PlayerViewCursorCallback.java @@ -2,6 +2,7 @@ package nl.andrewl.aos2_client.control; import nl.andrewl.aos2_client.Camera; import nl.andrewl.aos2_client.CommunicationHandler; +import nl.andrewl.aos2_client.config.ClientConfig; import nl.andrewl.aos_core.net.udp.ClientOrientationState; import org.lwjgl.glfw.GLFWCursorPosCallbackI; @@ -20,14 +21,15 @@ public class PlayerViewCursorCallback implements GLFWCursorPosCallbackI { */ private static final int ORIENTATION_UPDATE_LIMIT = 20; + private final ClientConfig.InputConfig config; private final Camera camera; private final CommunicationHandler comm; private float lastMouseCursorX; private float lastMouseCursorY; - private float mouseCursorSensitivity = 0.005f; private long lastOrientationUpdateSentAt = 0L; - public PlayerViewCursorCallback(Camera camera, CommunicationHandler comm) { + public PlayerViewCursorCallback(ClientConfig.InputConfig config, Camera camera, CommunicationHandler comm) { + this.config = config; this.camera = camera; this.comm = comm; } @@ -43,7 +45,10 @@ public class PlayerViewCursorCallback implements GLFWCursorPosCallbackI { float dy = y - lastMouseCursorY; lastMouseCursorX = x; lastMouseCursorY = y; - camera.setOrientation(camera.getOrientation().x - dx * mouseCursorSensitivity, camera.getOrientation().y - dy * mouseCursorSensitivity); + camera.setOrientation( + camera.getOrientation().x - dx * config.mouseSensitivity, + camera.getOrientation().y - dy * config.mouseSensitivity + ); long now = System.currentTimeMillis(); if (lastOrientationUpdateSentAt + ORIENTATION_UPDATE_LIMIT < now) { ForkJoinPool.commonPool().submit(() -> comm.sendDatagramPacket(new ClientOrientationState(comm.getClientId(), camera.getOrientation().x, camera.getOrientation().y))); diff --git a/client/src/main/java/nl/andrewl/aos2_client/render/GameRenderer.java b/client/src/main/java/nl/andrewl/aos2_client/render/GameRenderer.java index 6f269fb..010c44e 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/render/GameRenderer.java +++ b/client/src/main/java/nl/andrewl/aos2_client/render/GameRenderer.java @@ -2,6 +2,7 @@ package nl.andrewl.aos2_client.render; import nl.andrewl.aos2_client.Camera; import nl.andrewl.aos2_client.ClientWorld; +import nl.andrewl.aos2_client.config.ClientConfig; import nl.andrewl.aos2_client.render.chunk.ChunkRenderer; import nl.andrewl.aos2_client.render.gui.GUIRenderer; import nl.andrewl.aos2_client.render.gui.GUITexture; @@ -28,6 +29,7 @@ public class GameRenderer { private static final float Z_NEAR = 0.01f; private static final float Z_FAR = 500f; + private final ClientConfig.DisplayConfig config; private ChunkRenderer chunkRenderer; private GUIRenderer guiRenderer; private ModelRenderer modelRenderer; @@ -39,11 +41,11 @@ public class GameRenderer { private long windowHandle; private int screenWidth = 800; private int screenHeight = 600; - private float fov = 90f; private final Matrix4f perspectiveTransform; - public GameRenderer(ClientWorld world) { + public GameRenderer(ClientConfig.DisplayConfig config, ClientWorld world) { + this.config = config; this.world = world; this.camera = new Camera(); this.perspectiveTransform = new Matrix4f(); @@ -52,9 +54,7 @@ public class GameRenderer { public void setupWindow( GLFWCursorPosCallbackI viewCursorCallback, GLFWKeyCallbackI inputKeyCallback, - GLFWMouseButtonCallbackI mouseButtonCallback, - boolean fullscreen, - boolean grabCursor + GLFWMouseButtonCallbackI mouseButtonCallback ) { GLFWErrorCallback.createPrint(System.err).set(); if (!glfwInit()) throw new IllegalStateException("Could not initialize GLFW."); @@ -66,7 +66,7 @@ public class GameRenderer { GLFWVidMode primaryMonitorSettings = glfwGetVideoMode(monitorId); if (primaryMonitorSettings == null) throw new IllegalStateException("Could not get information about the primary monitory."); log.debug("Primary monitor settings: Width: {}, Height: {}", primaryMonitorSettings.width(), primaryMonitorSettings.height()); - if (fullscreen) { + if (config.fullscreen) { screenWidth = primaryMonitorSettings.width(); screenHeight = primaryMonitorSettings.height(); windowHandle = glfwCreateWindow(screenWidth, screenHeight, "Ace of Shades 2", monitorId, 0); @@ -82,7 +82,7 @@ public class GameRenderer { glfwSetKeyCallback(windowHandle, inputKeyCallback); glfwSetCursorPosCallback(windowHandle, viewCursorCallback); glfwSetMouseButtonCallback(windowHandle, mouseButtonCallback); - if (grabCursor) { + if (config.captureCursor) { glfwSetInputMode(windowHandle, GLFW_CURSOR, GLFW_CURSOR_DISABLED); } glfwSetInputMode(windowHandle, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); @@ -125,11 +125,6 @@ public class GameRenderer { updatePerspective(); } - public void setFov(float fov) { - this.fov = fov; - updatePerspective(); - } - public float getAspectRatio() { return (float) screenWidth / (float) screenHeight; } @@ -138,7 +133,7 @@ public class GameRenderer { * Updates the rendering perspective used to render the game. */ private void updatePerspective() { - perspectiveTransform.setPerspective(fov, getAspectRatio(), Z_NEAR, Z_FAR); + perspectiveTransform.setPerspective(config.fov, getAspectRatio(), Z_NEAR, Z_FAR); float[] data = new float[16]; perspectiveTransform.get(data); if (chunkRenderer != null) chunkRenderer.setPerspective(data);