Added basic settings support, smoother player movement, customizable guns, etc.
This commit is contained in:
parent
6eeb69d500
commit
f50a2d72a3
|
@ -70,7 +70,7 @@ public class Client {
|
||||||
player.setPosition(p.getPosition());
|
player.setPosition(p.getPosition());
|
||||||
player.setOrientation(p.getOrientation());
|
player.setOrientation(p.getOrientation());
|
||||||
player.setVelocity(p.getVelocity());
|
player.setVelocity(p.getVelocity());
|
||||||
player.setGun(Gun.forType(p.getGunType()));
|
player.setGun(new Gun(this.world.getGunTypes().get(p.getGunTypeName())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.soundManager.play(update.getSoundsToPlay());
|
this.soundManager.play(update.getSoundsToPlay());
|
||||||
|
@ -92,14 +92,7 @@ public class Client {
|
||||||
if (this.myPlayer == null) return;
|
if (this.myPlayer == null) return;
|
||||||
this.myPlayer.setHealth(update.getHealth());
|
this.myPlayer.setHealth(update.getHealth());
|
||||||
this.myPlayer.setReloading(update.isReloading());
|
this.myPlayer.setReloading(update.isReloading());
|
||||||
this.myPlayer.setGun(Gun.forType(
|
this.myPlayer.setGun(new Gun(this.myPlayer.getGun().getType(), update.getGunCurrentClipBulletCount(), update.getGunClipCount()));
|
||||||
this.myPlayer.getGun().getType(),
|
|
||||||
update.getGunMaxClipCount(),
|
|
||||||
update.getGunClipSize(),
|
|
||||||
update.getGunBulletsPerRound(),
|
|
||||||
update.getGunCurrentClipBulletCount(),
|
|
||||||
update.getGunClipCount()
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendPlayerState() {
|
public void sendPlayerState() {
|
||||||
|
|
|
@ -54,6 +54,8 @@ public class MessageTransceiver extends Thread {
|
||||||
this.client.setPlayer(msg.getPlayer());
|
this.client.setPlayer(msg.getPlayer());
|
||||||
this.client.setWorld(msg.getWorld());
|
this.client.setWorld(msg.getWorld());
|
||||||
established = true;
|
established = true;
|
||||||
|
} else if (obj instanceof ConnectionRejectedMessage msg) {
|
||||||
|
throw new IOException(msg.getMessage());
|
||||||
}
|
}
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
|
@ -9,7 +9,7 @@ public class Tester {
|
||||||
};
|
};
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
for (int i = 0; i < 1; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
try {
|
try {
|
||||||
new Client("localhost", 8035, names[ThreadLocalRandom.current().nextInt(names.length)]);
|
new Client("localhost", 8035, names[ThreadLocalRandom.current().nextInt(names.length)]);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
|
@ -50,6 +50,10 @@ public class PlayerKeyListener extends KeyAdapter {
|
||||||
state.setMovingRight(true);
|
state.setMovingRight(true);
|
||||||
} else if (e.getKeyCode() == KeyEvent.VK_R) {
|
} else if (e.getKeyCode() == KeyEvent.VK_R) {
|
||||||
state.setReloading(true);
|
state.setReloading(true);
|
||||||
|
} else if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
|
||||||
|
state.setSprinting(true);
|
||||||
|
} else if (e.getKeyCode() == KeyEvent.VK_CONTROL) {
|
||||||
|
state.setSneaking(true);
|
||||||
}
|
}
|
||||||
this.client.sendPlayerState();
|
this.client.sendPlayerState();
|
||||||
}
|
}
|
||||||
|
@ -68,6 +72,10 @@ public class PlayerKeyListener extends KeyAdapter {
|
||||||
state.setMovingRight(false);
|
state.setMovingRight(false);
|
||||||
} else if (e.getKeyCode() == KeyEvent.VK_R) {
|
} else if (e.getKeyCode() == KeyEvent.VK_R) {
|
||||||
state.setReloading(false);
|
state.setReloading(false);
|
||||||
|
} else if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
|
||||||
|
state.setSprinting(false);
|
||||||
|
} else if (e.getKeyCode() == KeyEvent.VK_CONTROL) {
|
||||||
|
state.setSneaking(false);
|
||||||
}
|
}
|
||||||
this.client.sendPlayerState();
|
this.client.sendPlayerState();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package nl.andrewlalis.aos_client.view;
|
||||||
import nl.andrewlalis.aos_client.Client;
|
import nl.andrewlalis.aos_client.Client;
|
||||||
import nl.andrewlalis.aos_core.model.*;
|
import nl.andrewlalis.aos_core.model.*;
|
||||||
import nl.andrewlalis.aos_core.model.tools.Gun;
|
import nl.andrewlalis.aos_core.model.tools.Gun;
|
||||||
import nl.andrewlalis.aos_core.model.tools.GunType;
|
|
||||||
import nl.andrewlalis.aos_core.net.chat.ChatMessage;
|
import nl.andrewlalis.aos_core.net.chat.ChatMessage;
|
||||||
import nl.andrewlalis.aos_core.net.chat.PlayerChatMessage;
|
import nl.andrewlalis.aos_core.net.chat.PlayerChatMessage;
|
||||||
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
|
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
|
||||||
|
@ -148,12 +147,7 @@ public class GamePanel extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawGun(Graphics2D g2, Gun gun) {
|
private void drawGun(Graphics2D g2, Gun gun) {
|
||||||
g2.setColor(Color.GRAY);
|
g2.setColor(Color.decode(gun.getType().getColor()));
|
||||||
if (gun.getType() == GunType.RIFLE) {
|
|
||||||
g2.setColor(new Color(59, 43, 0));
|
|
||||||
} else if (gun.getType() == GunType.SHOTGUN) {
|
|
||||||
g2.setColor(new Color(18, 18, 17));
|
|
||||||
}
|
|
||||||
Rectangle2D.Double gunBarrel = new Rectangle2D.Double(
|
Rectangle2D.Double gunBarrel = new Rectangle2D.Double(
|
||||||
0,
|
0,
|
||||||
0.5,
|
0.5,
|
||||||
|
@ -235,8 +229,8 @@ public class GamePanel extends JPanel {
|
||||||
g2.drawString("Reloading...", 5, this.getHeight() - 10);
|
g2.drawString("Reloading...", 5, this.getHeight() - 10);
|
||||||
}
|
}
|
||||||
Gun gun = myPlayer.getGun();
|
Gun gun = myPlayer.getGun();
|
||||||
g2.drawString("Clips: " + gun.getClipCount() + " / " + gun.getMaxClipCount(), 5, this.getHeight() - 20);
|
g2.drawString("Clips: " + gun.getClipCount() + " / " + gun.getType().getMaxClipCount(), 5, this.getHeight() - 20);
|
||||||
g2.drawString("Bullets: " + gun.getCurrentClipBulletCount() + " / " + gun.getClipSize(), 5, this.getHeight() - 30);
|
g2.drawString("Bullets: " + gun.getCurrentClipBulletCount() + " / " + gun.getType().getClipSize(), 5, this.getHeight() - 30);
|
||||||
if (myPlayer.getHealth() >= 66.0f) {
|
if (myPlayer.getHealth() >= 66.0f) {
|
||||||
g2.setColor(Color.GREEN);
|
g2.setColor(Color.GREEN);
|
||||||
} else if (myPlayer.getHealth() >= 33.0f) {
|
} else if (myPlayer.getHealth() >= 33.0f) {
|
||||||
|
|
15
core/pom.xml
15
core/pom.xml
|
@ -26,4 +26,19 @@
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>2.12.3</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-yaml -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||||
|
<artifactId>jackson-dataformat-yaml</artifactId>
|
||||||
|
<version>2.12.3</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -7,6 +7,9 @@ import java.util.Random;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
public record Vec2(float x, float y) implements Serializable {
|
public record Vec2(float x, float y) implements Serializable {
|
||||||
|
public static final Vec2 ZERO = new Vec2(0, 0);
|
||||||
|
public static final Vec2 UP = new Vec2(0, -1);
|
||||||
|
|
||||||
|
|
||||||
public float mag() {
|
public float mag() {
|
||||||
return (float) Math.sqrt(x * x + y * y);
|
return (float) Math.sqrt(x * x + y * y);
|
||||||
|
|
|
@ -3,28 +3,35 @@ package nl.andrewlalis.aos_core.model;
|
||||||
import nl.andrewlalis.aos_core.geom.Vec2;
|
import nl.andrewlalis.aos_core.geom.Vec2;
|
||||||
import nl.andrewlalis.aos_core.model.tools.Gun;
|
import nl.andrewlalis.aos_core.model.tools.Gun;
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
|
|
||||||
public class Bullet extends PhysicsObject {
|
public class Bullet extends PhysicsObject {
|
||||||
private final int playerId;
|
private final int playerId;
|
||||||
|
private final Player player;
|
||||||
private final Gun gun;
|
private final Gun gun;
|
||||||
|
|
||||||
public Bullet(Player player) {
|
public Bullet(Player player) {
|
||||||
this.playerId = player.getId();
|
this.playerId = player.getId();
|
||||||
|
this.player = player;
|
||||||
this.setPosition(player.getPosition()
|
this.setPosition(player.getPosition()
|
||||||
.add(player.getOrientation().mul(1.5f))
|
.add(player.getOrientation().mul(1.5f))
|
||||||
.add(player.getOrientation().perp().mul(Player.RADIUS))
|
.add(player.getOrientation().perp().mul(Player.RADIUS))
|
||||||
);
|
);
|
||||||
this.setOrientation(player.getOrientation());
|
this.setOrientation(player.getOrientation());
|
||||||
Vec2 perturbation = Vec2.random(-1, 1).mul(player.getGun().getAccuracy());
|
float accuracy = player.getGun().getType().getAccuracy();
|
||||||
this.setVelocity(this.getOrientation().add(perturbation).mul(player.getGun().getBulletSpeed()));
|
if (player.isSneaking()) {
|
||||||
|
accuracy *= Player.SNEAK_ACCURACY_MODIFIER;
|
||||||
|
} else if (player.isSprinting()) {
|
||||||
|
accuracy *= Player.SPRINT_ACCURACY_MODIFIER;
|
||||||
|
}
|
||||||
|
Vec2 perturbation = Vec2.random(-1, 1).mul(accuracy);
|
||||||
|
Vec2 localVelocity = this.getOrientation().add(perturbation).mul(player.getGun().getType().getBulletSpeed());
|
||||||
|
this.setVelocity(player.getVelocity().add(localVelocity));
|
||||||
this.gun = player.getGun();
|
this.gun = player.getGun();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bullet(Vec2 position, Vec2 velocity) {
|
public Bullet(Vec2 position, Vec2 velocity) {
|
||||||
super(position, new Vec2(0, -1), velocity);
|
super(position, new Vec2(0, -1), velocity);
|
||||||
this.playerId = -1;
|
this.playerId = -1;
|
||||||
|
this.player = null;
|
||||||
this.gun = null;
|
this.gun = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +39,10 @@ public class Bullet extends PhysicsObject {
|
||||||
return playerId;
|
return playerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
public Gun getGun() {
|
public Gun getGun() {
|
||||||
return gun;
|
return gun;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,23 @@ package nl.andrewlalis.aos_core.model;
|
||||||
|
|
||||||
import nl.andrewlalis.aos_core.geom.Vec2;
|
import nl.andrewlalis.aos_core.geom.Vec2;
|
||||||
import nl.andrewlalis.aos_core.model.tools.Gun;
|
import nl.andrewlalis.aos_core.model.tools.Gun;
|
||||||
|
import nl.andrewlalis.aos_core.model.tools.GunType;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class Player extends PhysicsObject implements Comparable<Player> {
|
public class Player extends PhysicsObject implements Comparable<Player> {
|
||||||
public static final float MOVEMENT_SPEED = 10; // Movement speed, in m/s
|
public static final float MOVEMENT_SPEED = 10; // Movement speed, in m/s
|
||||||
|
public static final float MOVEMENT_SPEED_SPRINT = 18;
|
||||||
|
public static final float MOVEMENT_SPEED_SNEAK = 5;
|
||||||
|
public static final float MOVEMENT_ACCELERATION = 60; // Acceleration speed, in m/s^2.
|
||||||
|
public static final float MOVEMENT_THRESHOLD = 0.001f; // Threshold for stopping movement. Speeds slower than this are reduced to 0.
|
||||||
|
public static final float MOVEMENT_DECELERATION = 30; // Deceleration speed, in m/s^2.
|
||||||
public static final float RADIUS = 0.5f; // Collision radius, in meters.
|
public static final float RADIUS = 0.5f; // Collision radius, in meters.
|
||||||
public static final float RESUPPLY_COOLDOWN = 30; // Seconds between allowing resupply.
|
public static final float RESUPPLY_COOLDOWN = 30; // Seconds between allowing resupply.
|
||||||
public static final float MAX_HEALTH = 100.0f;
|
public static final float MAX_HEALTH = 100.0f;
|
||||||
|
public static final float HEALTH_REGEN_RATE = 1.0f; // How quickly players regenerate health over time.
|
||||||
|
public static final float SNEAK_ACCURACY_MODIFIER = 0.5f;
|
||||||
|
public static final float SPRINT_ACCURACY_MODIFIER = 1.5f;
|
||||||
|
|
||||||
private final int id;
|
private final int id;
|
||||||
private final String name;
|
private final String name;
|
||||||
|
@ -23,12 +32,12 @@ public class Player extends PhysicsObject implements Comparable<Player> {
|
||||||
private boolean reloading;
|
private boolean reloading;
|
||||||
private transient long lastResupply;
|
private transient long lastResupply;
|
||||||
|
|
||||||
public Player(int id, String name, Team team) {
|
public Player(int id, String name, Team team, GunType gunType) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.team = team;
|
this.team = team;
|
||||||
this.state = new PlayerControlState();
|
this.state = new PlayerControlState();
|
||||||
this.gun = Gun.ak47();
|
this.gun = new Gun(gunType);
|
||||||
this.health = MAX_HEALTH;
|
this.health = MAX_HEALTH;
|
||||||
this.useWeapon();
|
this.useWeapon();
|
||||||
this.lastShot = System.currentTimeMillis();
|
this.lastShot = System.currentTimeMillis();
|
||||||
|
@ -79,7 +88,7 @@ public class Player extends PhysicsObject implements Comparable<Player> {
|
||||||
!this.state.isReloading() &&
|
!this.state.isReloading() &&
|
||||||
!this.reloading &&
|
!this.reloading &&
|
||||||
this.gun.getCurrentClipBulletCount() > 0 &&
|
this.gun.getCurrentClipBulletCount() > 0 &&
|
||||||
this.lastShot + ((long) (this.gun.getShotCooldownTime() * 1000)) < System.currentTimeMillis() &&
|
this.lastShot + ((long) (this.gun.getType().getShotCooldownTime() * 1000)) < System.currentTimeMillis() &&
|
||||||
(this.getTeam() == null || this.getTeam().getSpawnPoint().dist(this.getPosition()) > Team.SPAWN_RADIUS);
|
(this.getTeam() == null || this.getTeam().getSpawnPoint().dist(this.getPosition()) > Team.SPAWN_RADIUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,10 +109,7 @@ public class Player extends PhysicsObject implements Comparable<Player> {
|
||||||
|
|
||||||
public boolean isReloadingComplete() {
|
public boolean isReloadingComplete() {
|
||||||
long msSinceStart = System.currentTimeMillis() - this.reloadingStartedAt;
|
long msSinceStart = System.currentTimeMillis() - this.reloadingStartedAt;
|
||||||
if (msSinceStart > this.gun.getReloadTime() * 1000) {
|
return msSinceStart > this.gun.getType().getReloadTime() * 1000;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isReloading() {
|
public boolean isReloading() {
|
||||||
|
@ -138,6 +144,16 @@ public class Player extends PhysicsObject implements Comparable<Player> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSneaking() {
|
||||||
|
return this.state.isSneaking() &&
|
||||||
|
!this.state.isSprinting();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSprinting() {
|
||||||
|
return this.state.isSprinting() &&
|
||||||
|
!this.state.isSneaking();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
|
|
@ -11,6 +11,8 @@ public class PlayerControlState implements Serializable {
|
||||||
boolean movingRight;
|
boolean movingRight;
|
||||||
boolean movingForward;
|
boolean movingForward;
|
||||||
boolean movingBackward;
|
boolean movingBackward;
|
||||||
|
boolean sprinting;
|
||||||
|
boolean sneaking;
|
||||||
|
|
||||||
boolean shooting;
|
boolean shooting;
|
||||||
boolean reloading;
|
boolean reloading;
|
||||||
|
@ -49,6 +51,22 @@ public class PlayerControlState implements Serializable {
|
||||||
this.movingBackward = movingBackward;
|
this.movingBackward = movingBackward;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSprinting() {
|
||||||
|
return sprinting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSprinting(boolean sprinting) {
|
||||||
|
this.sprinting = sprinting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSneaking() {
|
||||||
|
return sneaking;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSneaking(boolean sneaking) {
|
||||||
|
this.sneaking = sneaking;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isShooting() {
|
public boolean isShooting() {
|
||||||
return shooting;
|
return shooting;
|
||||||
}
|
}
|
||||||
|
@ -73,19 +91,6 @@ public class PlayerControlState implements Serializable {
|
||||||
this.mouseLocation = mouseLocation;
|
this.mouseLocation = mouseLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "PlayerControlState{" +
|
|
||||||
"movingLeft=" + movingLeft +
|
|
||||||
", movingRight=" + movingRight +
|
|
||||||
", movingForward=" + movingForward +
|
|
||||||
", movingBackward=" + movingBackward +
|
|
||||||
", shooting=" + shooting +
|
|
||||||
", reloading=" + reloading +
|
|
||||||
", mouseLocation=" + mouseLocation +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] toBytes() {
|
public byte[] toBytes() {
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES + 2 * Float.BYTES);
|
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES + 2 * Float.BYTES);
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
@ -95,6 +100,8 @@ public class PlayerControlState implements Serializable {
|
||||||
if (this.movingBackward) flags |= 8;
|
if (this.movingBackward) flags |= 8;
|
||||||
if (this.shooting) flags |= 16;
|
if (this.shooting) flags |= 16;
|
||||||
if (this.reloading) flags |= 32;
|
if (this.reloading) flags |= 32;
|
||||||
|
if (this.sprinting) flags |= 64;
|
||||||
|
if (this.sneaking) flags |= 128;
|
||||||
buffer.putInt(flags);
|
buffer.putInt(flags);
|
||||||
buffer.putFloat(this.mouseLocation.x());
|
buffer.putFloat(this.mouseLocation.x());
|
||||||
buffer.putFloat(this.mouseLocation.y());
|
buffer.putFloat(this.mouseLocation.y());
|
||||||
|
@ -111,6 +118,8 @@ public class PlayerControlState implements Serializable {
|
||||||
s.movingBackward = (flags & 8) > 0;
|
s.movingBackward = (flags & 8) > 0;
|
||||||
s.shooting = (flags & 16) > 0;
|
s.shooting = (flags & 16) > 0;
|
||||||
s.reloading = (flags & 32) > 0;
|
s.reloading = (flags & 32) > 0;
|
||||||
|
s.sprinting = (flags & 64) > 0;
|
||||||
|
s.sneaking = (flags & 128) > 0;
|
||||||
s.mouseLocation = new Vec2(buffer.getFloat(), buffer.getFloat());
|
s.mouseLocation = new Vec2(buffer.getFloat(), buffer.getFloat());
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.util.List;
|
||||||
public class Team implements Serializable {
|
public class Team implements Serializable {
|
||||||
public static final float SPAWN_RADIUS = 3;
|
public static final float SPAWN_RADIUS = 3;
|
||||||
public static final float SUPPLY_POINT_RADIUS = 2;
|
public static final float SUPPLY_POINT_RADIUS = 2;
|
||||||
|
public static final boolean FRIENDLY_FIRE = false;
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final java.awt.Color color;
|
private final java.awt.Color color;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package nl.andrewlalis.aos_core.model;
|
package nl.andrewlalis.aos_core.model;
|
||||||
|
|
||||||
import nl.andrewlalis.aos_core.geom.Vec2;
|
import nl.andrewlalis.aos_core.geom.Vec2;
|
||||||
|
import nl.andrewlalis.aos_core.model.tools.GunType;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
@ -17,19 +17,18 @@ public class World implements Serializable {
|
||||||
private final Vec2 size;
|
private final Vec2 size;
|
||||||
|
|
||||||
private final List<Team> teams;
|
private final List<Team> teams;
|
||||||
|
private final Map<String, GunType> gunTypes;
|
||||||
private final Map<Integer, Player> players;
|
private final Map<Integer, Player> players;
|
||||||
private final List<Bullet> bullets;
|
private final List<Bullet> bullets;
|
||||||
private final List<Barricade> barricades;
|
private final List<Barricade> barricades;
|
||||||
|
|
||||||
private final List<String> soundsToPlay;
|
|
||||||
|
|
||||||
public World(Vec2 size) {
|
public World(Vec2 size) {
|
||||||
this.size = size;
|
this.size = size;
|
||||||
this.teams = new ArrayList<>();
|
this.teams = new ArrayList<>();
|
||||||
|
this.gunTypes = new ConcurrentHashMap<>();
|
||||||
this.players = new ConcurrentHashMap<>();
|
this.players = new ConcurrentHashMap<>();
|
||||||
this.bullets = new CopyOnWriteArrayList<>();
|
this.bullets = new CopyOnWriteArrayList<>();
|
||||||
this.barricades = new ArrayList<>();
|
this.barricades = new ArrayList<>();
|
||||||
this.soundsToPlay = new ArrayList<>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec2 getSize() {
|
public Vec2 getSize() {
|
||||||
|
@ -40,6 +39,10 @@ public class World implements Serializable {
|
||||||
return teams;
|
return teams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, GunType> getGunTypes() {
|
||||||
|
return gunTypes;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<Integer, Player> getPlayers() {
|
public Map<Integer, Player> getPlayers() {
|
||||||
return this.players;
|
return this.players;
|
||||||
}
|
}
|
||||||
|
@ -51,8 +54,4 @@ public class World implements Serializable {
|
||||||
public List<Barricade> getBarricades() {
|
public List<Barricade> getBarricades() {
|
||||||
return barricades;
|
return barricades;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getSoundsToPlay() {
|
|
||||||
return soundsToPlay;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,48 +3,7 @@ package nl.andrewlalis.aos_core.model.tools;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
public class Gun implements Serializable {
|
public class Gun implements Serializable {
|
||||||
|
GunType type;
|
||||||
private final GunType type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum number of clips a player can carry when using this gun.
|
|
||||||
*/
|
|
||||||
private final int maxClipCount;
|
|
||||||
/**
|
|
||||||
* Number of bullets in each clip.
|
|
||||||
*/
|
|
||||||
private final int clipSize;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of bullets that are fired simultaneously per round. Usually only
|
|
||||||
* shotguns fire multiple.
|
|
||||||
*/
|
|
||||||
private final int bulletsPerRound;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How accurate shots from this gun are.
|
|
||||||
*/
|
|
||||||
private final float accuracy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How long (in seconds) to wait after each shot, before another is shot.
|
|
||||||
*/
|
|
||||||
private final float shotCooldownTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How long (in seconds) for reloading a new clip.
|
|
||||||
*/
|
|
||||||
private final float reloadTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How fast the bullet travels (in m/s).
|
|
||||||
*/
|
|
||||||
private final float bulletSpeed;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How much damage the bullet does for a direct hit.
|
|
||||||
*/
|
|
||||||
private final float baseDamage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of bullets left in the current clip.
|
* Number of bullets left in the current clip.
|
||||||
|
@ -55,57 +14,20 @@ public class Gun implements Serializable {
|
||||||
*/
|
*/
|
||||||
private int clipCount;
|
private int clipCount;
|
||||||
|
|
||||||
private Gun(GunType type, int maxClipCount, int clipSize, int bulletsPerRound, float accuracy, float shotCooldownTime, float reloadTime, float bulletSpeed, float baseDamage) {
|
public Gun(GunType type, int currentClipBulletCount, int clipCount) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.maxClipCount = maxClipCount;
|
this.currentClipBulletCount = currentClipBulletCount;
|
||||||
this.clipSize = clipSize;
|
this.clipCount = clipCount;
|
||||||
this.bulletsPerRound = bulletsPerRound;
|
}
|
||||||
this.accuracy = accuracy;
|
|
||||||
this.shotCooldownTime = shotCooldownTime;
|
|
||||||
this.reloadTime = reloadTime;
|
|
||||||
this.bulletSpeed = bulletSpeed;
|
|
||||||
this.baseDamage = baseDamage;
|
|
||||||
|
|
||||||
this.currentClipBulletCount = 0;
|
public Gun(GunType type) {
|
||||||
this.clipCount = maxClipCount;
|
this(type, 0, type.getMaxClipCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
public GunType getType() {
|
public GunType getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMaxClipCount() {
|
|
||||||
return maxClipCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getClipSize() {
|
|
||||||
return clipSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getBulletsPerRound() {
|
|
||||||
return bulletsPerRound;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getAccuracy() {
|
|
||||||
return accuracy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getShotCooldownTime() {
|
|
||||||
return shotCooldownTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getReloadTime() {
|
|
||||||
return reloadTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getBulletSpeed() {
|
|
||||||
return bulletSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getBaseDamage() {
|
|
||||||
return baseDamage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCurrentClipBulletCount() {
|
public int getCurrentClipBulletCount() {
|
||||||
return currentClipBulletCount;
|
return currentClipBulletCount;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +37,7 @@ public class Gun implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refillClips() {
|
public void refillClips() {
|
||||||
this.clipCount = this.maxClipCount;
|
this.clipCount = this.type.getMaxClipCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void decrementBulletCount() {
|
public void decrementBulletCount() {
|
||||||
|
@ -133,36 +55,7 @@ public class Gun implements Serializable {
|
||||||
public void reload() {
|
public void reload() {
|
||||||
if (this.clipCount > 0) {
|
if (this.clipCount > 0) {
|
||||||
this.clipCount--;
|
this.clipCount--;
|
||||||
this.currentClipBulletCount = this.clipSize;
|
this.currentClipBulletCount = this.type.getClipSize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method to obtain a "dummy" gun for client-side rendering.
|
|
||||||
* TODO: Improve cleanliness so this isn't necessary.
|
|
||||||
* @param type The type of gun.
|
|
||||||
* @return The gun.
|
|
||||||
*/
|
|
||||||
public static Gun forType(GunType type) {
|
|
||||||
return new Gun(type, -1, -1, -1, -1, -1, -1, -1, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Gun forType(GunType type, int maxClipCount, int clipSize, int bulletsPerRound, int currentClipBulletCount, int clipCount) {
|
|
||||||
Gun g = new Gun(type, maxClipCount, clipSize, bulletsPerRound, -1, -1, -1, -1, -1);
|
|
||||||
g.currentClipBulletCount = currentClipBulletCount;
|
|
||||||
g.clipCount = clipCount;
|
|
||||||
return g;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Gun ak47() {
|
|
||||||
return new Gun(GunType.SMG, 4, 30, 1, 0.10f, 0.05f, 1.2f, 90, 40);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Gun m1Garand() {
|
|
||||||
return new Gun(GunType.RIFLE, 6, 8, 1, 0.02f, 0.75f, 1.5f, 150, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Gun winchester() {
|
|
||||||
return new Gun(GunType.SHOTGUN, 8, 4, 3, 0.15f, 0.5f, 2.0f, 75, 60);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package nl.andrewlalis.aos_core.model.tools;
|
||||||
|
|
||||||
|
public enum GunCategory {
|
||||||
|
SHOTGUN(0),
|
||||||
|
SMG(1),
|
||||||
|
RIFLE(2);
|
||||||
|
|
||||||
|
private final byte code;
|
||||||
|
|
||||||
|
GunCategory(int code) {
|
||||||
|
this.code = (byte) code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GunCategory get(byte code) {
|
||||||
|
for (var val : values()) {
|
||||||
|
if (val.code == code) return val;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,24 +1,113 @@
|
||||||
package nl.andrewlalis.aos_core.model.tools;
|
package nl.andrewlalis.aos_core.model.tools;
|
||||||
|
|
||||||
public enum GunType {
|
import java.io.Serializable;
|
||||||
SHOTGUN(0),
|
|
||||||
SMG(1),
|
|
||||||
RIFLE(2);
|
|
||||||
|
|
||||||
private final byte code;
|
/**
|
||||||
|
* Relatively constant configuration information about a particular type of gun,
|
||||||
|
* while not including state data for any single gun.
|
||||||
|
*/
|
||||||
|
public class GunType implements Serializable {
|
||||||
|
/**
|
||||||
|
* The name of this type of gun. Should be unique among all guns in a world.
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
/**
|
||||||
|
* The category of gun.
|
||||||
|
*/
|
||||||
|
private final GunCategory category;
|
||||||
|
/**
|
||||||
|
* The color of this type of gun, in hex.
|
||||||
|
*/
|
||||||
|
private final String color;
|
||||||
|
/**
|
||||||
|
* Maximum number of clips a player can carry when using this gun.
|
||||||
|
*/
|
||||||
|
private final int maxClipCount;
|
||||||
|
/**
|
||||||
|
* Number of bullets in each clip.
|
||||||
|
*/
|
||||||
|
private final int clipSize;
|
||||||
|
/**
|
||||||
|
* Number of bullets that are fired simultaneously per round. Usually only
|
||||||
|
* shotguns fire multiple.
|
||||||
|
*/
|
||||||
|
private final int bulletsPerRound;
|
||||||
|
/**
|
||||||
|
* How accurate shots from this gun are. 0 = never miss, 1 = complete random.
|
||||||
|
*/
|
||||||
|
private final float accuracy;
|
||||||
|
/**
|
||||||
|
* How long (in seconds) to wait after each shot, before another is shot.
|
||||||
|
*/
|
||||||
|
private final float shotCooldownTime;
|
||||||
|
/**
|
||||||
|
* How long (in seconds) for reloading a new clip.
|
||||||
|
*/
|
||||||
|
private final float reloadTime;
|
||||||
|
/**
|
||||||
|
* How fast the bullet travels (in m/s).
|
||||||
|
*/
|
||||||
|
private final float bulletSpeed;
|
||||||
|
/**
|
||||||
|
* How much damage the bullet does for a direct hit.
|
||||||
|
*/
|
||||||
|
private final float baseDamage;
|
||||||
|
|
||||||
GunType(int code) {
|
public GunType(String name, GunCategory category, String color, int maxClipCount, int clipSize, int bulletsPerRound, float accuracy, float shotCooldownTime, float reloadTime, float bulletSpeed, float baseDamage) {
|
||||||
this.code = (byte) code;
|
this.name = name;
|
||||||
|
this.category = category;
|
||||||
|
this.color = color;
|
||||||
|
this.maxClipCount = maxClipCount;
|
||||||
|
this.clipSize = clipSize;
|
||||||
|
this.bulletsPerRound = bulletsPerRound;
|
||||||
|
this.accuracy = accuracy;
|
||||||
|
this.shotCooldownTime = shotCooldownTime;
|
||||||
|
this.reloadTime = reloadTime;
|
||||||
|
this.bulletSpeed = bulletSpeed;
|
||||||
|
this.baseDamage = baseDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte getCode() {
|
public String getName() {
|
||||||
return code;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GunType get(byte code) {
|
public GunCategory getCategory() {
|
||||||
for (var val : values()) {
|
return category;
|
||||||
if (val.code == code) return val;
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
public String getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxClipCount() {
|
||||||
|
return maxClipCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getClipSize() {
|
||||||
|
return clipSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBulletsPerRound() {
|
||||||
|
return bulletsPerRound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getAccuracy() {
|
||||||
|
return accuracy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getShotCooldownTime() {
|
||||||
|
return shotCooldownTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getReloadTime() {
|
||||||
|
return reloadTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getBulletSpeed() {
|
||||||
|
return bulletSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getBaseDamage() {
|
||||||
|
return baseDamage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package nl.andrewlalis.aos_core.net;
|
||||||
|
|
||||||
|
public class ConnectionRejectedMessage extends Message {
|
||||||
|
private final String message;
|
||||||
|
|
||||||
|
public ConnectionRejectedMessage(String message) {
|
||||||
|
super(Type.CONNECTION_REJECTED);
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,5 +7,6 @@ public enum Type {
|
||||||
PLAYER_JOINED,
|
PLAYER_JOINED,
|
||||||
PLAYER_LEFT,
|
PLAYER_LEFT,
|
||||||
PLAYER_TEAM_CHANGE,
|
PLAYER_TEAM_CHANGE,
|
||||||
SERVER_SHUTDOWN
|
SERVER_SHUTDOWN,
|
||||||
|
CONNECTION_REJECTED
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,9 @@ public class PlayerDetailUpdate {
|
||||||
this.health = player.getHealth();
|
this.health = player.getHealth();
|
||||||
this.reloading = player.isReloading();
|
this.reloading = player.isReloading();
|
||||||
|
|
||||||
this.gunMaxClipCount = player.getGun().getMaxClipCount();
|
this.gunMaxClipCount = player.getGun().getType().getMaxClipCount();
|
||||||
this.gunClipSize = player.getGun().getClipSize();
|
this.gunClipSize = player.getGun().getType().getClipSize();
|
||||||
this.gunBulletsPerRound = player.getGun().getBulletsPerRound();
|
this.gunBulletsPerRound = player.getGun().getType().getBulletsPerRound();
|
||||||
this.gunCurrentClipBulletCount = player.getGun().getCurrentClipBulletCount();
|
this.gunCurrentClipBulletCount = player.getGun().getCurrentClipBulletCount();
|
||||||
this.gunClipCount = player.getGun().getClipCount();
|
this.gunClipCount = player.getGun().getClipCount();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,15 @@ package nl.andrewlalis.aos_core.net.data;
|
||||||
|
|
||||||
import nl.andrewlalis.aos_core.geom.Vec2;
|
import nl.andrewlalis.aos_core.geom.Vec2;
|
||||||
import nl.andrewlalis.aos_core.model.Player;
|
import nl.andrewlalis.aos_core.model.Player;
|
||||||
import nl.andrewlalis.aos_core.model.tools.GunType;
|
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data that's sent to all clients about a player, and contains only the
|
||||||
|
* information needed to render the player on the screen.
|
||||||
|
*/
|
||||||
public class PlayerUpdate {
|
public class PlayerUpdate {
|
||||||
public static final int BYTES = Integer.BYTES + 6 * Float.BYTES + 1;
|
public static final int BYTES = Integer.BYTES + 6 * Float.BYTES + 1;
|
||||||
|
|
||||||
|
@ -15,22 +18,22 @@ public class PlayerUpdate {
|
||||||
private final Vec2 position;
|
private final Vec2 position;
|
||||||
private final Vec2 orientation;
|
private final Vec2 orientation;
|
||||||
private final Vec2 velocity;
|
private final Vec2 velocity;
|
||||||
private final GunType gunType;
|
private final String gunTypeName;
|
||||||
|
|
||||||
public PlayerUpdate(Player player) {
|
public PlayerUpdate(Player player) {
|
||||||
this.id = player.getId();
|
this.id = player.getId();
|
||||||
this.position = player.getPosition();
|
this.position = player.getPosition();
|
||||||
this.orientation = player.getOrientation();
|
this.orientation = player.getOrientation();
|
||||||
this.velocity = player.getVelocity();
|
this.velocity = player.getVelocity();
|
||||||
this.gunType = player.getGun().getType();
|
this.gunTypeName = player.getGun().getType().getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerUpdate(int id, Vec2 position, Vec2 orientation, Vec2 velocity, GunType gunType) {
|
public PlayerUpdate(int id, Vec2 position, Vec2 orientation, Vec2 velocity, String gunTypeName) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.position = position;
|
this.position = position;
|
||||||
this.orientation = orientation;
|
this.orientation = orientation;
|
||||||
this.velocity = velocity;
|
this.velocity = velocity;
|
||||||
this.gunType = gunType;
|
this.gunTypeName = gunTypeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getId() {
|
public int getId() {
|
||||||
|
@ -49,8 +52,8 @@ public class PlayerUpdate {
|
||||||
return velocity;
|
return velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GunType getGunType() {
|
public String getGunTypeName() {
|
||||||
return gunType;
|
return gunTypeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(DataOutputStream out) throws IOException {
|
public void write(DataOutputStream out) throws IOException {
|
||||||
|
@ -61,16 +64,17 @@ public class PlayerUpdate {
|
||||||
out.writeFloat(this.orientation.y());
|
out.writeFloat(this.orientation.y());
|
||||||
out.writeFloat(this.velocity.x());
|
out.writeFloat(this.velocity.x());
|
||||||
out.writeFloat(this.velocity.y());
|
out.writeFloat(this.velocity.y());
|
||||||
out.writeByte(this.gunType.getCode());
|
out.writeInt(this.gunTypeName.length());
|
||||||
|
out.writeBytes(this.gunTypeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlayerUpdate read(DataInputStream in) throws IOException {
|
public static PlayerUpdate read(DataInputStream in) throws IOException {
|
||||||
return new PlayerUpdate(
|
int id = in.readInt();
|
||||||
in.readInt(),
|
Vec2 position = Vec2.read(in);
|
||||||
Vec2.read(in),
|
Vec2 orientation = Vec2.read(in);
|
||||||
Vec2.read(in),
|
Vec2 velocity = Vec2.read(in);
|
||||||
Vec2.read(in),
|
int gunTypeNameLength = in.readInt();
|
||||||
GunType.get(in.readByte())
|
String gunTypeName = new String(in.readNBytes(gunTypeNameLength));
|
||||||
);
|
return new PlayerUpdate(id, position, orientation, velocity, gunTypeName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,4 +2,8 @@ module aos_server {
|
||||||
requires java.logging;
|
requires java.logging;
|
||||||
requires aos_core;
|
requires aos_core;
|
||||||
requires java.desktop;
|
requires java.desktop;
|
||||||
|
requires com.fasterxml.jackson.databind;
|
||||||
|
requires com.fasterxml.jackson.dataformat.yaml;
|
||||||
|
|
||||||
|
opens nl.andrewlalis.aos_server.settings to com.fasterxml.jackson.databind;
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@ package nl.andrewlalis.aos_server;
|
||||||
import nl.andrewlalis.aos_core.model.Player;
|
import nl.andrewlalis.aos_core.model.Player;
|
||||||
import nl.andrewlalis.aos_core.net.chat.ChatMessage;
|
import nl.andrewlalis.aos_core.net.chat.ChatMessage;
|
||||||
import nl.andrewlalis.aos_core.net.chat.PlayerChatMessage;
|
import nl.andrewlalis.aos_core.net.chat.PlayerChatMessage;
|
||||||
|
import nl.andrewlalis.aos_server.command.GunsCommand;
|
||||||
import nl.andrewlalis.aos_server.command.ResetCommand;
|
import nl.andrewlalis.aos_server.command.ResetCommand;
|
||||||
import nl.andrewlalis.aos_server.command.chat.ChatCommand;
|
import nl.andrewlalis.aos_server.command.chat.ChatCommand;
|
||||||
import nl.andrewlalis.aos_server.command.chat.GunCommand;
|
import nl.andrewlalis.aos_server.command.chat.GunCommand;
|
||||||
|
@ -25,6 +26,7 @@ public class ChatManager {
|
||||||
this.chatCommands = new ConcurrentHashMap<>();
|
this.chatCommands = new ConcurrentHashMap<>();
|
||||||
this.chatCommands.put("gun", new GunCommand());
|
this.chatCommands.put("gun", new GunCommand());
|
||||||
this.chatCommands.put("reset", new ResetCommand(server));
|
this.chatCommands.put("reset", new ResetCommand(server));
|
||||||
|
this.chatCommands.put("guns", new GunsCommand(server));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handlePlayerChat(ClientHandler handler, Player player, ChatMessage msg) {
|
public void handlePlayerChat(ClientHandler handler, Player player, ChatMessage msg) {
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
package nl.andrewlalis.aos_server;
|
package nl.andrewlalis.aos_server;
|
||||||
|
|
||||||
import nl.andrewlalis.aos_core.model.Player;
|
import nl.andrewlalis.aos_core.model.Player;
|
||||||
import nl.andrewlalis.aos_core.net.IdentMessage;
|
import nl.andrewlalis.aos_core.net.*;
|
||||||
import nl.andrewlalis.aos_core.net.Message;
|
|
||||||
import nl.andrewlalis.aos_core.net.PlayerRegisteredMessage;
|
|
||||||
import nl.andrewlalis.aos_core.net.Type;
|
|
||||||
import nl.andrewlalis.aos_core.net.chat.ChatMessage;
|
import nl.andrewlalis.aos_core.net.chat.ChatMessage;
|
||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
|
@ -53,6 +50,10 @@ public class ClientHandler extends Thread {
|
||||||
* @throws IOException If initialization could not be completed.
|
* @throws IOException If initialization could not be completed.
|
||||||
*/
|
*/
|
||||||
private void initializeConnection() throws IOException {
|
private void initializeConnection() throws IOException {
|
||||||
|
if (this.server.getPlayerCount() > this.server.getSettings().getMaxPlayers()) {
|
||||||
|
this.send(new ConnectionRejectedMessage("Server is full."));
|
||||||
|
throw new IOException("Client cannot join because server is full.");
|
||||||
|
}
|
||||||
boolean connectionEstablished = false;
|
boolean connectionEstablished = false;
|
||||||
int attempts = 0;
|
int attempts = 0;
|
||||||
while (!connectionEstablished && attempts < 100) {
|
while (!connectionEstablished && attempts < 100) {
|
||||||
|
@ -74,6 +75,10 @@ public class ClientHandler extends Thread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Server getServer() {
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
public Player getPlayer() {
|
public Player getPlayer() {
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
@ -132,7 +137,7 @@ public class ClientHandler extends Thread {
|
||||||
this.server.getChatManager().handlePlayerChat(this, this.player, (ChatMessage) msg);
|
this.server.getChatManager().handlePlayerChat(this, this.player, (ChatMessage) msg);
|
||||||
}
|
}
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
if (e.getMessage().equals("Socket closed")) {
|
if (e.getMessage().equals("Socket closed") | e.getMessage().equals("Connection reset")) {
|
||||||
this.shutdown();
|
this.shutdown();
|
||||||
} else {
|
} else {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
package nl.andrewlalis.aos_server;
|
package nl.andrewlalis.aos_server;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||||
|
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||||
import nl.andrewlalis.aos_core.geom.Vec2;
|
import nl.andrewlalis.aos_core.geom.Vec2;
|
||||||
import nl.andrewlalis.aos_core.model.*;
|
import nl.andrewlalis.aos_core.model.*;
|
||||||
|
import nl.andrewlalis.aos_core.model.tools.GunCategory;
|
||||||
|
import nl.andrewlalis.aos_core.model.tools.GunType;
|
||||||
import nl.andrewlalis.aos_core.net.Message;
|
import nl.andrewlalis.aos_core.net.Message;
|
||||||
import nl.andrewlalis.aos_core.net.PlayerUpdateMessage;
|
import nl.andrewlalis.aos_core.net.PlayerUpdateMessage;
|
||||||
import nl.andrewlalis.aos_core.net.Type;
|
import nl.andrewlalis.aos_core.net.Type;
|
||||||
|
@ -10,6 +16,7 @@ import nl.andrewlalis.aos_core.net.data.DataTypes;
|
||||||
import nl.andrewlalis.aos_core.net.data.PlayerDetailUpdate;
|
import nl.andrewlalis.aos_core.net.data.PlayerDetailUpdate;
|
||||||
import nl.andrewlalis.aos_core.net.data.WorldUpdate;
|
import nl.andrewlalis.aos_core.net.data.WorldUpdate;
|
||||||
import nl.andrewlalis.aos_core.util.ByteUtils;
|
import nl.andrewlalis.aos_core.util.ByteUtils;
|
||||||
|
import nl.andrewlalis.aos_server.settings.ServerSettings;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -17,12 +24,11 @@ import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Scanner;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
public class Server {
|
public class Server {
|
||||||
public static final int DEFAULT_PORT = 8035;
|
private final ServerSettings settings;
|
||||||
|
|
||||||
private final List<ClientHandler> clientHandlers;
|
private final List<ClientHandler> clientHandlers;
|
||||||
private final ServerSocket serverSocket;
|
private final ServerSocket serverSocket;
|
||||||
|
@ -34,10 +40,11 @@ public class Server {
|
||||||
|
|
||||||
private volatile boolean running;
|
private volatile boolean running;
|
||||||
|
|
||||||
public Server(int port) throws IOException {
|
public Server(ServerSettings settings) throws IOException {
|
||||||
|
this.settings = settings;
|
||||||
this.clientHandlers = new CopyOnWriteArrayList<>();
|
this.clientHandlers = new CopyOnWriteArrayList<>();
|
||||||
this.serverSocket = new ServerSocket(port);
|
this.serverSocket = new ServerSocket(settings.getPort());
|
||||||
this.dataTransceiver = new DataTransceiver(this, port);
|
this.dataTransceiver = new DataTransceiver(this, settings.getPort());
|
||||||
this.cli = new ServerCli(this);
|
this.cli = new ServerCli(this);
|
||||||
this.world = new World(new Vec2(50, 70));
|
this.world = new World(new Vec2(50, 70));
|
||||||
this.initWorld();
|
this.initWorld();
|
||||||
|
@ -45,7 +52,27 @@ public class Server {
|
||||||
this.chatManager = new ChatManager(this);
|
this.chatManager = new ChatManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ServerSettings getSettings() {
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
private void initWorld() {
|
private void initWorld() {
|
||||||
|
for (var gs : this.settings.getGunSettings()) {
|
||||||
|
this.world.getGunTypes().put(gs.getName(), new GunType(
|
||||||
|
gs.getName(),
|
||||||
|
GunCategory.valueOf(gs.getCategory().toUpperCase()),
|
||||||
|
gs.getColor(),
|
||||||
|
gs.getMaxClipCount(),
|
||||||
|
gs.getClipSize(),
|
||||||
|
gs.getBulletsPerRound(),
|
||||||
|
gs.getAccuracy(),
|
||||||
|
gs.getShotCooldownTime(),
|
||||||
|
gs.getReloadTime(),
|
||||||
|
gs.getBulletSpeed(),
|
||||||
|
gs.getBaseDamage()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
world.getBarricades().add(new Barricade(10, 10, 30, 5));
|
world.getBarricades().add(new Barricade(10, 10, 30, 5));
|
||||||
world.getBarricades().add(new Barricade(10, 55, 30, 5));
|
world.getBarricades().add(new Barricade(10, 55, 30, 5));
|
||||||
world.getBarricades().add(new Barricade(20, 30, 10, 10));
|
world.getBarricades().add(new Barricade(20, 30, 10, 10));
|
||||||
|
@ -76,6 +103,10 @@ public class Server {
|
||||||
return chatManager;
|
return chatManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getPlayerCount() {
|
||||||
|
return this.clientHandlers.size();
|
||||||
|
}
|
||||||
|
|
||||||
public void acceptClientConnection() {
|
public void acceptClientConnection() {
|
||||||
try {
|
try {
|
||||||
Socket socket = this.serverSocket.accept();
|
Socket socket = this.serverSocket.accept();
|
||||||
|
@ -100,7 +131,7 @@ public class Server {
|
||||||
team = t;
|
team = t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Player p = new Player(id, name, team);
|
Player p = new Player(id, name, team, this.world.getGunTypes().get(this.settings.getPlayerSettings().getDefaultGun()));
|
||||||
this.world.getPlayers().put(p.getId(), p);
|
this.world.getPlayers().put(p.getId(), p);
|
||||||
String message = p.getName() + " connected.";
|
String message = p.getName() + " connected.";
|
||||||
this.broadcastMessage(new SystemChatMessage(SystemChatMessage.Level.INFO, message));
|
this.broadcastMessage(new SystemChatMessage(SystemChatMessage.Level.INFO, message));
|
||||||
|
@ -215,20 +246,11 @@ public class Server {
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
System.out.println("Enter the port number to start the server on, or blank for default (" + DEFAULT_PORT + "):");
|
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
|
||||||
Scanner sc = new Scanner(System.in);
|
mapper.setPropertyNamingStrategy(PropertyNamingStrategies.KEBAB_CASE);
|
||||||
String input = sc.nextLine();
|
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
int port = DEFAULT_PORT;
|
var settings = mapper.readValue(Server.class.getClassLoader().getResourceAsStream("default_settings.yaml"), ServerSettings.class);
|
||||||
if (input != null && !input.isBlank()) {
|
Server server = new Server(settings);
|
||||||
try {
|
|
||||||
port = Integer.parseInt(input.trim());
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
System.err.println("Invalid port.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Server server = new Server(port);
|
|
||||||
server.run();
|
server.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ public class ServerCli extends Thread {
|
||||||
|
|
||||||
this.commands.put("list", new ListPlayersCommand(server));
|
this.commands.put("list", new ListPlayersCommand(server));
|
||||||
this.commands.put("kick", new KickCommand(server));
|
this.commands.put("kick", new KickCommand(server));
|
||||||
|
this.commands.put("guns", new GunsCommand(server));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
|
|
|
@ -2,7 +2,7 @@ package nl.andrewlalis.aos_server;
|
||||||
|
|
||||||
import nl.andrewlalis.aos_core.geom.Vec2;
|
import nl.andrewlalis.aos_core.geom.Vec2;
|
||||||
import nl.andrewlalis.aos_core.model.*;
|
import nl.andrewlalis.aos_core.model.*;
|
||||||
import nl.andrewlalis.aos_core.model.tools.GunType;
|
import nl.andrewlalis.aos_core.model.tools.GunCategory;
|
||||||
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
|
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
|
||||||
import nl.andrewlalis.aos_core.net.data.Sound;
|
import nl.andrewlalis.aos_core.net.data.Sound;
|
||||||
import nl.andrewlalis.aos_core.net.data.SoundType;
|
import nl.andrewlalis.aos_core.net.data.SoundType;
|
||||||
|
@ -12,6 +12,12 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The world updater thread is responsible for periodically updating the server
|
||||||
|
* world data in a "tick" method. At each tick, we compute physics updates for
|
||||||
|
* every player, bullet, and other movable object in the world, and check for
|
||||||
|
* various interactions.
|
||||||
|
*/
|
||||||
public class WorldUpdater extends Thread {
|
public class WorldUpdater extends Thread {
|
||||||
public static final double TARGET_TPS = 120.0;
|
public static final double TARGET_TPS = 120.0;
|
||||||
public static final double MS_PER_TICK = 1000.0 / TARGET_TPS;
|
public static final double MS_PER_TICK = 1000.0 / TARGET_TPS;
|
||||||
|
@ -66,6 +72,7 @@ public class WorldUpdater extends Thread {
|
||||||
for (Player p : this.world.getPlayers().values()) {
|
for (Player p : this.world.getPlayers().values()) {
|
||||||
this.updatePlayerMovement(p, t);
|
this.updatePlayerMovement(p, t);
|
||||||
this.updatePlayerShooting(p);
|
this.updatePlayerShooting(p);
|
||||||
|
p.setHealth(Math.min(p.getHealth() + Player.HEALTH_REGEN_RATE * t, Player.MAX_HEALTH));
|
||||||
this.worldUpdate.addPlayer(p);
|
this.worldUpdate.addPlayer(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,18 +86,64 @@ public class WorldUpdater extends Thread {
|
||||||
}
|
}
|
||||||
p.setOrientation(newOrientation);
|
p.setOrientation(newOrientation);
|
||||||
}
|
}
|
||||||
float vx = 0;
|
|
||||||
float vy = 0;
|
Vec2 forward = Vec2.UP;
|
||||||
if (p.getState().isMovingForward()) vy += Player.MOVEMENT_SPEED;
|
|
||||||
if (p.getState().isMovingBackward()) vy -= Player.MOVEMENT_SPEED;
|
|
||||||
if (p.getState().isMovingLeft()) vx -= Player.MOVEMENT_SPEED;
|
|
||||||
if (p.getState().isMovingRight()) vx += Player.MOVEMENT_SPEED;
|
|
||||||
Vec2 forwardVector = new Vec2(0, -1);
|
|
||||||
if (p.getTeam() != null) {
|
if (p.getTeam() != null) {
|
||||||
forwardVector = p.getTeam().getOrientation();
|
forward = p.getTeam().getOrientation();
|
||||||
}
|
}
|
||||||
Vec2 leftVector = forwardVector.perp();
|
Vec2 left = forward.perp();
|
||||||
Vec2 newPos = p.getPosition().add(forwardVector.mul(vy * t)).add(leftVector.mul(vx * t));
|
|
||||||
|
// Compute changes to player velocity due to control input.
|
||||||
|
Vec2 localVelocity = p.getVelocity().rotate(-left.angle());
|
||||||
|
float vx = localVelocity.x();
|
||||||
|
float vy = localVelocity.y();
|
||||||
|
if (p.getState().isMovingForward()) {
|
||||||
|
vy -= Player.MOVEMENT_ACCELERATION * t;
|
||||||
|
}
|
||||||
|
if (p.getState().isMovingBackward()) {
|
||||||
|
vy += Player.MOVEMENT_ACCELERATION * t;
|
||||||
|
}
|
||||||
|
if (p.getState().isMovingLeft()) {
|
||||||
|
vx -= Player.MOVEMENT_ACCELERATION * t;
|
||||||
|
}
|
||||||
|
if (p.getState().isMovingRight()) {
|
||||||
|
vx += Player.MOVEMENT_ACCELERATION * t;
|
||||||
|
}
|
||||||
|
// Compute deceleration.
|
||||||
|
if (p.getState().isMovingForward() == p.getState().isMovingBackward()) {
|
||||||
|
if (vy > 0) {
|
||||||
|
vy = Math.max(0.0f, vy - Player.MOVEMENT_DECELERATION * t);
|
||||||
|
} else {
|
||||||
|
vy = Math.min(0.0f, vy + Player.MOVEMENT_DECELERATION * t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p.getState().isMovingLeft() == p.getState().isMovingRight()) {
|
||||||
|
if (vx > 0) {
|
||||||
|
vx = Math.max(0.0f, vx - Player.MOVEMENT_DECELERATION * t);
|
||||||
|
} else {
|
||||||
|
vx = Math.min(0.0f, vx + Player.MOVEMENT_DECELERATION * t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Vec2 newLocalVelocity = new Vec2(vx, vy);
|
||||||
|
if (newLocalVelocity.mag() < Player.MOVEMENT_THRESHOLD) {
|
||||||
|
newLocalVelocity = Vec2.ZERO;
|
||||||
|
}
|
||||||
|
float speedLimit;
|
||||||
|
if (p.isSprinting()) {
|
||||||
|
speedLimit = Player.MOVEMENT_SPEED_SPRINT;
|
||||||
|
} else if (p.isSneaking()) {
|
||||||
|
speedLimit = Player.MOVEMENT_SPEED_SNEAK;
|
||||||
|
} else {
|
||||||
|
speedLimit = Player.MOVEMENT_SPEED;
|
||||||
|
}
|
||||||
|
if (newLocalVelocity.mag() > speedLimit) {
|
||||||
|
newLocalVelocity = newLocalVelocity.mul(speedLimit / newLocalVelocity.mag());
|
||||||
|
}
|
||||||
|
p.setVelocity(newLocalVelocity.rotate(left.angle()));
|
||||||
|
|
||||||
|
Vec2 newPos = p.getPosition().add(p.getVelocity().mul(t));
|
||||||
float nx = newPos.x();
|
float nx = newPos.x();
|
||||||
float ny = newPos.y();
|
float ny = newPos.y();
|
||||||
|
|
||||||
|
@ -130,15 +183,15 @@ public class WorldUpdater extends Thread {
|
||||||
|
|
||||||
private void updatePlayerShooting(Player p) {
|
private void updatePlayerShooting(Player p) {
|
||||||
if (p.canUseWeapon()) {
|
if (p.canUseWeapon()) {
|
||||||
for (int i = 0; i < p.getGun().getBulletsPerRound(); i++) {
|
for (int i = 0; i < p.getGun().getType().getBulletsPerRound(); i++) {
|
||||||
Bullet b = new Bullet(p);
|
Bullet b = new Bullet(p);
|
||||||
this.world.getBullets().add(b);
|
this.world.getBullets().add(b);
|
||||||
this.worldUpdate.addBullet(b);
|
this.worldUpdate.addBullet(b);
|
||||||
}
|
}
|
||||||
SoundType soundType = SoundType.SHOT_SMG;
|
SoundType soundType = SoundType.SHOT_SMG;
|
||||||
if (p.getGun().getType() == GunType.RIFLE) {
|
if (p.getGun().getType().getCategory() == GunCategory.RIFLE) {
|
||||||
soundType = SoundType.SHOT_RIFLE;
|
soundType = SoundType.SHOT_RIFLE;
|
||||||
} else if (p.getGun().getType() == GunType.SHOTGUN) {
|
} else if (p.getGun().getType().getCategory() == GunCategory.SHOTGUN) {
|
||||||
soundType = SoundType.SHOT_SHOTGUN;
|
soundType = SoundType.SHOT_SHOTGUN;
|
||||||
}
|
}
|
||||||
this.worldUpdate.addSound(new Sound(p.getPosition(), 1.0f, soundType));
|
this.worldUpdate.addSound(new Sound(p.getPosition(), 1.0f, soundType));
|
||||||
|
@ -184,13 +237,20 @@ public class WorldUpdater extends Thread {
|
||||||
float y2 = b.getPosition().y();
|
float y2 = b.getPosition().y();
|
||||||
float lineDist = oldPos.dist(b.getPosition());
|
float lineDist = oldPos.dist(b.getPosition());
|
||||||
for (Player p : this.world.getPlayers().values()) {
|
for (Player p : this.world.getPlayers().values()) {
|
||||||
|
if (
|
||||||
|
!server.getSettings().getTeamSettings().friendlyFireEnabled() &&
|
||||||
|
b.getPlayer() != null && p.getTeam() != null &&
|
||||||
|
p.getTeam().equals(b.getPlayer().getTeam())
|
||||||
|
) {
|
||||||
|
continue; // Don't check collisions against teammates if friendly fire is off.
|
||||||
|
}
|
||||||
float n = ((p.getPosition().x() - x1) * (x2 - x1) + (p.getPosition().y() - y1) * (y2 - y1)) / lineDist;
|
float n = ((p.getPosition().x() - x1) * (x2 - x1) + (p.getPosition().y() - y1) * (y2 - y1)) / lineDist;
|
||||||
n = Math.max(Math.min(n, 1), 0);
|
n = Math.max(Math.min(n, 1), 0);
|
||||||
double dist = p.getPosition().dist(new Vec2(x1 + n * (x2 - x1), y1 + n * (y2 - y1)));
|
double dist = p.getPosition().dist(new Vec2(x1 + n * (x2 - x1), y1 + n * (y2 - y1)));
|
||||||
if (dist < Player.RADIUS && (p.getTeam() == null || p.getTeam().getSpawnPoint().dist(p.getPosition()) > Team.SPAWN_RADIUS)) {
|
if (dist < Player.RADIUS && (p.getTeam() == null || p.getTeam().getSpawnPoint().dist(p.getPosition()) > Team.SPAWN_RADIUS)) {
|
||||||
|
|
||||||
// Player was shot!
|
// Player was shot!
|
||||||
float damage = (float) (((Player.RADIUS - dist) / Player.RADIUS) * b.getGun().getBaseDamage());
|
float damage = (float) (((Player.RADIUS - dist) / Player.RADIUS) * b.getGun().getType().getBaseDamage());
|
||||||
p.takeDamage(damage);
|
p.takeDamage(damage);
|
||||||
if (p.getHealth() == 0.0f) {
|
if (p.getHealth() == 0.0f) {
|
||||||
Player shooter = this.world.getPlayers().get(b.getPlayerId());
|
Player shooter = this.world.getPlayers().get(b.getPlayerId());
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package nl.andrewlalis.aos_server.command;
|
||||||
|
|
||||||
|
import nl.andrewlalis.aos_core.model.Player;
|
||||||
|
import nl.andrewlalis.aos_core.model.tools.GunType;
|
||||||
|
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
|
||||||
|
import nl.andrewlalis.aos_server.ClientHandler;
|
||||||
|
import nl.andrewlalis.aos_server.Server;
|
||||||
|
import nl.andrewlalis.aos_server.command.chat.ChatCommand;
|
||||||
|
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class GunsCommand implements Command, ChatCommand {
|
||||||
|
private final Server server;
|
||||||
|
|
||||||
|
public GunsCommand(Server server) {
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(String[] args) {
|
||||||
|
for (var gunType : this.server.getWorld().getGunTypes().values()) {
|
||||||
|
System.out.println(gunType.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(ClientHandler handler, Player player, String[] args) {
|
||||||
|
String msg = handler.getServer().getWorld().getGunTypes().values().stream().map(GunType::getName).collect(Collectors.joining(", "));
|
||||||
|
handler.send(new SystemChatMessage(SystemChatMessage.Level.INFO, msg));
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,7 +27,7 @@ public class ListPlayersCommand implements Command {
|
||||||
player.getTeam() == null ? "none" : player.getTeam().getName(),
|
player.getTeam() == null ? "none" : player.getTeam().getName(),
|
||||||
player.getHealth(),
|
player.getHealth(),
|
||||||
Player.MAX_HEALTH,
|
Player.MAX_HEALTH,
|
||||||
player.getGun().getType().name()
|
player.getGun().getType().getName()
|
||||||
))
|
))
|
||||||
.collect(Collectors.joining("\n"));
|
.collect(Collectors.joining("\n"));
|
||||||
System.out.println(message);
|
System.out.println(message);
|
||||||
|
|
|
@ -2,23 +2,32 @@ package nl.andrewlalis.aos_server.command.chat;
|
||||||
|
|
||||||
import nl.andrewlalis.aos_core.model.Player;
|
import nl.andrewlalis.aos_core.model.Player;
|
||||||
import nl.andrewlalis.aos_core.model.tools.Gun;
|
import nl.andrewlalis.aos_core.model.tools.Gun;
|
||||||
|
import nl.andrewlalis.aos_core.model.tools.GunType;
|
||||||
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
|
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
|
||||||
import nl.andrewlalis.aos_server.ClientHandler;
|
import nl.andrewlalis.aos_server.ClientHandler;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
public class GunCommand implements ChatCommand {
|
public class GunCommand implements ChatCommand {
|
||||||
@Override
|
@Override
|
||||||
public void execute(ClientHandler handler, Player player, String[] args) {
|
public void execute(ClientHandler handler, Player player, String[] args) {
|
||||||
if (args.length < 1) {
|
if (args.length < 1) {
|
||||||
|
handler.send(new SystemChatMessage(SystemChatMessage.Level.WARNING, "No gun name specified."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String gunName = args[0];
|
String gunName = String.join(" ", args);
|
||||||
if (gunName.equalsIgnoreCase("smg")) {
|
GunType gunType = null;
|
||||||
player.setGun(Gun.ak47());
|
for (GunType type : handler.getServer().getWorld().getGunTypes().values()) {
|
||||||
} else if (gunName.equalsIgnoreCase("rifle")) {
|
if (type.getName().equalsIgnoreCase(gunName)) {
|
||||||
player.setGun(Gun.m1Garand());
|
gunType = type;
|
||||||
} else if (gunName.equalsIgnoreCase("shotgun")) {
|
break;
|
||||||
player.setGun(Gun.winchester());
|
}
|
||||||
}
|
}
|
||||||
handler.send(new SystemChatMessage(SystemChatMessage.Level.INFO, "Changed gun to " + player.getGun().getType().name() + "."));
|
if (gunType == null) {
|
||||||
|
handler.send(new SystemChatMessage(SystemChatMessage.Level.WARNING, "Unknown gun name."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
player.setGun(new Gun(gunType));
|
||||||
|
handler.send(new SystemChatMessage(SystemChatMessage.Level.INFO, "Changed gun to " + player.getGun().getType().getName() + "."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
package nl.andrewlalis.aos_server.settings;
|
||||||
|
|
||||||
|
public class GunSettings {
|
||||||
|
private String name;
|
||||||
|
private String category;
|
||||||
|
private String color;
|
||||||
|
private int maxClipCount;
|
||||||
|
private int clipSize;
|
||||||
|
private int bulletsPerRound;
|
||||||
|
private float accuracy;
|
||||||
|
private float shotCooldownTime;
|
||||||
|
private float reloadTime;
|
||||||
|
private float bulletSpeed;
|
||||||
|
private float baseDamage;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCategory() {
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxClipCount() {
|
||||||
|
return maxClipCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getClipSize() {
|
||||||
|
return clipSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBulletsPerRound() {
|
||||||
|
return bulletsPerRound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getAccuracy() {
|
||||||
|
return accuracy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getShotCooldownTime() {
|
||||||
|
return shotCooldownTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getReloadTime() {
|
||||||
|
return reloadTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getBulletSpeed() {
|
||||||
|
return bulletSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getBaseDamage() {
|
||||||
|
return baseDamage;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package nl.andrewlalis.aos_server.settings;
|
||||||
|
|
||||||
|
public class PlayerSettings {
|
||||||
|
private float speed;
|
||||||
|
private float sprintSpeed;
|
||||||
|
private float sneakSpeed;
|
||||||
|
private float acceleration;
|
||||||
|
private float deceleration;
|
||||||
|
private float radius;
|
||||||
|
private float resupplyCooldown;
|
||||||
|
private float maxHealth;
|
||||||
|
private float healthRegenRate;
|
||||||
|
private float sneakAccuracyModifier;
|
||||||
|
private float sprintAccuracyModifier;
|
||||||
|
private String defaultGun;
|
||||||
|
|
||||||
|
public float getSpeed() {
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getSprintSpeed() {
|
||||||
|
return sprintSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getSneakSpeed() {
|
||||||
|
return sneakSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getAcceleration() {
|
||||||
|
return acceleration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getDeceleration() {
|
||||||
|
return deceleration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getRadius() {
|
||||||
|
return radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getResupplyCooldown() {
|
||||||
|
return resupplyCooldown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMaxHealth() {
|
||||||
|
return maxHealth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getHealthRegenRate() {
|
||||||
|
return healthRegenRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getSneakAccuracyModifier() {
|
||||||
|
return sneakAccuracyModifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getSprintAccuracyModifier() {
|
||||||
|
return sprintAccuracyModifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDefaultGun() {
|
||||||
|
return defaultGun;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package nl.andrewlalis.aos_server.settings;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ServerSettings {
|
||||||
|
private int port;
|
||||||
|
private int maxPlayers;
|
||||||
|
private float ticksPerSecond;
|
||||||
|
private PlayerSettings playerSettings;
|
||||||
|
private TeamSettings teamSettings;
|
||||||
|
private List<GunSettings> gunSettings;
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxPlayers() {
|
||||||
|
return maxPlayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getTicksPerSecond() {
|
||||||
|
return ticksPerSecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerSettings getPlayerSettings() {
|
||||||
|
return playerSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TeamSettings getTeamSettings() {
|
||||||
|
return teamSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<GunSettings> getGunSettings() {
|
||||||
|
return gunSettings;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package nl.andrewlalis.aos_server.settings;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
public class TeamSettings {
|
||||||
|
private float spawnPointRadius;
|
||||||
|
private float supplyPointRadius;
|
||||||
|
@JsonProperty("friendly-fire")
|
||||||
|
private boolean friendlyFire;
|
||||||
|
|
||||||
|
public float getSpawnPointRadius() {
|
||||||
|
return spawnPointRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getSupplyPointRadius() {
|
||||||
|
return supplyPointRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean friendlyFireEnabled() {
|
||||||
|
return friendlyFire;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
port: 8035
|
||||||
|
max-players: 32
|
||||||
|
ticks-per-second: 120
|
||||||
|
|
||||||
|
# Settings that control player behavior.
|
||||||
|
player-settings:
|
||||||
|
speed: 10
|
||||||
|
sprint-speed: 18
|
||||||
|
sneak-speed: 5
|
||||||
|
acceleration: 60
|
||||||
|
deceleration: 30
|
||||||
|
radius: 0.5
|
||||||
|
resupply-cooldown: 30
|
||||||
|
max-health: 100
|
||||||
|
health-regen-rate: 1.0
|
||||||
|
sneak-accuracy-modifier: 0.5
|
||||||
|
sprint-accuracy-modifier: 1.5
|
||||||
|
# Should be the name of one of the guns defined in "gun-settings".
|
||||||
|
default-gun: M1 Garand
|
||||||
|
|
||||||
|
# Settings for team mechanics.
|
||||||
|
team-settings:
|
||||||
|
spawn-point-radius: 3
|
||||||
|
supply-point-radius: 2
|
||||||
|
friendly-fire: false
|
||||||
|
|
||||||
|
# The list of available guns are defined in this list.
|
||||||
|
gun-settings:
|
||||||
|
- name: AK-47
|
||||||
|
category: SMG
|
||||||
|
color: "#2e2b26"
|
||||||
|
max-clip-count: 4
|
||||||
|
clip-size: 30
|
||||||
|
bullets-per-round: 1
|
||||||
|
accuracy: 0.10
|
||||||
|
shot-cooldown-time: 0.05
|
||||||
|
reload-time: 1.2
|
||||||
|
bullet-speed: 90
|
||||||
|
base-damage: 40
|
||||||
|
|
||||||
|
- name: M1 Garand
|
||||||
|
category: RIFLE
|
||||||
|
color: "#452d06"
|
||||||
|
max-clip-count: 10
|
||||||
|
clip-size: 8
|
||||||
|
bullets-per-round: 1
|
||||||
|
accuracy: 0.02
|
||||||
|
shot-cooldown-time: 0.75
|
||||||
|
reload-time: 0.75
|
||||||
|
bullet-speed: 150
|
||||||
|
base-damage: 100
|
||||||
|
|
||||||
|
- name: Winchester
|
||||||
|
category: SHOTGUN
|
||||||
|
color: "#1a1205"
|
||||||
|
max-clip-count: 8
|
||||||
|
clip-size: 6
|
||||||
|
bullets-per-round: 3
|
||||||
|
accuracy: 0.15
|
||||||
|
shot-cooldown-time: 0.5
|
||||||
|
reload-time: 2.0
|
||||||
|
bullet-speed: 75
|
||||||
|
base-damage: 80
|
Loading…
Reference in New Issue