diff --git a/core/pom.xml b/core/pom.xml index 0e9a9bf..aca274b 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -41,6 +41,12 @@ zero-allocation-hashing 0.15 + + + org.yaml + snakeyaml + 1.30 + org.slf4j diff --git a/core/src/main/java/nl/andrewl/aos_core/config/Config.java b/core/src/main/java/nl/andrewl/aos_core/config/Config.java new file mode 100644 index 0000000..becf25a --- /dev/null +++ b/core/src/main/java/nl/andrewl/aos_core/config/Config.java @@ -0,0 +1,58 @@ +package nl.andrewl.aos_core.config; + +import org.yaml.snakeyaml.Yaml; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +public final class Config { + private static final Yaml yaml = new Yaml(); + + private Config() {} + + /** + * Loads a configuration YAML object from the first available path. + * @param configType The type of the configuration object. + * @param paths The paths to load from. + * @param fallback A default configuration object to use if no config could + * be loaded from any of the paths. + * @return The configuration object. + * @param The type of the configuration object. + */ + public static T loadConfig(Class configType, List paths, T fallback) { + for (var path : paths) { + if (Files.exists(path) && Files.isRegularFile(path) && Files.isReadable(path)) { + try (var reader = Files.newBufferedReader(path)) { + return yaml.loadAs(reader, configType); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return fallback; + } + + public static T loadConfig(Class configType, List paths) { + var cfg = loadConfig(configType, paths, null); + if (cfg == null) { + throw new RuntimeException("Could not load config from any of the supplied paths."); + } + return cfg; + } + + public static T loadConfig(Class configType, T fallback, Path... paths) { + return loadConfig(configType, List.of(paths), fallback); + } + + public static List getCommonConfigPaths() { + List paths = new ArrayList<>(); + paths.add(Path.of("config.yaml")); + paths.add(Path.of("config.yml")); + paths.add(Path.of("cfg.yaml")); + paths.add(Path.of("cfg.yml")); + return paths; + } +} diff --git a/server/src/main/java/nl/andrewl/aos2_server/Server.java b/server/src/main/java/nl/andrewl/aos2_server/Server.java index 2648033..72223d5 100644 --- a/server/src/main/java/nl/andrewl/aos2_server/Server.java +++ b/server/src/main/java/nl/andrewl/aos2_server/Server.java @@ -1,7 +1,8 @@ package nl.andrewl.aos2_server; +import nl.andrewl.aos2_server.config.ServerConfig; +import nl.andrewl.aos_core.config.Config; import nl.andrewl.aos_core.model.world.World; -import nl.andrewl.aos_core.model.world.WorldIO; import nl.andrewl.aos_core.model.world.Worlds; import nl.andrewl.aos_core.net.UdpReceiver; import nl.andrewl.aos_core.net.udp.ClientInputState; @@ -15,6 +16,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.*; import java.nio.file.Path; +import java.util.List; import java.util.concurrent.ForkJoinPool; public class Server implements Runnable { @@ -23,18 +25,19 @@ public class Server implements Runnable { private final ServerSocket serverSocket; private final DatagramSocket datagramSocket; private volatile boolean running; - + private final ServerConfig config; private final PlayerManager playerManager; private final World world; private final WorldUpdater worldUpdater; - public Server() throws IOException { - this.serverSocket = new ServerSocket(25565, 5); + public Server(ServerConfig config) throws IOException { + this.config = config; + this.serverSocket = new ServerSocket(config.port, config.connectionBacklog); this.serverSocket.setReuseAddress(true); - this.datagramSocket = new DatagramSocket(25565); + this.datagramSocket = new DatagramSocket(config.port); this.datagramSocket.setReuseAddress(true); this.playerManager = new PlayerManager(); - this.worldUpdater = new WorldUpdater(this, 20); + this.worldUpdater = new WorldUpdater(this, config.ticksPerSecond); this.world = Worlds.testingWorld(); } @@ -107,6 +110,10 @@ public class Server implements Runnable { } } + public ServerConfig getConfig() { + return config; + } + public World getWorld() { return world; } @@ -116,6 +123,11 @@ public class Server implements Runnable { } public static void main(String[] args) throws IOException { - new Server().run(); + List configPaths = Config.getCommonConfigPaths(); + if (args.length > 0) { + configPaths.add(Path.of(args[0].trim())); + } + ServerConfig cfg = Config.loadConfig(ServerConfig.class, configPaths, new ServerConfig()); + new Server(cfg).run(); } } diff --git a/server/src/main/java/nl/andrewl/aos2_server/ServerPlayer.java b/server/src/main/java/nl/andrewl/aos2_server/ServerPlayer.java index c246970..f35e5c1 100644 --- a/server/src/main/java/nl/andrewl/aos2_server/ServerPlayer.java +++ b/server/src/main/java/nl/andrewl/aos2_server/ServerPlayer.java @@ -1,5 +1,6 @@ package nl.andrewl.aos2_server; +import nl.andrewl.aos2_server.config.ServerConfig; import nl.andrewl.aos_core.model.Player; import nl.andrewl.aos_core.model.world.World; import nl.andrewl.aos_core.net.udp.ChunkUpdateMessage; @@ -24,17 +25,6 @@ public class ServerPlayer extends Player { public static final float WIDTH = 0.75f; public static final float RADIUS = WIDTH / 2f; - public static final float GRAVITY = 9.81f * 3; - public static final float SPEED_NORMAL = 4f; - public static final float SPEED_CROUCH = 1.5f; - public static final float SPEED_SPRINT = 9f; - public static final float MOVEMENT_ACCELERATION = 2f; - public static final float MOVEMENT_DECELERATION = 1f; - public static final float JUMP_SPEED = 8f; - - public static final int BLOCK_REMOVE_COOLDOWN = 250; - public static final int BLOCK_PLACE_COOLDOWN = 100; - private ClientInputState lastInputState; private long lastBlockRemovedAt = 0; private long lastBlockPlacedAt = 0; @@ -62,7 +52,7 @@ public class ServerPlayer extends Player { public void tick(float dt, World world, Server server) { long now = System.currentTimeMillis(); // Check for breaking blocks. - if (lastInputState.hitting() && now - lastBlockRemovedAt > BLOCK_REMOVE_COOLDOWN) { + if (lastInputState.hitting() && now - lastBlockRemovedAt > server.getConfig().actions.blockRemoveCooldown * 1000) { Vector3f eyePos = new Vector3f(position); eyePos.y += getEyeHeight(); var hit = world.getLookingAtPos(eyePos, viewVector, 10); @@ -73,7 +63,7 @@ public class ServerPlayer extends Player { } } // Check for placing blocks. - if (lastInputState.interacting() && now - lastBlockPlacedAt > BLOCK_PLACE_COOLDOWN) { + if (lastInputState.interacting() && now - lastBlockPlacedAt > server.getConfig().actions.blockPlaceCooldown * 1000) { Vector3f eyePos = new Vector3f(position); eyePos.y += getEyeHeight(); var hit = world.getLookingAtPos(eyePos, viewVector, 10); @@ -85,21 +75,21 @@ public class ServerPlayer extends Player { server.getPlayerManager().broadcastUdpMessage(ChunkUpdateMessage.fromWorld(placePos, world)); } } - tickMovement(dt, world); + tickMovement(dt, world, server.getConfig().physics); } - private void tickMovement(float dt, World world) { + private void tickMovement(float dt, World world, ServerConfig.PhysicsConfig config) { updated = false; // Reset the updated flag. This will be set to true if the player was updated in this tick. boolean grounded = isGrounded(world); - tickHorizontalVelocity(grounded); + tickHorizontalVelocity(config, grounded); if (isGrounded(world)) { if (lastInputState.jumping()) { - velocity.y = JUMP_SPEED * (lastInputState.sprinting() ? 1.25f : 1f); + velocity.y = config.jumpVerticalSpeed * (lastInputState.sprinting() ? 1.25f : 1f); updated = true; } } else { - velocity.y -= GRAVITY * dt; + velocity.y -= config.gravity * dt; updated = true; } @@ -113,7 +103,7 @@ public class ServerPlayer extends Player { } } - private void tickHorizontalVelocity(boolean doDeceleration) { + private void tickHorizontalVelocity(ServerConfig.PhysicsConfig config, boolean doDeceleration) { Vector3f horizontalVelocity = new Vector3f( velocity.x == velocity.x ? velocity.x : 0f, 0, @@ -127,15 +117,15 @@ public class ServerPlayer extends Player { if (acceleration.lengthSquared() > 0) { acceleration.normalize(); acceleration.rotateAxis(orientation.x, 0, 1, 0); - acceleration.mul(MOVEMENT_ACCELERATION); + acceleration.mul(config.movementAcceleration); horizontalVelocity.add(acceleration); final float maxSpeed; if (lastInputState.crouching()) { - maxSpeed = SPEED_CROUCH; + maxSpeed = config.crouchingSpeed; } else if (lastInputState.sprinting()) { - maxSpeed = SPEED_SPRINT; + maxSpeed = config.sprintingSpeed; } else { - maxSpeed = SPEED_NORMAL; + maxSpeed = config.walkingSpeed; } if (horizontalVelocity.length() > maxSpeed) { horizontalVelocity.normalize(maxSpeed); @@ -144,7 +134,7 @@ public class ServerPlayer extends Player { } else if (doDeceleration && horizontalVelocity.lengthSquared() > 0) { Vector3f deceleration = new Vector3f(horizontalVelocity) .negate().normalize() - .mul(Math.min(horizontalVelocity.length(), MOVEMENT_DECELERATION)); + .mul(Math.min(horizontalVelocity.length(), config.movementDeceleration)); horizontalVelocity.add(deceleration); if (horizontalVelocity.length() < 0.1f) { horizontalVelocity.set(0); diff --git a/server/src/main/java/nl/andrewl/aos2_server/config/ServerConfig.java b/server/src/main/java/nl/andrewl/aos2_server/config/ServerConfig.java new file mode 100644 index 0000000..3808993 --- /dev/null +++ b/server/src/main/java/nl/andrewl/aos2_server/config/ServerConfig.java @@ -0,0 +1,24 @@ +package nl.andrewl.aos2_server.config; + +public class ServerConfig { + public int port = 25565; + public int connectionBacklog = 5; + public float ticksPerSecond = 20.0f; + public PhysicsConfig physics = new PhysicsConfig(); + public ActionsConfig actions = new ActionsConfig(); + + public static class PhysicsConfig { + public float gravity = 9.81f * 3; + public float walkingSpeed = 4; + public float crouchingSpeed = 1.5f; + public float sprintingSpeed = 9; + public float movementAcceleration = 2; + public float movementDeceleration = 1; + public float jumpVerticalSpeed = 8; + } + + public static class ActionsConfig { + public float blockRemoveCooldown = 0.25f; + public float blockPlaceCooldown = 0.1f; + } +}