Added config.

This commit is contained in:
Andrew Lalis 2022-07-17 19:37:34 +02:00
parent de6e50264b
commit 725659a4a4
5 changed files with 121 additions and 31 deletions

View File

@ -41,6 +41,12 @@
<artifactId>zero-allocation-hashing</artifactId> <artifactId>zero-allocation-hashing</artifactId>
<version>0.15</version> <version>0.15</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.yaml/snakeyaml -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.30</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api --> <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>

View File

@ -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 <T> The type of the configuration object.
*/
public static <T> T loadConfig(Class<T> configType, List<Path> 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> T loadConfig(Class<T> configType, List<Path> 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> T loadConfig(Class<T> configType, T fallback, Path... paths) {
return loadConfig(configType, List.of(paths), fallback);
}
public static List<Path> getCommonConfigPaths() {
List<Path> 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;
}
}

View File

@ -1,7 +1,8 @@
package nl.andrewl.aos2_server; 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.World;
import nl.andrewl.aos_core.model.world.WorldIO;
import nl.andrewl.aos_core.model.world.Worlds; import nl.andrewl.aos_core.model.world.Worlds;
import nl.andrewl.aos_core.net.UdpReceiver; import nl.andrewl.aos_core.net.UdpReceiver;
import nl.andrewl.aos_core.net.udp.ClientInputState; import nl.andrewl.aos_core.net.udp.ClientInputState;
@ -15,6 +16,7 @@ import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.net.*; import java.net.*;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinPool;
public class Server implements Runnable { public class Server implements Runnable {
@ -23,18 +25,19 @@ public class Server implements Runnable {
private final ServerSocket serverSocket; private final ServerSocket serverSocket;
private final DatagramSocket datagramSocket; private final DatagramSocket datagramSocket;
private volatile boolean running; private volatile boolean running;
private final ServerConfig config;
private final PlayerManager playerManager; private final PlayerManager playerManager;
private final World world; private final World world;
private final WorldUpdater worldUpdater; private final WorldUpdater worldUpdater;
public Server() throws IOException { public Server(ServerConfig config) throws IOException {
this.serverSocket = new ServerSocket(25565, 5); this.config = config;
this.serverSocket = new ServerSocket(config.port, config.connectionBacklog);
this.serverSocket.setReuseAddress(true); this.serverSocket.setReuseAddress(true);
this.datagramSocket = new DatagramSocket(25565); this.datagramSocket = new DatagramSocket(config.port);
this.datagramSocket.setReuseAddress(true); this.datagramSocket.setReuseAddress(true);
this.playerManager = new PlayerManager(); this.playerManager = new PlayerManager();
this.worldUpdater = new WorldUpdater(this, 20); this.worldUpdater = new WorldUpdater(this, config.ticksPerSecond);
this.world = Worlds.testingWorld(); this.world = Worlds.testingWorld();
} }
@ -107,6 +110,10 @@ public class Server implements Runnable {
} }
} }
public ServerConfig getConfig() {
return config;
}
public World getWorld() { public World getWorld() {
return world; return world;
} }
@ -116,6 +123,11 @@ public class Server implements Runnable {
} }
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
new Server().run(); List<Path> 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();
} }
} }

View File

