Added KD command, team chat command, and synchronized team scores over network.
This commit is contained in:
parent
f50a2d72a3
commit
93e623d5d4
|
@ -3,6 +3,7 @@ package nl.andrewlalis.aos_client;
|
||||||
import nl.andrewlalis.aos_client.view.GameFrame;
|
import nl.andrewlalis.aos_client.view.GameFrame;
|
||||||
import nl.andrewlalis.aos_client.view.GamePanel;
|
import nl.andrewlalis.aos_client.view.GamePanel;
|
||||||
import nl.andrewlalis.aos_core.model.Player;
|
import nl.andrewlalis.aos_core.model.Player;
|
||||||
|
import nl.andrewlalis.aos_core.model.Team;
|
||||||
import nl.andrewlalis.aos_core.model.World;
|
import nl.andrewlalis.aos_core.model.World;
|
||||||
import nl.andrewlalis.aos_core.model.tools.Gun;
|
import nl.andrewlalis.aos_core.model.tools.Gun;
|
||||||
import nl.andrewlalis.aos_core.net.data.DataTypes;
|
import nl.andrewlalis.aos_core.net.data.DataTypes;
|
||||||
|
@ -73,6 +74,12 @@ public class Client {
|
||||||
player.setGun(new Gun(this.world.getGunTypes().get(p.getGunTypeName())));
|
player.setGun(new Gun(this.world.getGunTypes().get(p.getGunTypeName())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (var t : update.getTeamUpdates()) {
|
||||||
|
Team team = this.world.getTeams().get(t.getId());
|
||||||
|
if (team != null) {
|
||||||
|
team.setScore(t.getScore());
|
||||||
|
}
|
||||||
|
}
|
||||||
this.soundManager.play(update.getSoundsToPlay());
|
this.soundManager.play(update.getSoundsToPlay());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ public class GamePanel extends JPanel {
|
||||||
g2.fill(barricadeRect);
|
g2.fill(barricadeRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Team t : world.getTeams()) {
|
for (Team t : world.getTeams().values()) {
|
||||||
g2.setColor(t.getColor());
|
g2.setColor(t.getColor());
|
||||||
Ellipse2D.Double spawnCircle = new Ellipse2D.Double(
|
Ellipse2D.Double spawnCircle = new Ellipse2D.Double(
|
||||||
t.getSpawnPoint().x() - Team.SPAWN_RADIUS,
|
t.getSpawnPoint().x() - Team.SPAWN_RADIUS,
|
||||||
|
@ -231,17 +231,11 @@ public class GamePanel extends JPanel {
|
||||||
Gun gun = myPlayer.getGun();
|
Gun gun = myPlayer.getGun();
|
||||||
g2.drawString("Clips: " + gun.getClipCount() + " / " + gun.getType().getMaxClipCount(), 5, this.getHeight() - 20);
|
g2.drawString("Clips: " + gun.getClipCount() + " / " + gun.getType().getMaxClipCount(), 5, this.getHeight() - 20);
|
||||||
g2.drawString("Bullets: " + gun.getCurrentClipBulletCount() + " / " + gun.getType().getClipSize(), 5, this.getHeight() - 30);
|
g2.drawString("Bullets: " + gun.getCurrentClipBulletCount() + " / " + gun.getType().getClipSize(), 5, this.getHeight() - 30);
|
||||||
if (myPlayer.getHealth() >= 66.0f) {
|
|
||||||
g2.setColor(Color.GREEN);
|
g2.setColor(Color.GREEN);
|
||||||
} else if (myPlayer.getHealth() >= 33.0f) {
|
g2.drawString(String.format("Health: %.1f", myPlayer.getHealth()), 5, this.getHeight() - 40);
|
||||||
g2.setColor(Color.YELLOW);
|
|
||||||
} else {
|
|
||||||
g2.setColor(Color.RED);
|
|
||||||
}
|
|
||||||
g2.drawString(String.format("Health: %.1f / %.1f", myPlayer.getHealth(), Player.MAX_HEALTH), 5, this.getHeight() - 40);
|
|
||||||
|
|
||||||
int y = this.getHeight() - 60;
|
int y = this.getHeight() - 60;
|
||||||
for (Team t : world.getTeams()) {
|
for (Team t : world.getTeams().values()) {
|
||||||
g2.setColor(t.getColor());
|
g2.setColor(t.getColor());
|
||||||
g2.drawString("Team " + t.getName() + ": " + t.getScore(), 5, y);
|
g2.drawString("Team " + t.getName() + ": " + t.getScore(), 5, y);
|
||||||
y -= 15;
|
y -= 15;
|
||||||
|
|
|
@ -3,29 +3,22 @@ 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a single projectile bullet fired from a player's gun. When shot by
|
||||||
|
* a player, a newly-spawned bullet will be initialized with a velocity in the
|
||||||
|
* general direction of the gun, with some perturbation according to the gun's
|
||||||
|
* accuracy and player's sprinting/sneaking status.
|
||||||
|
*/
|
||||||
public class Bullet extends PhysicsObject {
|
public class Bullet extends PhysicsObject {
|
||||||
private final int playerId;
|
private final int playerId;
|
||||||
private final Player player;
|
private final Player player;
|
||||||
private final Gun gun;
|
private final Gun gun;
|
||||||
|
|
||||||
public Bullet(Player player) {
|
public Bullet(Player player, float sneakAccuracyModifier, float sprintAccuracyModifier) {
|
||||||
this.playerId = player.getId();
|
this.playerId = player.getId();
|
||||||
this.player = player;
|
this.player = player;
|
||||||
this.setPosition(player.getPosition()
|
|
||||||
.add(player.getOrientation().mul(1.5f))
|
|
||||||
.add(player.getOrientation().perp().mul(Player.RADIUS))
|
|
||||||
);
|
|
||||||
this.setOrientation(player.getOrientation());
|
|
||||||
float accuracy = player.getGun().getType().getAccuracy();
|
|
||||||
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();
|
||||||
|
this.setPhysicsProperties(sneakAccuracyModifier, sprintAccuracyModifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bullet(Vec2 position, Vec2 velocity) {
|
public Bullet(Vec2 position, Vec2 velocity) {
|
||||||
|
@ -35,6 +28,23 @@ public class Bullet extends PhysicsObject {
|
||||||
this.gun = null;
|
this.gun = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setPhysicsProperties(float sneakAccuracyModifier, float sprintAccuracyModifier) {
|
||||||
|
this.setPosition(player.getPosition()
|
||||||
|
.add(player.getOrientation().mul(1.5f))
|
||||||
|
.add(player.getOrientation().perp().mul(Player.RADIUS))
|
||||||
|
);
|
||||||
|
this.setOrientation(player.getOrientation());
|
||||||
|
float accuracy = player.getGun().getType().getAccuracy();
|
||||||
|
if (player.isSneaking()) {
|
||||||
|
accuracy *= sneakAccuracyModifier;
|
||||||
|
} else if (player.isSprinting()) {
|
||||||
|
accuracy *= sprintAccuracyModifier;
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
public int getPlayerId() {
|
public int getPlayerId() {
|
||||||
return playerId;
|
return playerId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,18 +7,8 @@ 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_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_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 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;
|
||||||
|
@ -32,13 +22,19 @@ 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, GunType gunType) {
|
// Stats
|
||||||
|
private transient int killCount;
|
||||||
|
private transient int deathCount;
|
||||||
|
private transient int shotCount;
|
||||||
|
private transient int resupplyCount;
|
||||||
|
|
||||||
|
public Player(int id, String name, Team team, GunType gunType, float maxHealth) {
|
||||||
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 = new Gun(gunType);
|
this.gun = new Gun(gunType);
|
||||||
this.health = MAX_HEALTH;
|
this.health = maxHealth;
|
||||||
this.useWeapon();
|
this.useWeapon();
|
||||||
this.lastShot = System.currentTimeMillis();
|
this.lastShot = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
@ -95,6 +91,7 @@ public class Player extends PhysicsObject implements Comparable<Player> {
|
||||||
public void useWeapon() {
|
public void useWeapon() {
|
||||||
this.lastShot = System.currentTimeMillis();
|
this.lastShot = System.currentTimeMillis();
|
||||||
this.gun.decrementBulletCount();
|
this.gun.decrementBulletCount();
|
||||||
|
this.shotCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startReloading() {
|
public void startReloading() {
|
||||||
|
@ -116,16 +113,17 @@ public class Player extends PhysicsObject implements Comparable<Player> {
|
||||||
return reloading;
|
return reloading;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canResupply() {
|
public boolean canResupply(float resupplyCooldown) {
|
||||||
return this.team != null &&
|
return this.team != null &&
|
||||||
this.team.getSupplyPoint().dist(this.getPosition()) < Team.SUPPLY_POINT_RADIUS &&
|
this.team.getSupplyPoint().dist(this.getPosition()) < Team.SUPPLY_POINT_RADIUS &&
|
||||||
System.currentTimeMillis() - this.lastResupply > RESUPPLY_COOLDOWN * 1000;
|
System.currentTimeMillis() - this.lastResupply > resupplyCooldown * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resupply() {
|
public void resupply(float maxHealth) {
|
||||||
this.lastResupply = System.currentTimeMillis();
|
this.lastResupply = System.currentTimeMillis();
|
||||||
this.gun.refillClips();
|
this.gun.refillClips();
|
||||||
this.health = MAX_HEALTH;
|
this.health = maxHealth;
|
||||||
|
this.resupplyCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getHealth() {
|
public float getHealth() {
|
||||||
|
@ -136,8 +134,8 @@ public class Player extends PhysicsObject implements Comparable<Player> {
|
||||||
this.health = Math.max(this.health - damage, 0.0f);
|
this.health = Math.max(this.health - damage, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void respawn() {
|
public void respawn(float maxHealth) {
|
||||||
this.resupply();
|
this.resupply(maxHealth);
|
||||||
this.gun.emptyCurrentClip();
|
this.gun.emptyCurrentClip();
|
||||||
if (this.team != null) {
|
if (this.team != null) {
|
||||||
this.setPosition(this.team.getSpawnPoint().add(Vec2.random(-Team.SPAWN_RADIUS / 2, Team.SPAWN_RADIUS / 2)));
|
this.setPosition(this.team.getSpawnPoint().add(Vec2.random(-Team.SPAWN_RADIUS / 2, Team.SPAWN_RADIUS / 2)));
|
||||||
|
@ -154,6 +152,37 @@ public class Player extends PhysicsObject implements Comparable<Player> {
|
||||||
!this.state.isSneaking();
|
!this.state.isSneaking();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getKillCount() {
|
||||||
|
return killCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDeathCount() {
|
||||||
|
return deathCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getShotCount() {
|
||||||
|
return shotCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getResupplyCount() {
|
||||||
|
return resupplyCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void incrementDeathCount() {
|
||||||
|
this.deathCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void incrementKillCount() {
|
||||||
|
this.killCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetStats() {
|
||||||
|
this.killCount = 0;
|
||||||
|
this.deathCount = 0;
|
||||||
|
this.shotCount = 0;
|
||||||
|
this.resupplyCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
|
|
@ -6,12 +6,13 @@ import java.awt.*;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
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 byte id;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final java.awt.Color color;
|
private final java.awt.Color color;
|
||||||
private final Vec2 spawnPoint;
|
private final Vec2 spawnPoint;
|
||||||
|
@ -22,7 +23,8 @@ public class Team implements Serializable {
|
||||||
|
|
||||||
private int score;
|
private int score;
|
||||||
|
|
||||||
public Team(String name, Color color, Vec2 spawnPoint, Vec2 supplyPoint, Vec2 orientation) {
|
public Team(byte id, String name, Color color, Vec2 spawnPoint, Vec2 supplyPoint, Vec2 orientation) {
|
||||||
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.color = color;
|
this.color = color;
|
||||||
this.spawnPoint = spawnPoint;
|
this.spawnPoint = spawnPoint;
|
||||||
|
@ -32,6 +34,10 @@ public class Team implements Serializable {
|
||||||
this.score = 0;
|
this.score = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -67,4 +73,21 @@ public class Team implements Serializable {
|
||||||
public void resetScore() {
|
public void resetScore() {
|
||||||
this.score = 0;
|
this.score = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setScore(int score) {
|
||||||
|
this.score = score;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Team team = (Team) o;
|
||||||
|
return getId() == team.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
public class World implements Serializable {
|
public class World implements Serializable {
|
||||||
private final Vec2 size;
|
private final Vec2 size;
|
||||||
|
|
||||||
private final List<Team> teams;
|
private final Map<Byte, Team> teams;
|
||||||
private final Map<String, GunType> gunTypes;
|
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;
|
||||||
|
@ -24,7 +24,7 @@ public class World implements Serializable {
|
||||||
|
|
||||||
public World(Vec2 size) {
|
public World(Vec2 size) {
|
||||||
this.size = size;
|
this.size = size;
|
||||||
this.teams = new ArrayList<>();
|
this.teams = new ConcurrentHashMap<>();
|
||||||
this.gunTypes = new ConcurrentHashMap<>();
|
this.gunTypes = new ConcurrentHashMap<>();
|
||||||
this.players = new ConcurrentHashMap<>();
|
this.players = new ConcurrentHashMap<>();
|
||||||
this.bullets = new CopyOnWriteArrayList<>();
|
this.bullets = new CopyOnWriteArrayList<>();
|
||||||
|
@ -35,7 +35,7 @@ public class World implements Serializable {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Team> getTeams() {
|
public Map<Byte, Team> getTeams() {
|
||||||
return teams;
|
return teams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package nl.andrewlalis.aos_core.net.data;
|
||||||
|
|
||||||
|
import nl.andrewlalis.aos_core.model.Team;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class TeamUpdate {
|
||||||
|
public static final int BYTES = 1 + Integer.BYTES;
|
||||||
|
|
||||||
|
private final byte id;
|
||||||
|
private final int score;
|
||||||
|
|
||||||
|
public TeamUpdate(Team team) {
|
||||||
|
this.id = team.getId();
|
||||||
|
this.score = team.getScore();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TeamUpdate(byte id, int score) {
|
||||||
|
this.id = id;
|
||||||
|
this.score = score;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getScore() {
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(DataOutputStream out) throws IOException {
|
||||||
|
out.writeByte(this.id);
|
||||||
|
out.writeInt(this.score);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TeamUpdate read(DataInputStream in) throws IOException {
|
||||||
|
return new TeamUpdate(
|
||||||
|
in.readByte(),
|
||||||
|
in.readInt()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package nl.andrewlalis.aos_core.net.data;
|
||||||
|
|
||||||
import nl.andrewlalis.aos_core.model.Bullet;
|
import nl.andrewlalis.aos_core.model.Bullet;
|
||||||
import nl.andrewlalis.aos_core.model.Player;
|
import nl.andrewlalis.aos_core.model.Player;
|
||||||
|
import nl.andrewlalis.aos_core.model.Team;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -20,21 +21,24 @@ import java.util.List;
|
||||||
public class WorldUpdate {
|
public class WorldUpdate {
|
||||||
private final List<PlayerUpdate> playerUpdates;
|
private final List<PlayerUpdate> playerUpdates;
|
||||||
private final List<BulletUpdate> bulletUpdates;
|
private final List<BulletUpdate> bulletUpdates;
|
||||||
|
private final List<TeamUpdate> teamUpdates;
|
||||||
private final List<Sound> soundsToPlay;
|
private final List<Sound> soundsToPlay;
|
||||||
|
|
||||||
public WorldUpdate() {
|
public WorldUpdate() {
|
||||||
this(new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
|
this(new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private WorldUpdate(List<PlayerUpdate> playerUpdates, List<BulletUpdate> bulletUpdates, List<Sound> soundsToPlay) {
|
private WorldUpdate(List<PlayerUpdate> playerUpdates, List<BulletUpdate> bulletUpdates, List<TeamUpdate> teamUpdates, List<Sound> soundsToPlay) {
|
||||||
this.playerUpdates = playerUpdates;
|
this.playerUpdates = playerUpdates;
|
||||||
this.bulletUpdates = bulletUpdates;
|
this.bulletUpdates = bulletUpdates;
|
||||||
|
this.teamUpdates = teamUpdates;
|
||||||
this.soundsToPlay = soundsToPlay;
|
this.soundsToPlay = soundsToPlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
this.playerUpdates.clear();
|
this.playerUpdates.clear();
|
||||||
this.bulletUpdates.clear();
|
this.bulletUpdates.clear();
|
||||||
|
this.teamUpdates.clear();
|
||||||
this.soundsToPlay.clear();
|
this.soundsToPlay.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +50,10 @@ public class WorldUpdate {
|
||||||
this.bulletUpdates.add(new BulletUpdate(b));
|
this.bulletUpdates.add(new BulletUpdate(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addTeam(Team team) {
|
||||||
|
this.teamUpdates.add(new TeamUpdate(team));
|
||||||
|
}
|
||||||
|
|
||||||
public void addSound(Sound sound) {
|
public void addSound(Sound sound) {
|
||||||
this.soundsToPlay.add(sound);
|
this.soundsToPlay.add(sound);
|
||||||
}
|
}
|
||||||
|
@ -58,6 +66,10 @@ public class WorldUpdate {
|
||||||
return bulletUpdates;
|
return bulletUpdates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<TeamUpdate> getTeamUpdates() {
|
||||||
|
return teamUpdates;
|
||||||
|
}
|
||||||
|
|
||||||
public List<Sound> getSoundsToPlay() {
|
public List<Sound> getSoundsToPlay() {
|
||||||
return soundsToPlay;
|
return soundsToPlay;
|
||||||
}
|
}
|
||||||
|
@ -66,6 +78,7 @@ public class WorldUpdate {
|
||||||
int size = 3 * Integer.BYTES + // List size integers.
|
int size = 3 * Integer.BYTES + // List size integers.
|
||||||
this.playerUpdates.size() * PlayerUpdate.BYTES +
|
this.playerUpdates.size() * PlayerUpdate.BYTES +
|
||||||
this.bulletUpdates.size() * BulletUpdate.BYTES +
|
this.bulletUpdates.size() * BulletUpdate.BYTES +
|
||||||
|
this.teamUpdates.size() * TeamUpdate.BYTES +
|
||||||
this.soundsToPlay.size() * Sound.BYTES;
|
this.soundsToPlay.size() * Sound.BYTES;
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream(size);
|
ByteArrayOutputStream out = new ByteArrayOutputStream(size);
|
||||||
DataOutputStream dataOut = new DataOutputStream(out);
|
DataOutputStream dataOut = new DataOutputStream(out);
|
||||||
|
@ -77,6 +90,10 @@ public class WorldUpdate {
|
||||||
for (var u : this.bulletUpdates) {
|
for (var u : this.bulletUpdates) {
|
||||||
u.write(dataOut);
|
u.write(dataOut);
|
||||||
}
|
}
|
||||||
|
dataOut.writeInt(this.teamUpdates.size());
|
||||||
|
for (var u : this.teamUpdates) {
|
||||||
|
u.write(dataOut);
|
||||||
|
}
|
||||||
dataOut.writeInt(this.soundsToPlay.size());
|
dataOut.writeInt(this.soundsToPlay.size());
|
||||||
for (var u : this.soundsToPlay) {
|
for (var u : this.soundsToPlay) {
|
||||||
u.write(dataOut);
|
u.write(dataOut);
|
||||||
|
@ -100,12 +117,17 @@ public class WorldUpdate {
|
||||||
for (int i = 0; i < bullets; i++) {
|
for (int i = 0; i < bullets; i++) {
|
||||||
bulletUpdates.add(BulletUpdate.read(dataIn));
|
bulletUpdates.add(BulletUpdate.read(dataIn));
|
||||||
}
|
}
|
||||||
|
int teams = dataIn.readInt();
|
||||||
|
List<TeamUpdate> teamUpdates = new ArrayList<>(teams);
|
||||||
|
for (int i = 0; i < teams; i++) {
|
||||||
|
teamUpdates.add(TeamUpdate.read(dataIn));
|
||||||
|
}
|
||||||
int sounds = dataIn.readInt();
|
int sounds = dataIn.readInt();
|
||||||
List<Sound> soundsToPlay = new ArrayList<>(sounds);
|
List<Sound> soundsToPlay = new ArrayList<>(sounds);
|
||||||
for (int i = 0; i < sounds; i++) {
|
for (int i = 0; i < sounds; i++) {
|
||||||
soundsToPlay.add(Sound.read(dataIn));
|
soundsToPlay.add(Sound.read(dataIn));
|
||||||
}
|
}
|
||||||
var obj = new WorldUpdate(playerUpdates, bulletUpdates, soundsToPlay);
|
var obj = new WorldUpdate(playerUpdates, bulletUpdates, teamUpdates, soundsToPlay);
|
||||||
dataIn.close();
|
dataIn.close();
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ 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;
|
||||||
|
import nl.andrewlalis.aos_server.command.chat.KillDeathRatioCommand;
|
||||||
|
import nl.andrewlalis.aos_server.command.chat.TeamChatCommand;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -27,6 +29,8 @@ public class ChatManager {
|
||||||
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));
|
this.chatCommands.put("guns", new GunsCommand(server));
|
||||||
|
this.chatCommands.put("kd", new KillDeathRatioCommand());
|
||||||
|
this.chatCommands.put("t", new TeamChatCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handlePlayerChat(ClientHandler handler, Player player, ChatMessage msg) {
|
public void handlePlayerChat(ClientHandler handler, Player player, ChatMessage msg) {
|
||||||
|
|
|
@ -79,14 +79,16 @@ public class Server {
|
||||||
world.getBarricades().add(new Barricade(0, 30, 10, 10));
|
world.getBarricades().add(new Barricade(0, 30, 10, 10));
|
||||||
world.getBarricades().add(new Barricade(40, 30, 10, 10));
|
world.getBarricades().add(new Barricade(40, 30, 10, 10));
|
||||||
|
|
||||||
world.getTeams().add(new Team(
|
world.getTeams().put((byte) 1, new Team(
|
||||||
|
(byte) 1,
|
||||||
"Red",
|
"Red",
|
||||||
Color.RED,
|
Color.RED,
|
||||||
new Vec2(3, 3),
|
new Vec2(3, 3),
|
||||||
new Vec2(15, 3),
|
new Vec2(15, 3),
|
||||||
new Vec2(0, 1)
|
new Vec2(0, 1)
|
||||||
));
|
));
|
||||||
world.getTeams().add(new Team(
|
world.getTeams().put((byte) 2, new Team(
|
||||||
|
(byte) 2,
|
||||||
"Blue",
|
"Blue",
|
||||||
Color.BLUE,
|
Color.BLUE,
|
||||||
new Vec2(world.getSize().x() - 3, world.getSize().y() - 3),
|
new Vec2(world.getSize().x() - 3, world.getSize().y() - 3),
|
||||||
|
@ -124,14 +126,14 @@ public class Server {
|
||||||
public Player registerNewPlayer(String name) {
|
public Player registerNewPlayer(String name) {
|
||||||
int id = ThreadLocalRandom.current().nextInt(1, Integer.MAX_VALUE);
|
int id = ThreadLocalRandom.current().nextInt(1, Integer.MAX_VALUE);
|
||||||
Team team = null;
|
Team team = null;
|
||||||
for (Team t : this.world.getTeams()) {
|
for (Team t : this.world.getTeams().values()) {
|
||||||
if (team == null) {
|
if (team == null) {
|
||||||
team = t;
|
team = t;
|
||||||
} else if (t.getPlayers().size() < team.getPlayers().size()) {
|
} else if (t.getPlayers().size() < team.getPlayers().size()) {
|
||||||
team = t;
|
team = t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Player p = new Player(id, name, team, this.world.getGunTypes().get(this.settings.getPlayerSettings().getDefaultGun()));
|
Player p = new Player(id, name, team, this.world.getGunTypes().get(this.settings.getPlayerSettings().getDefaultGun()), settings.getPlayerSettings().getMaxHealth());
|
||||||
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));
|
||||||
|
@ -196,10 +198,11 @@ public class Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetGame() {
|
public void resetGame() {
|
||||||
for (Team t : this.world.getTeams()) {
|
for (Team t : this.world.getTeams().values()) {
|
||||||
t.resetScore();
|
t.resetScore();
|
||||||
for (Player p : t.getPlayers()) {
|
for (Player p : t.getPlayers()) {
|
||||||
p.respawn();
|
p.resetStats();
|
||||||
|
p.respawn(settings.getPlayerSettings().getMaxHealth());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
broadcastMessage(new SystemChatMessage(SystemChatMessage.Level.INFO, "Game has been reset."));
|
broadcastMessage(new SystemChatMessage(SystemChatMessage.Level.INFO, "Game has been reset."));
|
||||||
|
@ -211,6 +214,14 @@ public class Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendTeamMessage(Team team, Message message) {
|
||||||
|
for (ClientHandler handler : this.clientHandlers) {
|
||||||
|
if (team.equals(handler.getPlayer().getTeam())) {
|
||||||
|
handler.send(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
this.running = false;
|
this.running = false;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -72,7 +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));
|
p.setHealth(Math.min(p.getHealth() + server.getSettings().getPlayerSettings().getHealthRegenRate() * t, server.getSettings().getPlayerSettings().getMaxHealth()));
|
||||||
this.worldUpdate.addPlayer(p);
|
this.worldUpdate.addPlayer(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,31 +97,33 @@ public class WorldUpdater extends Thread {
|
||||||
Vec2 localVelocity = p.getVelocity().rotate(-left.angle());
|
Vec2 localVelocity = p.getVelocity().rotate(-left.angle());
|
||||||
float vx = localVelocity.x();
|
float vx = localVelocity.x();
|
||||||
float vy = localVelocity.y();
|
float vy = localVelocity.y();
|
||||||
|
float a = server.getSettings().getPlayerSettings().getAcceleration();
|
||||||
if (p.getState().isMovingForward()) {
|
if (p.getState().isMovingForward()) {
|
||||||
vy -= Player.MOVEMENT_ACCELERATION * t;
|
vy -= a * t;
|
||||||
}
|
}
|
||||||
if (p.getState().isMovingBackward()) {
|
if (p.getState().isMovingBackward()) {
|
||||||
vy += Player.MOVEMENT_ACCELERATION * t;
|
vy += a * t;
|
||||||
}
|
}
|
||||||
if (p.getState().isMovingLeft()) {
|
if (p.getState().isMovingLeft()) {
|
||||||
vx -= Player.MOVEMENT_ACCELERATION * t;
|
vx -= a * t;
|
||||||
}
|
}
|
||||||
if (p.getState().isMovingRight()) {
|
if (p.getState().isMovingRight()) {
|
||||||
vx += Player.MOVEMENT_ACCELERATION * t;
|
vx += a * t;
|
||||||
}
|
}
|
||||||
// Compute deceleration.
|
// Compute deceleration.
|
||||||
|
float d = server.getSettings().getPlayerSettings().getDeceleration();
|
||||||
if (p.getState().isMovingForward() == p.getState().isMovingBackward()) {
|
if (p.getState().isMovingForward() == p.getState().isMovingBackward()) {
|
||||||
if (vy > 0) {
|
if (vy > 0) {
|
||||||
vy = Math.max(0.0f, vy - Player.MOVEMENT_DECELERATION * t);
|
vy = Math.max(0.0f, vy - d * t);
|
||||||
} else {
|
} else {
|
||||||
vy = Math.min(0.0f, vy + Player.MOVEMENT_DECELERATION * t);
|
vy = Math.min(0.0f, vy + d * t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p.getState().isMovingLeft() == p.getState().isMovingRight()) {
|
if (p.getState().isMovingLeft() == p.getState().isMovingRight()) {
|
||||||
if (vx > 0) {
|
if (vx > 0) {
|
||||||
vx = Math.max(0.0f, vx - Player.MOVEMENT_DECELERATION * t);
|
vx = Math.max(0.0f, vx - d * t);
|
||||||
} else {
|
} else {
|
||||||
vx = Math.min(0.0f, vx + Player.MOVEMENT_DECELERATION * t);
|
vx = Math.min(0.0f, vx + d * t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,11 +134,11 @@ public class WorldUpdater extends Thread {
|
||||||
}
|
}
|
||||||
float speedLimit;
|
float speedLimit;
|
||||||
if (p.isSprinting()) {
|
if (p.isSprinting()) {
|
||||||
speedLimit = Player.MOVEMENT_SPEED_SPRINT;
|
speedLimit = server.getSettings().getPlayerSettings().getSprintSpeed();
|
||||||
} else if (p.isSneaking()) {
|
} else if (p.isSneaking()) {
|
||||||
speedLimit = Player.MOVEMENT_SPEED_SNEAK;
|
speedLimit = server.getSettings().getPlayerSettings().getSneakSpeed();
|
||||||
} else {
|
} else {
|
||||||
speedLimit = Player.MOVEMENT_SPEED;
|
speedLimit = server.getSettings().getPlayerSettings().getSpeed();
|
||||||
}
|
}
|
||||||
if (newLocalVelocity.mag() > speedLimit) {
|
if (newLocalVelocity.mag() > speedLimit) {
|
||||||
newLocalVelocity = newLocalVelocity.mul(speedLimit / newLocalVelocity.mag());
|
newLocalVelocity = newLocalVelocity.mul(speedLimit / newLocalVelocity.mag());
|
||||||
|
@ -176,15 +178,15 @@ public class WorldUpdater extends Thread {
|
||||||
if (ny + Player.RADIUS > this.world.getSize().y()) ny = this.world.getSize().y() - Player.RADIUS;
|
if (ny + Player.RADIUS > this.world.getSize().y()) ny = this.world.getSize().y() - Player.RADIUS;
|
||||||
p.setPosition(new Vec2(nx, ny));
|
p.setPosition(new Vec2(nx, ny));
|
||||||
|
|
||||||
if (p.canResupply()) {
|
if (p.canResupply(server.getSettings().getPlayerSettings().getResupplyCooldown())) {
|
||||||
p.resupply();
|
p.resupply(server.getSettings().getPlayerSettings().getMaxHealth());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePlayerShooting(Player p) {
|
private void updatePlayerShooting(Player p) {
|
||||||
if (p.canUseWeapon()) {
|
if (p.canUseWeapon()) {
|
||||||
for (int i = 0; i < p.getGun().getType().getBulletsPerRound(); i++) {
|
for (int i = 0; i < p.getGun().getType().getBulletsPerRound(); i++) {
|
||||||
Bullet b = new Bullet(p);
|
Bullet b = new Bullet(p, server.getSettings().getPlayerSettings().getSneakAccuracyModifier(), server.getSettings().getPlayerSettings().getSprintAccuracyModifier());
|
||||||
this.world.getBullets().add(b);
|
this.world.getBullets().add(b);
|
||||||
this.worldUpdate.addBullet(b);
|
this.worldUpdate.addBullet(b);
|
||||||
}
|
}
|
||||||
|
@ -256,10 +258,13 @@ public class WorldUpdater extends Thread {
|
||||||
Player shooter = this.world.getPlayers().get(b.getPlayerId());
|
Player shooter = this.world.getPlayers().get(b.getPlayerId());
|
||||||
this.server.broadcastMessage(new SystemChatMessage(SystemChatMessage.Level.SEVERE, p.getName() + " was shot by " + shooter.getName() + "."));
|
this.server.broadcastMessage(new SystemChatMessage(SystemChatMessage.Level.SEVERE, p.getName() + " was shot by " + shooter.getName() + "."));
|
||||||
this.worldUpdate.addSound(new Sound(p.getPosition(), 1.0f, SoundType.DEATH));
|
this.worldUpdate.addSound(new Sound(p.getPosition(), 1.0f, SoundType.DEATH));
|
||||||
|
shooter.incrementKillCount();
|
||||||
if (shooter.getTeam() != null) {
|
if (shooter.getTeam() != null) {
|
||||||
shooter.getTeam().incrementScore();
|
shooter.getTeam().incrementScore();
|
||||||
|
this.worldUpdate.addTeam(shooter.getTeam());
|
||||||
}
|
}
|
||||||
p.respawn();
|
p.incrementDeathCount();
|
||||||
|
p.respawn(server.getSettings().getPlayerSettings().getMaxHealth());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ public class ListPlayersCommand implements Command {
|
||||||
player.getName(),
|
player.getName(),
|
||||||
player.getTeam() == null ? "none" : player.getTeam().getName(),
|
player.getTeam() == null ? "none" : player.getTeam().getName(),
|
||||||
player.getHealth(),
|
player.getHealth(),
|
||||||
Player.MAX_HEALTH,
|
this.server.getSettings().getPlayerSettings().getMaxHealth(),
|
||||||
player.getGun().getType().getName()
|
player.getGun().getType().getName()
|
||||||
))
|
))
|
||||||
.collect(Collectors.joining("\n"));
|
.collect(Collectors.joining("\n"));
|
||||||
|
|
|
@ -12,7 +12,7 @@ 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."));
|
handler.send(new SystemChatMessage(SystemChatMessage.Level.WARNING, "No gun name specified. Use /guns to see available guns."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String gunName = String.join(" ", args);
|
String gunName = String.join(" ", args);
|
||||||
|
@ -24,7 +24,7 @@ public class GunCommand implements ChatCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (gunType == null) {
|
if (gunType == null) {
|
||||||
handler.send(new SystemChatMessage(SystemChatMessage.Level.WARNING, "Unknown gun name."));
|
handler.send(new SystemChatMessage(SystemChatMessage.Level.WARNING, "Unknown gun name. Use /guns to see available guns."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
player.setGun(new Gun(gunType));
|
player.setGun(new Gun(gunType));
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package nl.andrewlalis.aos_server.command.chat;
|
||||||
|
|
||||||
|
import nl.andrewlalis.aos_core.model.Player;
|
||||||
|
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
|
||||||
|
import nl.andrewlalis.aos_server.ClientHandler;
|
||||||
|
|
||||||
|
public class KillDeathRatioCommand implements ChatCommand {
|
||||||
|
@Override
|
||||||
|
public void execute(ClientHandler handler, Player player, String[] args) {
|
||||||
|
float ratio = player.getKillCount() / ((float) player.getDeathCount());
|
||||||
|
handler.send(new SystemChatMessage(SystemChatMessage.Level.INFO, String.format("Your Kill/Death ratio is %.2f.", ratio)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package nl.andrewlalis.aos_server.command.chat;
|
||||||
|
|
||||||
|
import nl.andrewlalis.aos_core.model.Player;
|
||||||
|
import nl.andrewlalis.aos_core.net.chat.PlayerChatMessage;
|
||||||
|
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
|
||||||
|
import nl.andrewlalis.aos_server.ClientHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This command, when invoked, sends a message to all team members.
|
||||||
|
*/
|
||||||
|
public class TeamChatCommand implements ChatCommand {
|
||||||
|
@Override
|
||||||
|
public void execute(ClientHandler handler, Player player, String[] args) {
|
||||||
|
if (player.getTeam() == null) {
|
||||||
|
handler.send(new SystemChatMessage(SystemChatMessage.Level.WARNING, "You're not in a team, so you can't send team chat messages."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handler.getServer().sendTeamMessage(player.getTeam(), new PlayerChatMessage(player.getId(), String.join(" ", args)));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue