diff --git a/client/pom.xml b/client/pom.xml
index a60db88..1b9abab 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -5,7 +5,7 @@
ace-of-shades
nl.andrewlalis
- 0.5.0
+ 0.6.0
4.0.0
diff --git a/client/src/main/java/nl/andrewlalis/aos_client/Client.java b/client/src/main/java/nl/andrewlalis/aos_client/Client.java
index 4d0e115..ef9a384 100644
--- a/client/src/main/java/nl/andrewlalis/aos_client/Client.java
+++ b/client/src/main/java/nl/andrewlalis/aos_client/Client.java
@@ -9,14 +9,15 @@ import nl.andrewlalis.aos_client.view.GameRenderer;
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.tools.Grenade;
import nl.andrewlalis.aos_core.model.tools.Gun;
-import nl.andrewlalis.aos_core.model.tools.GunType;
-import nl.andrewlalis.aos_core.model.tools.Tool;
+import nl.andrewlalis.aos_core.model.tools.Knife;
import nl.andrewlalis.aos_core.net.data.DataTypes;
import nl.andrewlalis.aos_core.net.data.PlayerDetailUpdate;
import nl.andrewlalis.aos_core.net.data.WorldUpdate;
+import nl.andrewlalis.aos_core.net.data.tool.GrenadeData;
import nl.andrewlalis.aos_core.net.data.tool.GunData;
-import nl.andrewlalis.aos_core.net.data.tool.ToolData;
+import nl.andrewlalis.aos_core.net.data.tool.KnifeData;
import java.io.IOException;
@@ -27,6 +28,7 @@ public class Client {
private final MessageTransceiver messageTransceiver;
private World world;
+ private Player player;
private final GameRenderer renderer;
private final SoundManager soundManager;
@@ -49,7 +51,7 @@ public class Client {
this.messageTransceiver.start();
this.chatManager.bindTransceiver(this.messageTransceiver);
- while (this.myPlayer == null || this.world == null) {
+ while (this.player == null || this.world == null) {
try {
System.out.println("Waiting for server response and player registration...");
Thread.sleep(100);
@@ -91,10 +93,12 @@ public class Client {
player.setPosition(p.getPosition());
player.setOrientation(p.getOrientation());
player.setVelocity(p.getVelocity());
- player.setGun(new Gun(this.world.getGunTypes().get(p.getGunTypeName())));
if (player.getVelocity().mag() > 0) {
- this.soundManager.playWalking(player, myPlayer);
+ this.soundManager.playWalking(player, null);
}
+ player.getTools().clear();
+ player.getTools().add(p.getSelectedTool().toTool(this.world));
+ player.setSelectedToolIndex(0);
}
}
for (var t : update.getTeamUpdates()) {
@@ -103,7 +107,7 @@ public class Client {
team.setScore(t.getScore());
}
}
- this.soundManager.play(update.getSoundsToPlay(), myPlayer);
+ this.soundManager.play(update.getSoundsToPlay(), null);
}
public void setWorld(World world) {
@@ -111,11 +115,11 @@ public class Client {
}
public void setPlayer(Player player) {
- this.myPlayer = player;
+ this.player = player;
}
public Player getPlayer() {
- return myPlayer;
+ return this.player;
}
/**
@@ -124,17 +128,34 @@ public class Client {
* @param update The updated player information from the server.
*/
public void updatePlayer(PlayerDetailUpdate update) {
- if (this.myPlayer == null) return;
- this.myPlayer.setHealth(update.getHealth());
+ if (this.player != null) {
+ this.player.setHealth(update.getHealth());
+ this.player.getTools().clear();
+ for (var td : update.getTools()) {
+ if (td instanceof KnifeData knifeData) {
+ this.player.getTools().add(new Knife());
+ } else if (td instanceof GunData gunData) {
+ this.player.getTools().add(new Gun(
+ this.world.getGunTypeById(gunData.getTypeId()),
+ gunData.getCurrentClipBulletCount(),
+ gunData.getClipCount(),
+ gunData.isReloading()
+ ));
+ } else if (td instanceof GrenadeData grenadeData) {
+ this.player.getTools().add(new Grenade(grenadeData.getGrenades(), grenadeData.getMaxGrenades()));
+ }
+ }
+ this.player.setSelectedToolIndex(update.getSelectedToolIndex());
+ }
}
/**
* Sends a player control state message to the server, which indicates that
* the player's controls have been updated, due to a key or mouse event.
*/
- public void sendPlayerState() {
+ public void sendControlState() {
try {
- this.messageTransceiver.sendData(DataTypes.PLAYER_CONTROL_STATE, myPlayer.getId(), myPlayer.getState().toBytes());
+ this.messageTransceiver.sendData(DataTypes.PLAYER_CONTROL_STATE, this.player.getId(), this.player.getState().toBytes());
} catch (IOException e) {
e.printStackTrace();
}
diff --git a/client/src/main/java/nl/andrewlalis/aos_client/control/PlayerKeyListener.java b/client/src/main/java/nl/andrewlalis/aos_client/control/PlayerKeyListener.java
index f9fb041..507822f 100644
--- a/client/src/main/java/nl/andrewlalis/aos_client/control/PlayerKeyListener.java
+++ b/client/src/main/java/nl/andrewlalis/aos_client/control/PlayerKeyListener.java
@@ -28,7 +28,7 @@ public class PlayerKeyListener extends KeyAdapter {
s.setReloading(false);
s.setSneaking(false);
s.setSprinting(false);
- this.client.sendPlayerState();
+ this.client.sendControlState();
if (e.getKeyChar() == '/') this.chatManager.appendToChat('/');
}
} else if (this.chatManager.isChatting()) {
@@ -63,8 +63,12 @@ public class PlayerKeyListener extends KeyAdapter {
state.setSprinting(true);
} else if (e.getKeyCode() == KeyEvent.VK_CONTROL) {
state.setSneaking(true);
+ } else if (e.getKeyCode() == KeyEvent.VK_Q) {
+ state.setSelectingPreviousTool(true);
+ } else if (e.getKeyCode() == KeyEvent.VK_E) {
+ state.setSelectingNextTool(true);
}
- this.client.sendPlayerState();
+ this.client.sendControlState();
}
@Override
@@ -85,7 +89,11 @@ public class PlayerKeyListener extends KeyAdapter {
state.setSprinting(false);
} else if (e.getKeyCode() == KeyEvent.VK_CONTROL) {
state.setSneaking(false);
+ } else if (e.getKeyCode() == KeyEvent.VK_Q) {
+ state.setSelectingPreviousTool(false);
+ } else if (e.getKeyCode() == KeyEvent.VK_E) {
+ state.setSelectingNextTool(false);
}
- this.client.sendPlayerState();
+ this.client.sendControlState();
}
}
diff --git a/client/src/main/java/nl/andrewlalis/aos_client/control/PlayerMouseListener.java b/client/src/main/java/nl/andrewlalis/aos_client/control/PlayerMouseListener.java
index 8a8f893..14eb0e7 100644
--- a/client/src/main/java/nl/andrewlalis/aos_client/control/PlayerMouseListener.java
+++ b/client/src/main/java/nl/andrewlalis/aos_client/control/PlayerMouseListener.java
@@ -8,6 +8,15 @@ import javax.swing.event.MouseInputAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
+/**
+ * Listens for changes to the player's mouse state. This handles the following
+ * possible control events:
+ *
+ * - Pressing the mouse to use the player's weapon.
+ * - Scrolling the mouse wheel to zoom in or out.
+ * - Moving the mouse to change the player's orientation.
+ *
+ */
public class PlayerMouseListener extends MouseInputAdapter {
private static final float MOUSE_UPDATES_PER_SECOND = 60.0f;
private static final long MS_PER_MOUSE_UPDATE = (long) (1000.0f / MOUSE_UPDATES_PER_SECOND);
@@ -25,16 +34,16 @@ public class PlayerMouseListener extends MouseInputAdapter {
@Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
- client.getPlayer().getState().setShooting(true);
- client.sendPlayerState();
+ client.getPlayer().getState().setUsingTool(true);
+ client.sendControlState();
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
- client.getPlayer().getState().setShooting(false);
- client.sendPlayerState();
+ client.getPlayer().getState().setUsingTool(false);
+ client.sendControlState();
}
}
@@ -54,7 +63,7 @@ public class PlayerMouseListener extends MouseInputAdapter {
client.getPlayer().getState().setMouseLocation(centeredMouseLocation);
long now = System.currentTimeMillis();
if (now - this.lastMouseMove > MS_PER_MOUSE_UPDATE) {
- client.sendPlayerState();
+ client.sendControlState();
this.lastMouseMove = now;
}
}
@@ -64,10 +73,10 @@ public class PlayerMouseListener extends MouseInputAdapter {
Vec2 c = new Vec2(this.gamePanel.getWidth() / 2.0f, this.gamePanel.getHeight() / 2.0f);
Vec2 centeredMouseLocation = new Vec2(e.getX(), e.getY()).sub(c);
client.getPlayer().getState().setMouseLocation(centeredMouseLocation);
- client.getPlayer().getState().setShooting(true);
+ client.getPlayer().getState().setUsingTool(true);
long now = System.currentTimeMillis();
if (now - this.lastMouseMove > MS_PER_MOUSE_UPDATE) {
- client.sendPlayerState();
+ client.sendControlState();
this.lastMouseMove = now;
}
}
diff --git a/client/src/main/java/nl/andrewlalis/aos_client/model/ClientPlayerData.java b/client/src/main/java/nl/andrewlalis/aos_client/model/ClientPlayerData.java
deleted file mode 100644
index 642dea7..0000000
--- a/client/src/main/java/nl/andrewlalis/aos_client/model/ClientPlayerData.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package nl.andrewlalis.aos_client.model;
-
-import nl.andrewlalis.aos_core.net.data.tool.ToolData;
-
-import java.util.List;
-
-/**
- * Information about the client's player, which contains more detailed data than
- * what is provided for any random player in the world.
- */
-public class ClientPlayerData extends PlayerData {
- private float health;
- private List tools;
- private int selectedToolIndex;
-
- public float getHealth() {
- return health;
- }
-
- public List getTools() {
- return tools;
- }
-
- public int getSelectedToolIndex() {
- return selectedToolIndex;
- }
-}
diff --git a/client/src/main/java/nl/andrewlalis/aos_client/model/PlayerData.java b/client/src/main/java/nl/andrewlalis/aos_client/model/PlayerData.java
deleted file mode 100644
index 8356201..0000000
--- a/client/src/main/java/nl/andrewlalis/aos_client/model/PlayerData.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package nl.andrewlalis.aos_client.model;
-
-import nl.andrewlalis.aos_core.geom.Vec2;
-
-/**
- * The data about a player which the client needs to know in order to render it.
- */
-public class PlayerData {
- private int id;
- private String name;
- private byte teamId;
-
- private Vec2 position;
- private Vec2 orientation;
- private Vec2 velocity;
-
- public int getId() {
- return id;
- }
-
- public String getName() {
- return name;
- }
-
- public byte getTeamId() {
- return teamId;
- }
-
- public Vec2 getPosition() {
- return position;
- }
-
- public Vec2 getOrientation() {
- return orientation;
- }
-
- public Vec2 getVelocity() {
- return velocity;
- }
-}
diff --git a/client/src/main/java/nl/andrewlalis/aos_client/view/GamePanel.java b/client/src/main/java/nl/andrewlalis/aos_client/view/GamePanel.java
index dd29898..6e78c78 100644
--- a/client/src/main/java/nl/andrewlalis/aos_client/view/GamePanel.java
+++ b/client/src/main/java/nl/andrewlalis/aos_client/view/GamePanel.java
@@ -1,8 +1,9 @@
package nl.andrewlalis.aos_client.view;
-import nl.andrewlalis.aos_client.net.ChatManager;
import nl.andrewlalis.aos_client.Client;
+import nl.andrewlalis.aos_client.net.ChatManager;
import nl.andrewlalis.aos_core.model.*;
+import nl.andrewlalis.aos_core.model.tools.Grenade;
import nl.andrewlalis.aos_core.model.tools.Gun;
import nl.andrewlalis.aos_core.net.chat.ChatMessage;
import nl.andrewlalis.aos_core.net.chat.ChatType;
@@ -84,7 +85,7 @@ public class GamePanel extends JPanel {
* @param world The world to render.
*/
private void drawWorld(Graphics2D g2, World world) {
- Player myPlayer = client.getPlayer();
+ Player myPlayer = this.client.getPlayer();
if (myPlayer == null) return;
double scale = this.scales[this.scaleIndex];
AffineTransform pre = g2.getTransform();
@@ -193,7 +194,9 @@ public class GamePanel extends JPanel {
Color playerColor = p.getTeam() != null ? p.getTeam().getColor() : Color.BLACK;
g2.setColor(playerColor);
g2.fill(dot);
- this.drawGun(g2, p.getGun());
+ if (p.getSelectedTool() instanceof Gun gun) {
+ this.drawGun(g2, gun);
+ }
g2.setTransform(pre);
}
}
@@ -302,21 +305,35 @@ public class GamePanel extends JPanel {
Player myPlayer = this.client.getPlayer();
if (myPlayer == null) return;
+ int lineHeight = this.getHeight() - 10;
g2.setColor(Color.WHITE);
- if (myPlayer.isReloading()) {
- g2.drawString("Reloading...", 5, this.getHeight() - 10);
+ if (myPlayer.getSelectedTool() != null) {
+ g2.drawString(myPlayer.getSelectedTool().getName(), 5, lineHeight);
+ lineHeight -= 10;
}
- Gun gun = myPlayer.getGun();
- g2.drawString("Clips: " + gun.getClipCount() + " / " + gun.getType().maxClipCount(), 5, this.getHeight() - 20);
- g2.drawString("Bullets: " + gun.getCurrentClipBulletCount() + " / " + gun.getType().clipSize(), 5, this.getHeight() - 30);
- g2.setColor(Color.GREEN);
- g2.drawString(String.format("Health: %.1f", myPlayer.getHealth()), 5, this.getHeight() - 40);
- int y = this.getHeight() - 60;
+ if (myPlayer.getSelectedTool() instanceof Gun gun) {
+ if (gun.isReloading()) {
+ g2.drawString("Reloading...", 5, lineHeight);
+ lineHeight -= 10;
+ }
+ g2.drawString("Clips: " + gun.getClipCount() + " / " + gun.getType().maxClipCount(), 5, lineHeight);
+ lineHeight -= 10;
+ g2.drawString("Bullets: " + gun.getCurrentClipBulletCount() + " / " + gun.getType().clipSize(), 5, lineHeight);
+ lineHeight -= 10;
+ } else if (myPlayer.getSelectedTool() instanceof Grenade grenade) {
+ g2.drawString(grenade.getGrenadesRemaining() + " / " + grenade.getMaxGrenades() + " grenades", 5, lineHeight);
+ lineHeight -= 10;
+ }
+
+ g2.setColor(Color.GREEN);
+ g2.drawString(String.format("Health: %.1f", myPlayer.getHealth()), 5, lineHeight);
+ lineHeight -= 10;
+
for (Team t : world.getTeams().values()) {
g2.setColor(t.getColor());
- g2.drawString("Team " + t.getName() + ": " + t.getScore(), 5, y);
- y -= 15;
+ g2.drawString("Team " + t.getName() + ": " + t.getScore(), 5, lineHeight);
+ lineHeight -= 15;
}
}
}
diff --git a/core/pom.xml b/core/pom.xml
index ea6f593..02e60fa 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -5,7 +5,7 @@
ace-of-shades
nl.andrewlalis
- 0.5.0
+ 0.6.0
4.0.0
diff --git a/core/src/main/java/module-info.java b/core/src/main/java/module-info.java
index 30193f9..363ff2e 100644
--- a/core/src/main/java/module-info.java
+++ b/core/src/main/java/module-info.java
@@ -7,7 +7,7 @@ module aos_core {
exports nl.andrewlalis.aos_core.net.data.tool to aos_server, aos_client;
exports nl.andrewlalis.aos_core.model to aos_server, aos_client;
- exports nl.andrewlalis.aos_core.model.tools to aos_client, aos_server;
+ exports nl.andrewlalis.aos_core.model.tools to aos_server, aos_client;
exports nl.andrewlalis.aos_core.geom to aos_server, aos_client;
exports nl.andrewlalis.aos_core.util to aos_server, aos_client;
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/model/Bullet.java b/core/src/main/java/nl/andrewlalis/aos_core/model/Bullet.java
index 03d2f70..583dd07 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/model/Bullet.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/model/Bullet.java
@@ -14,10 +14,10 @@ public class Bullet extends PhysicsObject {
private final Player player;
private final Gun gun;
- public Bullet(Player player, float sneakAccuracyModifier, float sprintAccuracyModifier) {
+ public Bullet(Player player, Gun gun, float sneakAccuracyModifier, float sprintAccuracyModifier) {
this.playerId = player.getId();
this.player = player;
- this.gun = player.getGun();
+ this.gun = gun;
this.setPhysicsProperties(sneakAccuracyModifier, sprintAccuracyModifier);
}
@@ -34,14 +34,14 @@ public class Bullet extends PhysicsObject {
.add(player.getOrientation().perp().mul(Player.RADIUS))
);
this.setOrientation(player.getOrientation());
- float inaccuracy = player.getGun().getType().inaccuracy();
+ float inaccuracy = this.gun.getType().inaccuracy();
if (player.isSneaking()) {
inaccuracy *= sneakAccuracyModifier;
} else if (player.isSprinting()) {
inaccuracy *= sprintAccuracyModifier;
}
Vec2 perturbation = Vec2.random(-1, 1).mul(inaccuracy);
- Vec2 localVelocity = this.getOrientation().add(perturbation).mul(player.getGun().getType().bulletSpeed());
+ Vec2 localVelocity = this.getOrientation().add(perturbation).mul(this.gun.getType().bulletSpeed());
this.setVelocity(player.getVelocity().add(localVelocity));
}
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/model/Player.java b/core/src/main/java/nl/andrewlalis/aos_core/model/Player.java
index d9e258f..8433be0 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/model/Player.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/model/Player.java
@@ -2,45 +2,38 @@ package nl.andrewlalis.aos_core.model;
import nl.andrewlalis.aos_core.geom.Vec2;
import nl.andrewlalis.aos_core.model.tools.Gun;
-import nl.andrewlalis.aos_core.model.tools.GunType;
+import nl.andrewlalis.aos_core.model.tools.Knife;
import nl.andrewlalis.aos_core.model.tools.Tool;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
public class Player extends PhysicsObject implements Comparable {
public static final float MOVEMENT_THRESHOLD = 0.001f; // Threshold for stopping movement. Speeds slower than this are reduced to 0.
public static final float RADIUS = 0.5f; // Collision radius, in meters.
+ public static final float TOOL_CHANGE_TIME = 0.5f; // Cooldown when swapping weapons, in seconds.
private final int id;
private final String name;
private Team team;
private PlayerControlState state;
- private List tools;
- private Tool selectedTool;
+ private final List tools;
+ private int selectedToolIndex;
private float health;
- // Stats
- private transient int killCount;
- private transient int deathCount;
- private transient int shotCount;
- private transient int resupplyCount;
- private transient int killStreak;
-
private transient long lastResupply;
+ private transient long lastToolChange;
- public Player(int id, String name, Team team, GunType gunType, float maxHealth) {
+ public Player(int id, String name, Team team, float maxHealth) {
this.id = id;
this.name = name;
this.team = team;
this.state = new PlayerControlState();
this.health = maxHealth;
- this.tools = new ArrayList<>();
- var gun = new Gun(gunType);
- this.tools.add(gun);
- this.selectedTool = gun;
+ this.tools = new CopyOnWriteArrayList<>();
+ this.tools.add(new Knife());
+ this.selectedToolIndex = 0;
}
public int getId() {
@@ -72,7 +65,30 @@ public class Player extends PhysicsObject implements Comparable {
}
public Tool getSelectedTool() {
- return this.selectedTool;
+ if (this.tools.isEmpty()) return null;
+ return this.tools.get(this.selectedToolIndex);
+ }
+
+ public boolean canChangeSelectedTool() {
+ return System.currentTimeMillis() - this.lastToolChange > TOOL_CHANGE_TIME * 1000;
+ }
+
+ public void setSelectedToolIndex(int index) {
+ if (index > this.tools.size() - 1) {
+ index = 0;
+ } else if (index < 0) {
+ index = this.tools.size() - 1;
+ }
+ this.selectedToolIndex = index;
+ this.lastToolChange = System.currentTimeMillis();
+ }
+
+ public void selectNextTool() {
+ this.setSelectedToolIndex(this.selectedToolIndex + 1);
+ }
+
+ public void selectPreviousTool() {
+ this.setSelectedToolIndex(this.selectedToolIndex - 1);
}
public void setHealth(float health) {
@@ -80,10 +96,11 @@ public class Player extends PhysicsObject implements Comparable {
}
public boolean canUseGun() {
- return this.state.isShooting() &&
- this.selectedTool instanceof Gun gun && gun.isUsable() &&
+ return this.state.isUsingTool() &&
+ this.getSelectedTool() instanceof Gun gun && gun.isUsable() &&
(this.getTeam() == null || this.getTeam().getSpawnPoint().dist(this.getPosition()) > Team.SPAWN_RADIUS);
}
+
public boolean canResupply(float resupplyCooldown) {
return this.team != null &&
this.team.getSupplyPoint().dist(this.getPosition()) < Team.SUPPLY_POINT_RADIUS &&
@@ -96,7 +113,6 @@ public class Player extends PhysicsObject implements Comparable {
}
this.health = maxHealth;
this.lastResupply = System.currentTimeMillis();
- this.resupplyCount++;
}
public float getHealth() {
@@ -127,43 +143,6 @@ public class Player extends PhysicsObject implements Comparable {
!this.state.isSneaking();
}
- public int getKillCount() {
- return killCount;
- }
-
- public int getDeathCount() {
- return deathCount;
- }
-
- public int getShotCount() {
- return shotCount;
- }
-
- public int getResupplyCount() {
- return resupplyCount;
- }
-
- public int getKillStreak() {
- return killStreak;
- }
-
- public void incrementDeathCount() {
- this.deathCount++;
- this.killStreak = 0;
- }
-
- public void incrementKillCount() {
- this.killCount++;
- this.killStreak++;
- }
-
- public void resetStats() {
- this.killCount = 0;
- this.deathCount = 0;
- this.shotCount = 0;
- this.resupplyCount = 0;
- }
-
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/model/PlayerControlState.java b/core/src/main/java/nl/andrewlalis/aos_core/model/PlayerControlState.java
index 771adc5..a6f8468 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/model/PlayerControlState.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/model/PlayerControlState.java
@@ -1,11 +1,15 @@
package nl.andrewlalis.aos_core.model;
import nl.andrewlalis.aos_core.geom.Vec2;
-import nl.andrewlalis.aos_core.net.data.DataTypes;
import java.io.Serializable;
import java.nio.ByteBuffer;
+/**
+ * This object represents the player's controls at a given point in time. This
+ * object is sent by the client to the server each time the client's inputs
+ * change somehow.
+ */
public class PlayerControlState implements Serializable {
boolean movingLeft;
boolean movingRight;
@@ -14,9 +18,12 @@ public class PlayerControlState implements Serializable {
boolean sprinting;
boolean sneaking;
- boolean shooting;
+ boolean usingTool;
boolean reloading;
+ boolean selectingPreviousTool;
+ boolean selectingNextTool;
+
Vec2 mouseLocation;
public boolean isMovingLeft() {
@@ -67,12 +74,12 @@ public class PlayerControlState implements Serializable {
this.sneaking = sneaking;
}
- public boolean isShooting() {
- return shooting;
+ public boolean isUsingTool() {
+ return usingTool;
}
- public void setShooting(boolean shooting) {
- this.shooting = shooting;
+ public void setUsingTool(boolean usingTool) {
+ this.usingTool = usingTool;
}
public boolean isReloading() {
@@ -83,6 +90,22 @@ public class PlayerControlState implements Serializable {
this.reloading = reloading;
}
+ public boolean isSelectingPreviousTool() {
+ return selectingPreviousTool;
+ }
+
+ public void setSelectingPreviousTool(boolean selectingPreviousTool) {
+ this.selectingPreviousTool = selectingPreviousTool;
+ }
+
+ public boolean isSelectingNextTool() {
+ return selectingNextTool;
+ }
+
+ public void setSelectingNextTool(boolean selectingNextTool) {
+ this.selectingNextTool = selectingNextTool;
+ }
+
public Vec2 getMouseLocation() {
return mouseLocation;
}
@@ -98,10 +121,12 @@ public class PlayerControlState implements Serializable {
if (this.movingRight) flags |= 2;
if (this.movingForward) flags |= 4;
if (this.movingBackward) flags |= 8;
- if (this.shooting) flags |= 16;
+ if (this.usingTool) flags |= 16;
if (this.reloading) flags |= 32;
if (this.sprinting) flags |= 64;
if (this.sneaking) flags |= 128;
+ if (this.selectingPreviousTool) flags |= 256;
+ if (this.selectingNextTool) flags |= 512;
buffer.putInt(flags);
buffer.putFloat(this.mouseLocation.x());
buffer.putFloat(this.mouseLocation.y());
@@ -116,10 +141,12 @@ public class PlayerControlState implements Serializable {
s.movingRight = (flags & 2) > 0;
s.movingForward = (flags & 4) > 0;
s.movingBackward = (flags & 8) > 0;
- s.shooting = (flags & 16) > 0;
+ s.usingTool = (flags & 16) > 0;
s.reloading = (flags & 32) > 0;
s.sprinting = (flags & 64) > 0;
s.sneaking = (flags & 128) > 0;
+ s.selectingPreviousTool = (flags & 256) > 0;
+ s.selectingNextTool = (flags & 512) > 0;
s.mouseLocation = new Vec2(buffer.getFloat(), buffer.getFloat());
return s;
}
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/model/Team.java b/core/src/main/java/nl/andrewlalis/aos_core/model/Team.java
index 113f3f2..5f7572e 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/model/Team.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/model/Team.java
@@ -14,7 +14,7 @@ public class Team implements Serializable {
private final byte id;
private final String name;
- private final java.awt.Color color;
+ private final Color color;
private final Vec2 spawnPoint;
private final Vec2 supplyPoint;
private final Vec2 orientation;
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/model/World.java b/core/src/main/java/nl/andrewlalis/aos_core/model/World.java
index 47e9485..cb778f8 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/model/World.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/model/World.java
@@ -43,6 +43,13 @@ public class World implements Serializable {
return gunTypes;
}
+ public GunType getGunTypeById(byte id) {
+ for (var t : this.gunTypes.values()) {
+ if (t.id() == id) return t;
+ }
+ return null;
+ }
+
public Map getPlayers() {
return this.players;
}
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/model/tools/Grenade.java b/core/src/main/java/nl/andrewlalis/aos_core/model/tools/Grenade.java
index f88e0a2..b904739 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/model/tools/Grenade.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/model/tools/Grenade.java
@@ -5,16 +5,17 @@ package nl.andrewlalis.aos_core.model.tools;
* world, if there are some grenades available.
*/
public class Grenade implements Tool {
- private final int maxGrenades = 3;
+ private final int maxGrenades;
private int grenades;
- public Grenade(int grenades) {
+ public Grenade(int grenades, int maxGrenades) {
this.grenades = grenades;
+ this.maxGrenades = maxGrenades;
}
public Grenade() {
- this.grenades = maxGrenades;
+ this(3, 3);
}
public int getGrenadesRemaining() {
@@ -25,6 +26,14 @@ public class Grenade implements Tool {
return maxGrenades;
}
+ /**
+ * @return The name of the tool, as it should be shown to the players.
+ */
+ @Override
+ public String getName() {
+ return "Grenade";
+ }
+
@Override
public void use() {
this.grenades--;
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/model/tools/Gun.java b/core/src/main/java/nl/andrewlalis/aos_core/model/tools/Gun.java
index 8b86b96..f63fb96 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/model/tools/Gun.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/model/tools/Gun.java
@@ -19,16 +19,17 @@ public class Gun implements Tool {
private transient long reloadingStartedAt;
private boolean reloading;
- public Gun(GunType type, int currentClipBulletCount, int clipCount) {
+ public Gun(GunType type, int currentClipBulletCount, int clipCount, boolean reloading) {
this.type = type;
this.currentClipBulletCount = currentClipBulletCount;
this.clipCount = clipCount;
+ this.reloading = reloading;
this.lastShot = System.currentTimeMillis();
}
public Gun(GunType type) {
- this(type, 0, type.maxClipCount());
+ this(type, 0, type.maxClipCount(), false);
}
public GunType getType() {
@@ -76,6 +77,14 @@ public class Gun implements Tool {
this.reloading = false;
}
+ /**
+ * @return The name of the tool, as it should be shown to the players.
+ */
+ @Override
+ public String getName() {
+ return this.getType().name();
+ }
+
@Override
public void use() {
this.lastShot = System.currentTimeMillis();
@@ -91,6 +100,15 @@ public class Gun implements Tool {
public boolean isUsable() {
return !this.reloading &&
this.currentClipBulletCount > 0 &&
- this.lastShot + (this.type.shotCooldownTime() * 1000) < System.currentTimeMillis();
+ (this.lastShot + (long) (this.type.shotCooldownTime() * 1000)) < System.currentTimeMillis();
+ }
+
+ @Override
+ public void reset() {
+ this.reloading = false;
+ this.currentClipBulletCount = this.type.clipSize();
+ this.clipCount = this.type.maxClipCount();
+ this.lastShot = 0;
+ this.reloadingStartedAt = 0;
}
}
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/model/tools/GunType.java b/core/src/main/java/nl/andrewlalis/aos_core/model/tools/GunType.java
index 54b4e7a..4aea1ea 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/model/tools/GunType.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/model/tools/GunType.java
@@ -1,9 +1,12 @@
package nl.andrewlalis.aos_core.model.tools;
+import java.io.Serializable;
+
/**
* Information about a particular type of gun.
*/
-public record GunType(
+public record GunType (
+ byte id,
String name,
GunCategory category,
String color,
@@ -16,4 +19,4 @@ public record GunType(
float bulletSpeed,
float baseDamage,
float recoil
-) {}
+) implements Serializable {}
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/model/tools/Knife.java b/core/src/main/java/nl/andrewlalis/aos_core/model/tools/Knife.java
new file mode 100644
index 0000000..36b3b51
--- /dev/null
+++ b/core/src/main/java/nl/andrewlalis/aos_core/model/tools/Knife.java
@@ -0,0 +1,45 @@
+package nl.andrewlalis.aos_core.model.tools;
+
+public class Knife implements Tool {
+ /**
+ * @return The name of the tool, as it should be shown to the players.
+ */
+ @Override
+ public String getName() {
+ return "Knife";
+ }
+
+ /**
+ * Uses the tool.
+ */
+ @Override
+ public void use() {
+
+ }
+
+ /**
+ * Resupplies the tool, when a player is resupplied at their team's area.
+ */
+ @Override
+ public void resupply() {
+
+ }
+
+ /**
+ * Resets the tool to its preferred initial state. This is useful for things
+ * like respawning.
+ */
+ @Override
+ public void reset() {
+
+ }
+
+ /**
+ * @return True if the player may use the tool to perform an action, or
+ * false if it's not possible to do so.
+ */
+ @Override
+ public boolean isUsable() {
+ return true;
+ }
+}
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/model/tools/Tool.java b/core/src/main/java/nl/andrewlalis/aos_core/model/tools/Tool.java
index de59f58..2b67993 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/model/tools/Tool.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/model/tools/Tool.java
@@ -6,6 +6,11 @@ import java.io.Serializable;
* Represents some sort of usable tool item that players can equip and use.
*/
public interface Tool extends Serializable {
+ /**
+ * @return The name of the tool, as it should be shown to the players.
+ */
+ String getName();
+
/**
* Uses the tool.
*/
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/net/data/PlayerDetailUpdate.java b/core/src/main/java/nl/andrewlalis/aos_core/net/data/PlayerDetailUpdate.java
index 2fbacfd..4711387 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/net/data/PlayerDetailUpdate.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/net/data/PlayerDetailUpdate.java
@@ -3,9 +3,11 @@ package nl.andrewlalis.aos_core.net.data;
import nl.andrewlalis.aos_core.model.Player;
import nl.andrewlalis.aos_core.model.tools.Grenade;
import nl.andrewlalis.aos_core.model.tools.Gun;
+import nl.andrewlalis.aos_core.model.tools.Knife;
import nl.andrewlalis.aos_core.model.tools.Tool;
import nl.andrewlalis.aos_core.net.data.tool.GrenadeData;
import nl.andrewlalis.aos_core.net.data.tool.GunData;
+import nl.andrewlalis.aos_core.net.data.tool.KnifeData;
import nl.andrewlalis.aos_core.net.data.tool.ToolData;
import java.nio.ByteBuffer;
@@ -14,28 +16,33 @@ import java.util.List;
public class PlayerDetailUpdate {
private final float health;
-
- private List tools;
- private int selectedToolIndex;
+ private final List tools;
+ private final int selectedToolIndex;
public PlayerDetailUpdate(Player player) {
this.health = player.getHealth();
this.tools = new ArrayList<>(player.getTools().size());
+ int toolIndex = 0;
for (int i = 0; i < player.getTools().size(); i++) {
var t = player.getTools().get(i);
- if (t instanceof Gun g) {
+ if (t instanceof Knife k) {
+ this.tools.add(new KnifeData(k));
+ } else if (t instanceof Gun g) {
this.tools.add(new GunData(g));
} else if (t instanceof Grenade g) {
this.tools.add(new GrenadeData(g));
}
if (t.equals(player.getSelectedTool())) {
- selectedToolIndex = i;
+ toolIndex = i;
}
}
+ this.selectedToolIndex = toolIndex;
}
private PlayerDetailUpdate(float health, List tools, int selectedToolIndex) {
this.health = health;
+ this.tools = tools;
+ this.selectedToolIndex = selectedToolIndex;
}
public float getHealth() {
@@ -46,10 +53,14 @@ public class PlayerDetailUpdate {
return tools;
}
+ public int getSelectedToolIndex() {
+ return this.selectedToolIndex;
+ }
+
public byte[] toBytes() {
int size = Float.BYTES + 2 * Integer.BYTES;
for (var td : this.tools) {
- size += td.getByteSize();
+ size += 1 + td.getByteSize();
}
ByteBuffer buffer = ByteBuffer.allocate(size);
buffer.putFloat(this.health);
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/net/data/PlayerUpdate.java b/core/src/main/java/nl/andrewlalis/aos_core/net/data/PlayerUpdate.java
index 5bc4b3a..50681db 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/net/data/PlayerUpdate.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/net/data/PlayerUpdate.java
@@ -4,21 +4,22 @@ import nl.andrewlalis.aos_core.geom.Vec2;
import nl.andrewlalis.aos_core.model.Player;
import nl.andrewlalis.aos_core.model.tools.Grenade;
import nl.andrewlalis.aos_core.model.tools.Gun;
+import nl.andrewlalis.aos_core.model.tools.Knife;
import nl.andrewlalis.aos_core.net.data.tool.GrenadeData;
import nl.andrewlalis.aos_core.net.data.tool.GunData;
+import nl.andrewlalis.aos_core.net.data.tool.KnifeData;
import nl.andrewlalis.aos_core.net.data.tool.ToolData;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.nio.ByteBuffer;
/**
* 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 static final int BYTES = Integer.BYTES + 6 * Float.BYTES + 1;
-
private final int id;
private final Vec2 position;
private final Vec2 orientation;
@@ -30,7 +31,9 @@ public class PlayerUpdate {
this.position = player.getPosition();
this.orientation = player.getOrientation();
this.velocity = player.getVelocity();
- if (player.getSelectedTool() instanceof Gun gun) {
+ if (player.getSelectedTool() instanceof Knife knife) {
+ this.selectedTool = new KnifeData(knife);
+ } else if (player.getSelectedTool() instanceof Gun gun) {
this.selectedTool = new GunData(gun);
} else if (player.getSelectedTool() instanceof Grenade grenade) {
this.selectedTool = new GrenadeData(grenade);
@@ -39,12 +42,12 @@ public class PlayerUpdate {
}
}
- public PlayerUpdate(int id, Vec2 position, Vec2 orientation, Vec2 velocity) {
+ public PlayerUpdate(int id, Vec2 position, Vec2 orientation, Vec2 velocity, ToolData selectedTool) {
this.id = id;
this.position = position;
this.orientation = orientation;
this.velocity = velocity;
- this.selectedTool = null;
+ this.selectedTool = selectedTool;
}
public int getId() {
@@ -63,6 +66,10 @@ public class PlayerUpdate {
return velocity;
}
+ public ToolData getSelectedTool() {
+ return selectedTool;
+ }
+
public void write(DataOutputStream out) throws IOException {
out.writeInt(this.id);
out.writeFloat(this.position.x());
@@ -71,6 +78,10 @@ public class PlayerUpdate {
out.writeFloat(this.orientation.y());
out.writeFloat(this.velocity.x());
out.writeFloat(this.velocity.y());
+ out.writeInt(1 + this.selectedTool.getByteSize());
+ ByteBuffer buffer = ByteBuffer.allocate(1 + this.selectedTool.getByteSize());
+ this.selectedTool.write(buffer);
+ out.write(buffer.array());
}
public static PlayerUpdate read(DataInputStream in) throws IOException {
@@ -78,6 +89,9 @@ public class PlayerUpdate {
Vec2 position = Vec2.read(in);
Vec2 orientation = Vec2.read(in);
Vec2 velocity = Vec2.read(in);
- return new PlayerUpdate(id, position, orientation, velocity, gunTypeName);
+ int toolByteSize = in.readInt();
+ ByteBuffer buffer = ByteBuffer.wrap(in.readNBytes(toolByteSize));
+ ToolData tool = ToolData.read(buffer);
+ return new PlayerUpdate(id, position, orientation, velocity, tool);
}
}
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/net/data/WorldUpdate.java b/core/src/main/java/nl/andrewlalis/aos_core/net/data/WorldUpdate.java
index d5f0f52..c8316c7 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/net/data/WorldUpdate.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/net/data/WorldUpdate.java
@@ -75,12 +75,7 @@ public class WorldUpdate {
}
public byte[] toBytes() throws IOException {
- int size = 3 * Integer.BYTES + // List size integers.
- this.playerUpdates.size() * PlayerUpdate.BYTES +
- this.bulletUpdates.size() * BulletUpdate.BYTES +
- this.teamUpdates.size() * TeamUpdate.BYTES +
- this.soundsToPlay.size() * SoundData.BYTES;
- ByteArrayOutputStream out = new ByteArrayOutputStream(size);
+ ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
DataOutputStream dataOut = new DataOutputStream(out);
dataOut.writeInt(this.playerUpdates.size());
for (var u : this.playerUpdates) {
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/net/data/tool/GrenadeData.java b/core/src/main/java/nl/andrewlalis/aos_core/net/data/tool/GrenadeData.java
index ea621bd..4cc87d4 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/net/data/tool/GrenadeData.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/net/data/tool/GrenadeData.java
@@ -1,6 +1,8 @@
package nl.andrewlalis.aos_core.net.data.tool;
+import nl.andrewlalis.aos_core.model.World;
import nl.andrewlalis.aos_core.model.tools.Grenade;
+import nl.andrewlalis.aos_core.model.tools.Tool;
import java.nio.ByteBuffer;
@@ -18,6 +20,14 @@ public class GrenadeData extends ToolData {
this.maxGrenades = grenade.getMaxGrenades();
}
+ public int getGrenades() {
+ return grenades;
+ }
+
+ public int getMaxGrenades() {
+ return maxGrenades;
+ }
+
@Override
public int getByteSize() {
return 2 * Integer.BYTES;
@@ -34,4 +44,9 @@ public class GrenadeData extends ToolData {
this.grenades = buffer.getInt();
this.maxGrenades = buffer.getInt();
}
+
+ @Override
+ public Tool toTool(World world) {
+ return new Grenade(this.grenades, this.maxGrenades);
+ }
}
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/net/data/tool/GunData.java b/core/src/main/java/nl/andrewlalis/aos_core/net/data/tool/GunData.java
index b23d27e..f2aecb5 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/net/data/tool/GunData.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/net/data/tool/GunData.java
@@ -1,10 +1,13 @@
package nl.andrewlalis.aos_core.net.data.tool;
+import nl.andrewlalis.aos_core.model.World;
import nl.andrewlalis.aos_core.model.tools.Gun;
+import nl.andrewlalis.aos_core.model.tools.Tool;
import java.nio.ByteBuffer;
public class GunData extends ToolData {
+ private byte typeId;
private boolean reloading;
private int clipCount;
private int currentClipBulletCount;
@@ -18,6 +21,7 @@ public class GunData extends ToolData {
public GunData(Gun gun) {
this();
+ this.typeId = gun.getType().id();
this.reloading = gun.isReloading();
this.clipCount = gun.getClipCount();
this.currentClipBulletCount = gun.getCurrentClipBulletCount();
@@ -26,6 +30,10 @@ public class GunData extends ToolData {
this.maxClipCount = gun.getType().maxClipCount();
}
+ public byte getTypeId() {
+ return typeId;
+ }
+
public boolean isReloading() {
return reloading;
}
@@ -52,11 +60,12 @@ public class GunData extends ToolData {
@Override
public int getByteSize() {
- return 1 + 5 * Integer.BYTES;
+ return 2 * Byte.BYTES + 5 * Integer.BYTES;
}
@Override
protected void putData(ByteBuffer buffer) {
+ buffer.put(this.getTypeId());
buffer.put((byte) (this.reloading ? 1 : 0));
buffer.putInt(this.clipCount);
buffer.putInt(this.currentClipBulletCount);
@@ -67,6 +76,7 @@ public class GunData extends ToolData {
@Override
protected void getData(ByteBuffer buffer) {
+ this.typeId = buffer.get();
this.reloading = buffer.get() == 1;
this.clipCount = buffer.getInt();
this.currentClipBulletCount = buffer.getInt();
@@ -74,4 +84,9 @@ public class GunData extends ToolData {
this.clipSize = buffer.getInt();
this.maxClipCount = buffer.getInt();
}
+
+ @Override
+ public Tool toTool(World world) {
+ return new Gun(world.getGunTypeById(this.getTypeId()), this.currentClipBulletCount, this.clipCount, this.reloading);
+ }
}
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/net/data/tool/KnifeData.java b/core/src/main/java/nl/andrewlalis/aos_core/net/data/tool/KnifeData.java
new file mode 100644
index 0000000..46d27b1
--- /dev/null
+++ b/core/src/main/java/nl/andrewlalis/aos_core/net/data/tool/KnifeData.java
@@ -0,0 +1,37 @@
+package nl.andrewlalis.aos_core.net.data.tool;
+
+import nl.andrewlalis.aos_core.model.World;
+import nl.andrewlalis.aos_core.model.tools.Knife;
+import nl.andrewlalis.aos_core.model.tools.Tool;
+
+import java.nio.ByteBuffer;
+
+public class KnifeData extends ToolData {
+ public KnifeData() {
+ super((byte) 2);
+ }
+
+ public KnifeData(Knife knife) {
+ super((byte) 2);
+ }
+
+ @Override
+ public int getByteSize() {
+ return 1;
+ }
+
+ @Override
+ protected void putData(ByteBuffer buffer) {
+ buffer.put((byte) 0);
+ }
+
+ @Override
+ protected void getData(ByteBuffer buffer) {
+ buffer.get();
+ }
+
+ @Override
+ public Tool toTool(World world) {
+ return new Knife();
+ }
+}
diff --git a/core/src/main/java/nl/andrewlalis/aos_core/net/data/tool/ToolData.java b/core/src/main/java/nl/andrewlalis/aos_core/net/data/tool/ToolData.java
index b3090d5..a65bdd6 100644
--- a/core/src/main/java/nl/andrewlalis/aos_core/net/data/tool/ToolData.java
+++ b/core/src/main/java/nl/andrewlalis/aos_core/net/data/tool/ToolData.java
@@ -1,5 +1,8 @@
package nl.andrewlalis.aos_core.net.data.tool;
+import nl.andrewlalis.aos_core.model.World;
+import nl.andrewlalis.aos_core.model.tools.Tool;
+
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
@@ -9,6 +12,7 @@ public abstract class ToolData {
static {
dataMapping.put((byte) 0, GunData.class);
dataMapping.put((byte) 1, GrenadeData.class);
+ dataMapping.put((byte) 2, KnifeData.class);
}
private final byte toolType;
@@ -52,4 +56,11 @@ public abstract class ToolData {
* @param buffer The byte buffer to read data from.
*/
protected abstract void getData(ByteBuffer buffer);
+
+ /**
+ * Converts this data back into a Tool instance.
+ * @param world The world in which the tool is being used.
+ * @return The tool that this data represents.
+ */
+ public abstract Tool toTool(World world);
}
diff --git a/network.md b/network.md
new file mode 100644
index 0000000..48675b1
--- /dev/null
+++ b/network.md
@@ -0,0 +1,8 @@
+# Networking Protocol
+In order to make Ace of Shades as performant as possible, the application makes use of a custom, rather low-level system of communication between the server and client. This document explains how this protocol works.
+
+## Tick Updates
+Every time the server computes one game tick, it sends a packet to each client. This packet includes the following information:
+
+- Updated position, velocity, and orientation data for all physics objects.
+-
diff --git a/pom.xml b/pom.xml
index b3bf81b..5990a35 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
nl.andrewlalis
ace-of-shades
pom
- 0.5.0
+ 0.6.0
server
client
diff --git a/server-registry/pom.xml b/server-registry/pom.xml
index 83aa913..b24c3c7 100644
--- a/server-registry/pom.xml
+++ b/server-registry/pom.xml
@@ -5,7 +5,7 @@
ace-of-shades
nl.andrewlalis
- 0.5.0
+ 0.6.0
4.0.0
diff --git a/server/pom.xml b/server/pom.xml
index 334f210..ba71cdd 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -5,7 +5,7 @@
ace-of-shades
nl.andrewlalis
- 0.5.0
+ 0.6.0
4.0.0
diff --git a/server/src/main/java/nl/andrewlalis/aos_server/Server.java b/server/src/main/java/nl/andrewlalis/aos_server/Server.java
index b2cfad6..32ca381 100644
--- a/server/src/main/java/nl/andrewlalis/aos_server/Server.java
+++ b/server/src/main/java/nl/andrewlalis/aos_server/Server.java
@@ -1,7 +1,12 @@
package nl.andrewlalis.aos_server;
import nl.andrewlalis.aos_core.geom.Vec2;
-import nl.andrewlalis.aos_core.model.*;
+import nl.andrewlalis.aos_core.model.Barricade;
+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.tools.Grenade;
+import nl.andrewlalis.aos_core.model.tools.Gun;
import nl.andrewlalis.aos_core.model.tools.GunCategory;
import nl.andrewlalis.aos_core.model.tools.GunType;
import nl.andrewlalis.aos_core.net.Message;
@@ -9,6 +14,7 @@ import nl.andrewlalis.aos_core.net.PlayerUpdateMessage;
import nl.andrewlalis.aos_core.net.Type;
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
import nl.andrewlalis.aos_core.net.data.DataTypes;
+import nl.andrewlalis.aos_core.model.PlayerControlState;
import nl.andrewlalis.aos_core.net.data.PlayerDetailUpdate;
import nl.andrewlalis.aos_core.net.data.WorldUpdate;
import nl.andrewlalis.aos_core.util.ByteUtils;
@@ -59,8 +65,10 @@ public class Server {
}
private void initWorld() {
+ byte gunTypeId = 0;
for (var gs : this.settings.getGunSettings()) {
this.world.getGunTypes().put(gs.getName(), new GunType(
+ gunTypeId++,
gs.getName(),
GunCategory.valueOf(gs.getCategory().toUpperCase()),
gs.getColor(),
@@ -136,7 +144,9 @@ public class Server {
team = t;
}
}
- Player p = new Player(id, name, team, this.world.getGunTypes().get(this.settings.getPlayerSettings().getDefaultGun()), settings.getPlayerSettings().getMaxHealth());
+ Player p = new Player(id, name, team, settings.getPlayerSettings().getMaxHealth());
+ p.getTools().add(new Gun(this.world.getGunTypes().get(this.settings.getPlayerSettings().getDefaultGun())));
+ p.getTools().add(new Grenade(3, 3));
this.world.getPlayers().put(p.getId(), p);
String message = p.getName() + " connected.";
this.broadcastMessage(new SystemChatMessage(SystemChatMessage.Level.INFO, message));
@@ -204,7 +214,6 @@ public class Server {
for (Team t : this.world.getTeams().values()) {
t.resetScore();
for (Player p : t.getPlayers()) {
- p.resetStats();
p.respawn(settings.getPlayerSettings().getMaxHealth());
}
}
diff --git a/server/src/main/java/nl/andrewlalis/aos_server/WorldUpdater.java b/server/src/main/java/nl/andrewlalis/aos_server/WorldUpdater.java
index 9b47fa6..d1379e3 100644
--- a/server/src/main/java/nl/andrewlalis/aos_server/WorldUpdater.java
+++ b/server/src/main/java/nl/andrewlalis/aos_server/WorldUpdater.java
@@ -2,6 +2,7 @@ package nl.andrewlalis.aos_server;
import nl.andrewlalis.aos_core.geom.Vec2;
import nl.andrewlalis.aos_core.model.*;
+import nl.andrewlalis.aos_core.model.tools.Gun;
import nl.andrewlalis.aos_core.model.tools.GunCategory;
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
import nl.andrewlalis.aos_core.net.data.SoundData;
@@ -71,7 +72,7 @@ public class WorldUpdater extends Thread {
private void updatePlayers(float t) {
for (Player p : this.world.getPlayers().values()) {
this.updatePlayerMovement(p, t);
- this.updatePlayerShooting(p);
+ this.updatePlayerInteraction(p);
p.setHealth(Math.min(p.getHealth() + server.getSettings().getPlayerSettings().getHealthRegenRate() * t, server.getSettings().getPlayerSettings().getMaxHealth()));
this.worldUpdate.addPlayer(p);
}
@@ -183,31 +184,38 @@ public class WorldUpdater extends Thread {
}
}
- private void updatePlayerShooting(Player p) {
- if (p.canUseGun()) {
- for (int i = 0; i < p.getGun().getType().bulletsPerRound(); i++) {
- Bullet b = new Bullet(p, server.getSettings().getPlayerSettings().getSneakAccuracyModifier(), server.getSettings().getPlayerSettings().getSprintAccuracyModifier());
- this.world.getBullets().add(b);
- this.worldUpdate.addBullet(b);
- }
- SoundType soundType = SoundType.SHOT_SMG;
- if (p.getGun().getType().category() == GunCategory.RIFLE) {
- soundType = SoundType.SHOT_RIFLE;
- } else if (p.getGun().getType().category() == GunCategory.SHOTGUN) {
- soundType = SoundType.SHOT_SHOTGUN;
- } else if (p.getGun().getType().category() == GunCategory.MACHINE) {
- soundType = ThreadLocalRandom.current().nextFloat() < 0.8f ? SoundType.SHOT_MACHINE_GUN_1 : SoundType.SHOT_MACHINE_GUN_2;
- }
- this.worldUpdate.addSound(new SoundData(p.getPosition(), 1.0f, soundType));
- p.useWeapon();
- p.setVelocity(p.getVelocity().add(p.getOrientation().mul(-1 * p.getGun().getType().recoil())));
+ private void updatePlayerInteraction(Player p) {
+ if ((p.getState().isSelectingNextTool() ^ p.getState().isSelectingPreviousTool()) && p.canChangeSelectedTool()) {
+ if (p.getState().isSelectingNextTool()) p.selectNextTool();
+ if (p.getState().isSelectingPreviousTool()) p.selectPreviousTool();
+ return; // Don't immediately do any action with the newly-selected tool.
}
- if (p.getState().isReloading() && !p.isReloading() && p.getGun().canReload()) {
- p.startReloading();
- }
- if (p.isReloading() && p.isReloadingComplete()) {
- p.finishReloading();
- this.worldUpdate.addSound(new SoundData(p.getPosition(), 1.0f, SoundType.RELOAD));
+ if (p.getSelectedTool() instanceof Gun gun) {
+ if (p.canUseGun()) {
+ for (int i = 0; i < gun.getType().bulletsPerRound(); i++) {
+ Bullet b = new Bullet(p, gun, server.getSettings().getPlayerSettings().getSneakAccuracyModifier(), server.getSettings().getPlayerSettings().getSprintAccuracyModifier());
+ this.world.getBullets().add(b);
+ this.worldUpdate.addBullet(b);
+ }
+ SoundType soundType = SoundType.SHOT_SMG;
+ if (gun.getType().category() == GunCategory.RIFLE) {
+ soundType = SoundType.SHOT_RIFLE;
+ } else if (gun.getType().category() == GunCategory.SHOTGUN) {
+ soundType = SoundType.SHOT_SHOTGUN;
+ } else if (gun.getType().category() == GunCategory.MACHINE) {
+ soundType = ThreadLocalRandom.current().nextFloat() < 0.8f ? SoundType.SHOT_MACHINE_GUN_1 : SoundType.SHOT_MACHINE_GUN_2;
+ }
+ this.worldUpdate.addSound(new SoundData(p.getPosition(), 1.0f, soundType));
+ gun.use();
+ p.setVelocity(p.getVelocity().add(p.getOrientation().mul(-1 * gun.getType().recoil())));
+ }
+ if (p.getState().isReloading() && !gun.isReloading() && gun.canReload()) {
+ gun.startReloading();
+ }
+ if (gun.isReloading() && gun.isReloadingComplete()) {
+ gun.reload();
+ this.worldUpdate.addSound(new SoundData(p.getPosition(), 1.0f, SoundType.RELOAD));
+ }
}
}
@@ -261,12 +269,10 @@ public class WorldUpdater extends Thread {
Player shooter = this.world.getPlayers().get(b.getPlayerId());
this.server.broadcastMessage(new SystemChatMessage(SystemChatMessage.Level.SEVERE, p.getName() + " was shot by " + shooter.getName() + "."));
this.worldUpdate.addSound(new SoundData(p.getPosition(), 1.0f, SoundType.DEATH));
- shooter.incrementKillCount();
if (shooter.getTeam() != null) {
shooter.getTeam().incrementScore();
this.worldUpdate.addTeam(shooter.getTeam());
}
- p.incrementDeathCount();
p.respawn(server.getSettings().getPlayerSettings().getMaxHealth());
}
}
diff --git a/server/src/main/java/nl/andrewlalis/aos_server/command/chat/GunCommand.java b/server/src/main/java/nl/andrewlalis/aos_server/command/chat/GunCommand.java
index c3b0974..e26251a 100644
--- a/server/src/main/java/nl/andrewlalis/aos_server/command/chat/GunCommand.java
+++ b/server/src/main/java/nl/andrewlalis/aos_server/command/chat/GunCommand.java
@@ -6,8 +6,6 @@ import nl.andrewlalis.aos_core.model.tools.GunType;
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
import nl.andrewlalis.aos_server.ClientHandler;
-import java.util.Locale;
-
public class GunCommand implements ChatCommand {
@Override
public void execute(ClientHandler handler, Player player, String[] args) {
@@ -27,7 +25,16 @@ public class GunCommand implements ChatCommand {
handler.send(new SystemChatMessage(SystemChatMessage.Level.WARNING, "Unknown gun name. Use /guns to see available guns."));
return;
}
- player.setGun(new Gun(gunType));
- handler.send(new SystemChatMessage(SystemChatMessage.Level.INFO, "Changed gun to " + player.getGun().getType().name() + "."));
+ boolean gunSet = false;
+ for (int i = 0; i < player.getTools().size(); i++) {
+ if (player.getTools().get(i) instanceof Gun) {
+ player.getTools().set(i, new Gun(gunType));
+ gunSet = true;
+ }
+ }
+ if (!gunSet) {
+ player.getTools().add(new Gun(gunType));
+ }
+ handler.send(new SystemChatMessage(SystemChatMessage.Level.INFO, "Changed gun to " + gunType.name() + "."));
}
}
diff --git a/server/src/main/java/nl/andrewlalis/aos_server/command/chat/KillDeathRatioCommand.java b/server/src/main/java/nl/andrewlalis/aos_server/command/chat/KillDeathRatioCommand.java
index 2d86915..5dfe24d 100644
--- a/server/src/main/java/nl/andrewlalis/aos_server/command/chat/KillDeathRatioCommand.java
+++ b/server/src/main/java/nl/andrewlalis/aos_server/command/chat/KillDeathRatioCommand.java
@@ -7,7 +7,8 @@ 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)));
+// float ratio = player.getKillCount() / ((float) player.getDeathCount());
+// handler.send(new SystemChatMessage(SystemChatMessage.Level.INFO, String.format("Your Kill/Death ratio is %.2f.", ratio)));
+ handler.send(new SystemChatMessage(SystemChatMessage.Level.WARNING, "K/D command not yet implemented."));
}
}
diff --git a/server/src/main/java/nl/andrewlalis/aos_server/model/PlayerStatistics.java b/server/src/main/java/nl/andrewlalis/aos_server/model/PlayerStatistics.java
new file mode 100644
index 0000000..889ee38
--- /dev/null
+++ b/server/src/main/java/nl/andrewlalis/aos_server/model/PlayerStatistics.java
@@ -0,0 +1,9 @@
+package nl.andrewlalis.aos_server.model;
+
+public class PlayerStatistics {
+ private transient int killCount;
+ private transient int deathCount;
+ private transient int shotCount;
+ private transient int resupplyCount;
+ private transient int killStreak;
+}