@ -1,5 +1,6 @@
package nl.andrewl.aos2_server; 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.Player;
import nl.andrewl.aos_core.model.world.World; import nl.andrewl.aos_core.model.world.World;
import nl.andrewl.aos_core.net.udp.ChunkUpdateMessage; 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 WIDTH = 0.75f;
public static final float RADIUS = WIDTH / 2f; 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 ClientInputState lastInputState;
private long lastBlockRemovedAt = 0; private long lastBlockRemovedAt = 0;
private long lastBlockPlacedAt = 0; private long lastBlockPlacedAt = 0;
@ -62,7 +52,7 @@ public class ServerPlayer extends Player {
public void tick(float dt, World world, Server server) { public void tick(float dt, World world, Server server) {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
// Check for breaking blocks. // 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); Vector3f eyePos = new Vector3f(position);
eyePos.y += getEyeHeight(); eyePos.y += getEyeHeight();
var hit = world.getLookingAtPos(eyePos, viewVector, 10); var hit = world.getLookingAtPos(eyePos, viewVector, 10);
@ -73,7 +63,7 @@ public class ServerPlayer extends Player {
} }
} }
// Check for placing blocks. // 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); Vector3f eyePos = new Vector3f(position);
eyePos.y += getEyeHeight(); eyePos.y += getEyeHeight();
var hit = world.getLookingAtPos(eyePos, viewVector, 10); var hit = world.getLookingAtPos(eyePos, viewVector, 10);
@ -85,21 +75,21 @@ public class ServerPlayer extends Player {
server.getPlayerManager().broadcastUdpMessage(ChunkUpdateMessage.fromWorld(placePos, world)); 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. updated = false; // Reset the updated flag. This will be set to true if the player was updated in this tick.
boolean grounded = isGrounded(world); boolean grounded = isGrounded(world);
tickHorizontalVelocity(grounded); tickHorizontalVelocity(config, grounded);
if (isGrounded(world)) { if (isGrounded(world)) {
if (lastInputState.jumping()) { if (lastInputState.jumping()) {
velocity.y = JUMP_SPEED * (lastInputState.sprinting() ? 1.25f : 1f); velocity.y = config.jumpVerticalSpeed * (lastInputState.sprinting() ? 1.25f : 1f);
updated = true; updated = true;
} }
} else { } else {
velocity.y -= GRAVITY * dt; velocity.y -= config.gravity * dt;
updated = true; 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( Vector3f horizontalVelocity = new Vector3f(
velocity.x == velocity.x ? velocity.x : 0f, velocity.x == velocity.x ? velocity.x : 0f,
0, 0,
@ -127,15 +117,15 @@ public class ServerPlayer extends Player {
if (acceleration.lengthSquared() > 0) { if (acceleration.lengthSquared() > 0) {
acceleration.normalize(); acceleration.normalize();
acceleration.rotateAxis(orientation.x, 0, 1, 0); acceleration.rotateAxis(orientation.x, 0, 1, 0);
acceleration.mul(MOVEMENT_ACCELERATION); acceleration.mul(config.movementAcceleration);
horizontalVelocity.add(acceleration); horizontalVelocity.add(acceleration);
final float maxSpeed; final float maxSpeed;
if (lastInputState.crouching()) { if (lastInputState.crouching()) {
maxSpeed = SPEED_CROUCH; maxSpeed = config.crouchingSpeed;
} else if (lastInputState.sprinting()) { } else if (lastInputState.sprinting()) {
maxSpeed = SPEED_SPRINT; maxSpeed = config.sprintingSpeed;
} else { } else {
maxSpeed = SPEED_NORMAL; maxSpeed = config.walkingSpeed;
} }
if (horizontalVelocity.length() > maxSpeed) { if (horizontalVelocity.length() > maxSpeed) {
horizontalVelocity.normalize(maxSpeed); horizontalVelocity.normalize(maxSpeed);
@ -144,7 +134,7 @@ public class ServerPlayer extends Player {
} else if (doDeceleration && horizontalVelocity.lengthSquared() > 0) { } else if (doDeceleration && horizontalVelocity.lengthSquared() > 0) {
Vector3f deceleration = new Vector3f(horizontalVelocity) Vector3f deceleration = new Vector3f(horizontalVelocity)
.negate().normalize() .negate().normalize()
.mul(Math.min(horizontalVelocity.length(), MOVEMENT_DECELERATION)); .mul(Math.min(horizontalVelocity.length(), config.movementDeceleration));
horizontalVelocity.add(deceleration); horizontalVelocity.add(deceleration);
if (horizontalVelocity.length() < 0.1f) { if (horizontalVelocity.length() < 0.1f) {
horizontalVelocity.set(0); horizontalVelocity.set(0);

View File

@ -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;
}
}