Major update to add tools to players, and hopefully improve network performance.
This commit is contained in:
parent
27ee1336a7
commit
c5c05cf60d
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>ace-of-shades</artifactId>
|
<artifactId>ace-of-shades</artifactId>
|
||||||
<groupId>nl.andrewlalis</groupId>
|
<groupId>nl.andrewlalis</groupId>
|
||||||
<version>0.5.0</version>
|
<version>0.6.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
|
@ -9,14 +9,15 @@ import nl.andrewlalis.aos_client.view.GameRenderer;
|
||||||
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.Team;
|
||||||
import nl.andrewlalis.aos_core.model.World;
|
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.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 nl.andrewlalis.aos_core.net.data.DataTypes;
|
import nl.andrewlalis.aos_core.net.data.DataTypes;
|
||||||
import nl.andrewlalis.aos_core.net.data.PlayerDetailUpdate;
|
import nl.andrewlalis.aos_core.net.data.PlayerDetailUpdate;
|
||||||
import nl.andrewlalis.aos_core.net.data.WorldUpdate;
|
import nl.andrewlalis.aos_core.net.data.WorldUpdate;
|
||||||
|
import nl.andrewlalis.aos_core.net.data.tool.GrenadeData;
|
||||||
import nl.andrewlalis.aos_core.net.data.tool.GunData;
|
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;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ public class Client {
|
||||||
private final MessageTransceiver messageTransceiver;
|
private final MessageTransceiver messageTransceiver;
|
||||||
|
|
||||||
private World world;
|
private World world;
|
||||||
|
private Player player;
|
||||||
|
|
||||||
private final GameRenderer renderer;
|
private final GameRenderer renderer;
|
||||||
private final SoundManager soundManager;
|
private final SoundManager soundManager;
|
||||||
|
@ -49,7 +51,7 @@ public class Client {
|
||||||
this.messageTransceiver.start();
|
this.messageTransceiver.start();
|
||||||
this.chatManager.bindTransceiver(this.messageTransceiver);
|
this.chatManager.bindTransceiver(this.messageTransceiver);
|
||||||
|
|
||||||
while (this.myPlayer == null || this.world == null) {
|
while (this.player == null || this.world == null) {
|
||||||
try {
|
try {
|
||||||
System.out.println("Waiting for server response and player registration...");
|
System.out.println("Waiting for server response and player registration...");
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
|
@ -91,10 +93,12 @@ public class Client {
|
||||||
player.setPosition(p.getPosition());
|
player.setPosition(p.getPosition());
|
||||||
player.setOrientation(p.getOrientation());
|
player.setOrientation(p.getOrientation());
|
||||||
player.setVelocity(p.getVelocity());
|
player.setVelocity(p.getVelocity());
|
||||||
player.setGun(new Gun(this.world.getGunTypes().get(p.getGunTypeName())));
|
|
||||||
if (player.getVelocity().mag() > 0) {
|
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()) {
|
for (var t : update.getTeamUpdates()) {
|
||||||
|
@ -103,7 +107,7 @@ public class Client {
|
||||||
team.setScore(t.getScore());
|
team.setScore(t.getScore());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.soundManager.play(update.getSoundsToPlay(), myPlayer);
|
this.soundManager.play(update.getSoundsToPlay(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWorld(World world) {
|
public void setWorld(World world) {
|
||||||
|
@ -111,11 +115,11 @@ public class Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPlayer(Player player) {
|
public void setPlayer(Player player) {
|
||||||
this.myPlayer = player;
|
this.player = player;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player getPlayer() {
|
public Player getPlayer() {
|
||||||
return myPlayer;
|
return this.player;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -124,17 +128,34 @@ public class Client {
|
||||||
* @param update The updated player information from the server.
|
* @param update The updated player information from the server.
|
||||||
*/
|
*/
|
||||||
public void updatePlayer(PlayerDetailUpdate update) {
|
public void updatePlayer(PlayerDetailUpdate update) {
|
||||||
if (this.myPlayer == null) return;
|
if (this.player != null) {
|
||||||
this.myPlayer.setHealth(update.getHealth());
|
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
|
* 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.
|
* the player's controls have been updated, due to a key or mouse event.
|
||||||
*/
|
*/
|
||||||
public void sendPlayerState() {
|
public void sendControlState() {
|
||||||
try {
|
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) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ public class PlayerKeyListener extends KeyAdapter {
|
||||||
s.setReloading(false);
|
s.setReloading(false);
|
||||||
s.setSneaking(false);
|
s.setSneaking(false);
|
||||||
s.setSprinting(false);
|
s.setSprinting(false);
|
||||||
this.client.sendPlayerState();
|
this.client.sendControlState();
|
||||||
if (e.getKeyChar() == '/') this.chatManager.appendToChat('/');
|
if (e.getKeyChar() == '/') this.chatManager.appendToChat('/');
|
||||||
}
|
}
|
||||||
} else if (this.chatManager.isChatting()) {
|
} else if (this.chatManager.isChatting()) {
|
||||||
|
@ -63,8 +63,12 @@ public class PlayerKeyListener extends KeyAdapter {
|
||||||
state.setSprinting(true);
|
state.setSprinting(true);
|
||||||
} else if (e.getKeyCode() == KeyEvent.VK_CONTROL) {
|
} else if (e.getKeyCode() == KeyEvent.VK_CONTROL) {
|
||||||
state.setSneaking(true);
|
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
|
@Override
|
||||||
|
@ -85,7 +89,11 @@ public class PlayerKeyListener extends KeyAdapter {
|
||||||
state.setSprinting(false);
|
state.setSprinting(false);
|
||||||
} else if (e.getKeyCode() == KeyEvent.VK_CONTROL) {
|
} else if (e.getKeyCode() == KeyEvent.VK_CONTROL) {
|
||||||
state.setSneaking(false);
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,15 @@ import javax.swing.event.MouseInputAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.awt.event.MouseWheelEvent;
|
import java.awt.event.MouseWheelEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listens for changes to the player's mouse state. This handles the following
|
||||||
|
* possible control events:
|
||||||
|
* <ul>
|
||||||
|
* <li>Pressing the mouse to use the player's weapon.</li>
|
||||||
|
* <li>Scrolling the mouse wheel to zoom in or out.</li>
|
||||||
|
* <li>Moving the mouse to change the player's orientation.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
public class PlayerMouseListener extends MouseInputAdapter {
|
public class PlayerMouseListener extends MouseInputAdapter {
|
||||||
private static final float MOUSE_UPDATES_PER_SECOND = 60.0f;
|
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);
|
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
|
@Override
|
||||||
public void mousePressed(MouseEvent e) {
|
public void mousePressed(MouseEvent e) {
|
||||||
if (e.getButton() == MouseEvent.BUTTON1) {
|
if (e.getButton() == MouseEvent.BUTTON1) {
|
||||||
client.getPlayer().getState().setShooting(true);
|
client.getPlayer().getState().setUsingTool(true);
|
||||||
client.sendPlayerState();
|
client.sendControlState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseReleased(MouseEvent e) {
|
public void mouseReleased(MouseEvent e) {
|
||||||
if (e.getButton() == MouseEvent.BUTTON1) {
|
if (e.getButton() == MouseEvent.BUTTON1) {
|
||||||
client.getPlayer().getState().setShooting(false);
|
client.getPlayer().getState().setUsingTool(false);
|
||||||
client.sendPlayerState();
|
client.sendControlState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +63,7 @@ public class PlayerMouseListener extends MouseInputAdapter {
|
||||||
client.getPlayer().getState().setMouseLocation(centeredMouseLocation);
|
client.getPlayer().getState().setMouseLocation(centeredMouseLocation);
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
if (now - this.lastMouseMove > MS_PER_MOUSE_UPDATE) {
|
if (now - this.lastMouseMove > MS_PER_MOUSE_UPDATE) {
|
||||||
client.sendPlayerState();
|
client.sendControlState();
|
||||||
this.lastMouseMove = now;
|
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 c = new Vec2(this.gamePanel.getWidth() / 2.0f, this.gamePanel.getHeight() / 2.0f);
|
||||||
Vec2 centeredMouseLocation = new Vec2(e.getX(), e.getY()).sub(c);
|
Vec2 centeredMouseLocation = new Vec2(e.getX(), e.getY()).sub(c);
|
||||||
client.getPlayer().getState().setMouseLocation(centeredMouseLocation);
|
client.getPlayer().getState().setMouseLocation(centeredMouseLocation);
|
||||||
client.getPlayer().getState().setShooting(true);
|
client.getPlayer().getState().setUsingTool(true);
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
if (now - this.lastMouseMove > MS_PER_MOUSE_UPDATE) {
|
if (now - this.lastMouseMove > MS_PER_MOUSE_UPDATE) {
|
||||||
client.sendPlayerState();
|
client.sendControlState();
|
||||||
this.lastMouseMove = now;
|
this.lastMouseMove = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<ToolData> tools;
|
|
||||||
private int selectedToolIndex;
|
|
||||||
|
|
||||||
public float getHealth() {
|
|
||||||
return health;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ToolData> getTools() {
|
|
||||||
return tools;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSelectedToolIndex() {
|
|
||||||
return selectedToolIndex;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +1,9 @@
|
||||||
package nl.andrewlalis.aos_client.view;
|
package nl.andrewlalis.aos_client.view;
|
||||||
|
|
||||||
import nl.andrewlalis.aos_client.net.ChatManager;
|
|
||||||
import nl.andrewlalis.aos_client.Client;
|
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.*;
|
||||||
|
import nl.andrewlalis.aos_core.model.tools.Grenade;
|
||||||
import nl.andrewlalis.aos_core.model.tools.Gun;
|
import nl.andrewlalis.aos_core.model.tools.Gun;
|
||||||
import nl.andrewlalis.aos_core.net.chat.ChatMessage;
|
import nl.andrewlalis.aos_core.net.chat.ChatMessage;
|
||||||
import nl.andrewlalis.aos_core.net.chat.ChatType;
|
import nl.andrewlalis.aos_core.net.chat.ChatType;
|
||||||
|
@ -84,7 +85,7 @@ public class GamePanel extends JPanel {
|
||||||
* @param world The world to render.
|
* @param world The world to render.
|
||||||
*/
|
*/
|
||||||
private void drawWorld(Graphics2D g2, World world) {
|
private void drawWorld(Graphics2D g2, World world) {
|
||||||
Player myPlayer = client.getPlayer();
|
Player myPlayer = this.client.getPlayer();
|
||||||
if (myPlayer == null) return;
|
if (myPlayer == null) return;
|
||||||
double scale = this.scales[this.scaleIndex];
|
double scale = this.scales[this.scaleIndex];
|
||||||
AffineTransform pre = g2.getTransform();
|
AffineTransform pre = g2.getTransform();
|
||||||
|
@ -193,7 +194,9 @@ public class GamePanel extends JPanel {
|
||||||
Color playerColor = p.getTeam() != null ? p.getTeam().getColor() : Color.BLACK;
|
Color playerColor = p.getTeam() != null ? p.getTeam().getColor() : Color.BLACK;
|
||||||
g2.setColor(playerColor);
|
g2.setColor(playerColor);
|
||||||
g2.fill(dot);
|
g2.fill(dot);
|
||||||
this.drawGun(g2, p.getGun());
|
if (p.getSelectedTool() instanceof Gun gun) {
|
||||||
|
this.drawGun(g2, gun);
|
||||||
|
}
|
||||||
g2.setTransform(pre);
|
g2.setTransform(pre);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -302,21 +305,35 @@ public class GamePanel extends JPanel {
|
||||||
Player myPlayer = this.client.getPlayer();
|
Player myPlayer = this.client.getPlayer();
|
||||||
if (myPlayer == null) return;
|
if (myPlayer == null) return;
|
||||||
|
|
||||||
|
int lineHeight = this.getHeight() - 10;
|
||||||
g2.setColor(Color.WHITE);
|
g2.setColor(Color.WHITE);
|
||||||
if (myPlayer.isReloading()) {
|
if (myPlayer.getSelectedTool() != null) {
|
||||||
g2.drawString("Reloading...", 5, this.getHeight() - 10);
|
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()) {
|
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, lineHeight);
|
||||||
y -= 15;
|
lineHeight -= 15;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>ace-of-shades</artifactId>
|
<artifactId>ace-of-shades</artifactId>
|
||||||
<groupId>nl.andrewlalis</groupId>
|
<groupId>nl.andrewlalis</groupId>
|
||||||
<version>0.5.0</version>
|
<version>0.6.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
|
@ -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.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 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.geom to aos_server, aos_client;
|
||||||
exports nl.andrewlalis.aos_core.util to aos_server, aos_client;
|
exports nl.andrewlalis.aos_core.util to aos_server, aos_client;
|
||||||
|
|
|
@ -14,10 +14,10 @@ public class Bullet extends PhysicsObject {
|
||||||
private final Player player;
|
private final Player player;
|
||||||
private final Gun gun;
|
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.playerId = player.getId();
|
||||||
this.player = player;
|
this.player = player;
|
||||||
this.gun = player.getGun();
|
this.gun = gun;
|
||||||
this.setPhysicsProperties(sneakAccuracyModifier, sprintAccuracyModifier);
|
this.setPhysicsProperties(sneakAccuracyModifier, sprintAccuracyModifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,14 +34,14 @@ public class Bullet extends PhysicsObject {
|
||||||
.add(player.getOrientation().perp().mul(Player.RADIUS))
|
.add(player.getOrientation().perp().mul(Player.RADIUS))
|
||||||
);
|
);
|
||||||
this.setOrientation(player.getOrientation());
|
this.setOrientation(player.getOrientation());
|
||||||
float inaccuracy = player.getGun().getType().inaccuracy();
|
float inaccuracy = this.gun.getType().inaccuracy();
|
||||||
if (player.isSneaking()) {
|
if (player.isSneaking()) {
|
||||||
inaccuracy *= sneakAccuracyModifier;
|
inaccuracy *= sneakAccuracyModifier;
|
||||||
} else if (player.isSprinting()) {
|
} else if (player.isSprinting()) {
|
||||||
inaccuracy *= sprintAccuracyModifier;
|
inaccuracy *= sprintAccuracyModifier;
|
||||||
}
|
}
|
||||||
Vec2 perturbation = Vec2.random(-1, 1).mul(inaccuracy);
|
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));
|
this.setVelocity(player.getVelocity().add(localVelocity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,45 +2,38 @@ package nl.andrewlalis.aos_core.model;
|
||||||
|
|
||||||
import nl.andrewlalis.aos_core.geom.Vec2;
|
import nl.andrewlalis.aos_core.geom.Vec2;
|
||||||
import nl.andrewlalis.aos_core.model.tools.Gun;
|
import nl.andrewlalis.aos_core.model.tools.Gun;
|
||||||
import nl.andrewlalis.aos_core.model.tools.GunType;
|
import nl.andrewlalis.aos_core.model.tools.Knife;
|
||||||
import nl.andrewlalis.aos_core.model.tools.Tool;
|
import nl.andrewlalis.aos_core.model.tools.Tool;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
public class Player extends PhysicsObject implements Comparable<Player> {
|
public class Player extends PhysicsObject implements Comparable<Player> {
|
||||||
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 RADIUS = 0.5f; // Collision radius, in meters.
|
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 int id;
|
||||||
private final String name;
|
private final String name;
|
||||||
private Team team;
|
private Team team;
|
||||||
private PlayerControlState state;
|
private PlayerControlState state;
|
||||||
private List<Tool> tools;
|
private final List<Tool> tools;
|
||||||
private Tool selectedTool;
|
private int selectedToolIndex;
|
||||||
private float health;
|
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 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.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.team = team;
|
this.team = team;
|
||||||
this.state = new PlayerControlState();
|
this.state = new PlayerControlState();
|
||||||
this.health = maxHealth;
|
this.health = maxHealth;
|
||||||
this.tools = new ArrayList<>();
|
this.tools = new CopyOnWriteArrayList<>();
|
||||||
var gun = new Gun(gunType);
|
this.tools.add(new Knife());
|
||||||
this.tools.add(gun);
|
this.selectedToolIndex = 0;
|
||||||
this.selectedTool = gun;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getId() {
|
public int getId() {
|
||||||
|
@ -72,7 +65,30 @@ public class Player extends PhysicsObject implements Comparable<Player> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tool getSelectedTool() {
|
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) {
|
public void setHealth(float health) {
|
||||||
|
@ -80,10 +96,11 @@ public class Player extends PhysicsObject implements Comparable<Player> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canUseGun() {
|
public boolean canUseGun() {
|
||||||
return this.state.isShooting() &&
|
return this.state.isUsingTool() &&
|
||||||
this.selectedTool instanceof Gun gun && gun.isUsable() &&
|
this.getSelectedTool() instanceof Gun gun && gun.isUsable() &&
|
||||||
(this.getTeam() == null || this.getTeam().getSpawnPoint().dist(this.getPosition()) > Team.SPAWN_RADIUS);
|
(this.getTeam() == null || this.getTeam().getSpawnPoint().dist(this.getPosition()) > Team.SPAWN_RADIUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canResupply(float resupplyCooldown) {
|
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 &&
|
||||||
|
@ -96,7 +113,6 @@ public class Player extends PhysicsObject implements Comparable<Player> {
|
||||||
}
|
}
|
||||||
this.health = maxHealth;
|
this.health = maxHealth;
|
||||||
this.lastResupply = System.currentTimeMillis();
|
this.lastResupply = System.currentTimeMillis();
|
||||||
this.resupplyCount++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getHealth() {
|
public float getHealth() {
|
||||||
|
@ -127,43 +143,6 @@ 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 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
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
package nl.andrewlalis.aos_core.model;
|
package nl.andrewlalis.aos_core.model;
|
||||||
|
|
||||||
import nl.andrewlalis.aos_core.geom.Vec2;
|
import nl.andrewlalis.aos_core.geom.Vec2;
|
||||||
import nl.andrewlalis.aos_core.net.data.DataTypes;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.nio.ByteBuffer;
|
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 {
|
public class PlayerControlState implements Serializable {
|
||||||
boolean movingLeft;
|
boolean movingLeft;
|
||||||
boolean movingRight;
|
boolean movingRight;
|
||||||
|
@ -14,9 +18,12 @@ public class PlayerControlState implements Serializable {
|
||||||
boolean sprinting;
|
boolean sprinting;
|
||||||
boolean sneaking;
|
boolean sneaking;
|
||||||
|
|
||||||
boolean shooting;
|
boolean usingTool;
|
||||||
boolean reloading;
|
boolean reloading;
|
||||||
|
|
||||||
|
boolean selectingPreviousTool;
|
||||||
|
boolean selectingNextTool;
|
||||||
|
|
||||||
Vec2 mouseLocation;
|
Vec2 mouseLocation;
|
||||||
|
|
||||||
public boolean isMovingLeft() {
|
public boolean isMovingLeft() {
|
||||||
|
@ -67,12 +74,12 @@ public class PlayerControlState implements Serializable {
|
||||||
this.sneaking = sneaking;
|
this.sneaking = sneaking;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isShooting() {
|
public boolean isUsingTool() {
|
||||||
return shooting;
|
return usingTool;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setShooting(boolean shooting) {
|
public void setUsingTool(boolean usingTool) {
|
||||||
this.shooting = shooting;
|
this.usingTool = usingTool;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isReloading() {
|
public boolean isReloading() {
|
||||||
|
@ -83,6 +90,22 @@ public class PlayerControlState implements Serializable {
|
||||||
this.reloading = reloading;
|
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() {
|
public Vec2 getMouseLocation() {
|
||||||
return mouseLocation;
|
return mouseLocation;
|
||||||
}
|
}
|
||||||
|
@ -98,10 +121,12 @@ public class PlayerControlState implements Serializable {
|
||||||
if (this.movingRight) flags |= 2;
|
if (this.movingRight) flags |= 2;
|
||||||
if (this.movingForward) flags |= 4;
|
if (this.movingForward) flags |= 4;
|
||||||
if (this.movingBackward) flags |= 8;
|
if (this.movingBackward) flags |= 8;
|
||||||
if (this.shooting) flags |= 16;
|
if (this.usingTool) flags |= 16;
|
||||||
if (this.reloading) flags |= 32;
|
if (this.reloading) flags |= 32;
|
||||||
if (this.sprinting) flags |= 64;
|
if (this.sprinting) flags |= 64;
|
||||||
if (this.sneaking) flags |= 128;
|
if (this.sneaking) flags |= 128;
|
||||||
|
if (this.selectingPreviousTool) flags |= 256;
|
||||||
|
if (this.selectingNextTool) flags |= 512;
|
||||||
buffer.putInt(flags);
|
buffer.putInt(flags);
|
||||||
buffer.putFloat(this.mouseLocation.x());
|
buffer.putFloat(this.mouseLocation.x());
|
||||||
buffer.putFloat(this.mouseLocation.y());
|
buffer.putFloat(this.mouseLocation.y());
|
||||||
|
@ -116,10 +141,12 @@ public class PlayerControlState implements Serializable {
|
||||||
s.movingRight = (flags & 2) > 0;
|
s.movingRight = (flags & 2) > 0;
|
||||||
s.movingForward = (flags & 4) > 0;
|
s.movingForward = (flags & 4) > 0;
|
||||||
s.movingBackward = (flags & 8) > 0;
|
s.movingBackward = (flags & 8) > 0;
|
||||||
s.shooting = (flags & 16) > 0;
|
s.usingTool = (flags & 16) > 0;
|
||||||
s.reloading = (flags & 32) > 0;
|
s.reloading = (flags & 32) > 0;
|
||||||
s.sprinting = (flags & 64) > 0;
|
s.sprinting = (flags & 64) > 0;
|
||||||
s.sneaking = (flags & 128) > 0;
|
s.sneaking = (flags & 128) > 0;
|
||||||
|
s.selectingPreviousTool = (flags & 256) > 0;
|
||||||
|
s.selectingNextTool = (flags & 512) > 0;
|
||||||
s.mouseLocation = new Vec2(buffer.getFloat(), buffer.getFloat());
|
s.mouseLocation = new Vec2(buffer.getFloat(), buffer.getFloat());
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ public class Team implements Serializable {
|
||||||
|
|
||||||
private final byte id;
|
private final byte id;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final java.awt.Color color;
|
private final Color color;
|
||||||
private final Vec2 spawnPoint;
|
private final Vec2 spawnPoint;
|
||||||
private final Vec2 supplyPoint;
|
private final Vec2 supplyPoint;
|
||||||
private final Vec2 orientation;
|
private final Vec2 orientation;
|
||||||
|
|
|
@ -43,6 +43,13 @@ public class World implements Serializable {
|
||||||
return gunTypes;
|
return gunTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GunType getGunTypeById(byte id) {
|
||||||
|
for (var t : this.gunTypes.values()) {
|
||||||
|
if (t.id() == id) return t;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<Integer, Player> getPlayers() {
|
public Map<Integer, Player> getPlayers() {
|
||||||
return this.players;
|
return this.players;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,16 +5,17 @@ package nl.andrewlalis.aos_core.model.tools;
|
||||||
* world, if there are some grenades available.
|
* world, if there are some grenades available.
|
||||||
*/
|
*/
|
||||||
public class Grenade implements Tool {
|
public class Grenade implements Tool {
|
||||||
private final int maxGrenades = 3;
|
private final int maxGrenades;
|
||||||
|
|
||||||
private int grenades;
|
private int grenades;
|
||||||
|
|
||||||
public Grenade(int grenades) {
|
public Grenade(int grenades, int maxGrenades) {
|
||||||
this.grenades = grenades;
|
this.grenades = grenades;
|
||||||
|
this.maxGrenades = maxGrenades;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Grenade() {
|
public Grenade() {
|
||||||
this.grenades = maxGrenades;
|
this(3, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getGrenadesRemaining() {
|
public int getGrenadesRemaining() {
|
||||||
|
@ -25,6 +26,14 @@ public class Grenade implements Tool {
|
||||||
return maxGrenades;
|
return maxGrenades;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The name of the tool, as it should be shown to the players.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Grenade";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void use() {
|
public void use() {
|
||||||
this.grenades--;
|
this.grenades--;
|
||||||
|
|
|
@ -19,16 +19,17 @@ public class Gun implements Tool {
|
||||||
private transient long reloadingStartedAt;
|
private transient long reloadingStartedAt;
|
||||||
private boolean reloading;
|
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.type = type;
|
||||||
this.currentClipBulletCount = currentClipBulletCount;
|
this.currentClipBulletCount = currentClipBulletCount;
|
||||||
this.clipCount = clipCount;
|
this.clipCount = clipCount;
|
||||||
|
this.reloading = reloading;
|
||||||
|
|
||||||
this.lastShot = System.currentTimeMillis();
|
this.lastShot = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Gun(GunType type) {
|
public Gun(GunType type) {
|
||||||
this(type, 0, type.maxClipCount());
|
this(type, 0, type.maxClipCount(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GunType getType() {
|
public GunType getType() {
|
||||||
|
@ -76,6 +77,14 @@ public class Gun implements Tool {
|
||||||
this.reloading = false;
|
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
|
@Override
|
||||||
public void use() {
|
public void use() {
|
||||||
this.lastShot = System.currentTimeMillis();
|
this.lastShot = System.currentTimeMillis();
|
||||||
|
@ -91,6 +100,15 @@ public class Gun implements Tool {
|
||||||
public boolean isUsable() {
|
public boolean isUsable() {
|
||||||
return !this.reloading &&
|
return !this.reloading &&
|
||||||
this.currentClipBulletCount > 0 &&
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
package nl.andrewlalis.aos_core.model.tools;
|
package nl.andrewlalis.aos_core.model.tools;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about a particular type of gun.
|
* Information about a particular type of gun.
|
||||||
*/
|
*/
|
||||||
public record GunType(
|
public record GunType (
|
||||||
|
byte id,
|
||||||
String name,
|
String name,
|
||||||
GunCategory category,
|
GunCategory category,
|
||||||
String color,
|
String color,
|
||||||
|
@ -16,4 +19,4 @@ public record GunType(
|
||||||
float bulletSpeed,
|
float bulletSpeed,
|
||||||
float baseDamage,
|
float baseDamage,
|
||||||
float recoil
|
float recoil
|
||||||
) {}
|
) implements Serializable {}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,11 @@ import java.io.Serializable;
|
||||||
* Represents some sort of usable tool item that players can equip and use.
|
* Represents some sort of usable tool item that players can equip and use.
|
||||||
*/
|
*/
|
||||||
public interface Tool extends Serializable {
|
public interface Tool extends Serializable {
|
||||||
|
/**
|
||||||
|
* @return The name of the tool, as it should be shown to the players.
|
||||||
|
*/
|
||||||
|
String getName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses the tool.
|
* Uses the tool.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -3,9 +3,11 @@ package nl.andrewlalis.aos_core.net.data;
|
||||||
import nl.andrewlalis.aos_core.model.Player;
|
import nl.andrewlalis.aos_core.model.Player;
|
||||||
import nl.andrewlalis.aos_core.model.tools.Grenade;
|
import nl.andrewlalis.aos_core.model.tools.Grenade;
|
||||||
import nl.andrewlalis.aos_core.model.tools.Gun;
|
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.model.tools.Tool;
|
||||||
import nl.andrewlalis.aos_core.net.data.tool.GrenadeData;
|
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.GunData;
|
||||||
|
import nl.andrewlalis.aos_core.net.data.tool.KnifeData;
|
||||||
import nl.andrewlalis.aos_core.net.data.tool.ToolData;
|
import nl.andrewlalis.aos_core.net.data.tool.ToolData;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
@ -14,28 +16,33 @@ import java.util.List;
|
||||||
|
|
||||||
public class PlayerDetailUpdate {
|
public class PlayerDetailUpdate {
|
||||||
private final float health;
|
private final float health;
|
||||||
|
private final List<ToolData> tools;
|
||||||
private List<ToolData> tools;
|
private final int selectedToolIndex;
|
||||||
private int selectedToolIndex;
|
|
||||||
|
|
||||||
public PlayerDetailUpdate(Player player) {
|
public PlayerDetailUpdate(Player player) {
|
||||||
this.health = player.getHealth();
|
this.health = player.getHealth();
|
||||||
this.tools = new ArrayList<>(player.getTools().size());
|
this.tools = new ArrayList<>(player.getTools().size());
|
||||||
|
int toolIndex = 0;
|
||||||
for (int i = 0; i < player.getTools().size(); i++) {
|
for (int i = 0; i < player.getTools().size(); i++) {
|
||||||
var t = player.getTools().get(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));
|
this.tools.add(new GunData(g));
|
||||||
} else if (t instanceof Grenade g) {
|
} else if (t instanceof Grenade g) {
|
||||||
this.tools.add(new GrenadeData(g));
|
this.tools.add(new GrenadeData(g));
|
||||||
}
|
}
|
||||||
if (t.equals(player.getSelectedTool())) {
|
if (t.equals(player.getSelectedTool())) {
|
||||||
selectedToolIndex = i;
|
toolIndex = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.selectedToolIndex = toolIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PlayerDetailUpdate(float health, List<ToolData> tools, int selectedToolIndex) {
|
private PlayerDetailUpdate(float health, List<ToolData> tools, int selectedToolIndex) {
|
||||||
this.health = health;
|
this.health = health;
|
||||||
|
this.tools = tools;
|
||||||
|
this.selectedToolIndex = selectedToolIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getHealth() {
|
public float getHealth() {
|
||||||
|
@ -46,10 +53,14 @@ public class PlayerDetailUpdate {
|
||||||
return tools;
|
return tools;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getSelectedToolIndex() {
|
||||||
|
return this.selectedToolIndex;
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] toBytes() {
|
public byte[] toBytes() {
|
||||||
int size = Float.BYTES + 2 * Integer.BYTES;
|
int size = Float.BYTES + 2 * Integer.BYTES;
|
||||||
for (var td : this.tools) {
|
for (var td : this.tools) {
|
||||||
size += td.getByteSize();
|
size += 1 + td.getByteSize();
|
||||||
}
|
}
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(size);
|
ByteBuffer buffer = ByteBuffer.allocate(size);
|
||||||
buffer.putFloat(this.health);
|
buffer.putFloat(this.health);
|
||||||
|
|
|
@ -4,21 +4,22 @@ import nl.andrewlalis.aos_core.geom.Vec2;
|
||||||
import nl.andrewlalis.aos_core.model.Player;
|
import nl.andrewlalis.aos_core.model.Player;
|
||||||
import nl.andrewlalis.aos_core.model.tools.Grenade;
|
import nl.andrewlalis.aos_core.model.tools.Grenade;
|
||||||
import nl.andrewlalis.aos_core.model.tools.Gun;
|
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.GrenadeData;
|
||||||
import nl.andrewlalis.aos_core.net.data.tool.GunData;
|
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 nl.andrewlalis.aos_core.net.data.tool.ToolData;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data that's sent to all clients about a player, and contains only the
|
* The data that's sent to all clients about a player, and contains only the
|
||||||
* information needed to render the player on the screen.
|
* information needed to render the player on the screen.
|
||||||
*/
|
*/
|
||||||
public class PlayerUpdate {
|
public class PlayerUpdate {
|
||||||
public static final int BYTES = Integer.BYTES + 6 * Float.BYTES + 1;
|
|
||||||
|
|
||||||
private final int id;
|
private final int id;
|
||||||
private final Vec2 position;
|
private final Vec2 position;
|
||||||
private final Vec2 orientation;
|
private final Vec2 orientation;
|
||||||
|
@ -30,7 +31,9 @@ public class PlayerUpdate {
|
||||||
this.position = player.getPosition();
|
this.position = player.getPosition();
|
||||||
this.orientation = player.getOrientation();
|
this.orientation = player.getOrientation();
|
||||||
this.velocity = player.getVelocity();
|
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);
|
this.selectedTool = new GunData(gun);
|
||||||
} else if (player.getSelectedTool() instanceof Grenade grenade) {
|
} else if (player.getSelectedTool() instanceof Grenade grenade) {
|
||||||
this.selectedTool = new GrenadeData(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.id = id;
|
||||||
this.position = position;
|
this.position = position;
|
||||||
this.orientation = orientation;
|
this.orientation = orientation;
|
||||||
this.velocity = velocity;
|
this.velocity = velocity;
|
||||||
this.selectedTool = null;
|
this.selectedTool = selectedTool;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getId() {
|
public int getId() {
|
||||||
|
@ -63,6 +66,10 @@ public class PlayerUpdate {
|
||||||
return velocity;
|
return velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ToolData getSelectedTool() {
|
||||||
|
return selectedTool;
|
||||||
|
}
|
||||||
|
|
||||||
public void write(DataOutputStream out) throws IOException {
|
public void write(DataOutputStream out) throws IOException {
|
||||||
out.writeInt(this.id);
|
out.writeInt(this.id);
|
||||||
out.writeFloat(this.position.x());
|
out.writeFloat(this.position.x());
|
||||||
|
@ -71,6 +78,10 @@ public class PlayerUpdate {
|
||||||
out.writeFloat(this.orientation.y());
|
out.writeFloat(this.orientation.y());
|
||||||
out.writeFloat(this.velocity.x());
|
out.writeFloat(this.velocity.x());
|
||||||
out.writeFloat(this.velocity.y());
|
out.writeFloat(this.velocity.y());
|
||||||
|
out.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 {
|
public static PlayerUpdate read(DataInputStream in) throws IOException {
|
||||||
|
@ -78,6 +89,9 @@ public class PlayerUpdate {
|
||||||
Vec2 position = Vec2.read(in);
|
Vec2 position = Vec2.read(in);
|
||||||
Vec2 orientation = Vec2.read(in);
|
Vec2 orientation = Vec2.read(in);
|
||||||
Vec2 velocity = 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,12 +75,7 @@ public class WorldUpdate {
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] toBytes() throws IOException {
|
public byte[] toBytes() throws IOException {
|
||||||
int size = 3 * Integer.BYTES + // List size integers.
|
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
|
||||||
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);
|
|
||||||
DataOutputStream dataOut = new DataOutputStream(out);
|
DataOutputStream dataOut = new DataOutputStream(out);
|
||||||
dataOut.writeInt(this.playerUpdates.size());
|
dataOut.writeInt(this.playerUpdates.size());
|
||||||
for (var u : this.playerUpdates) {
|
for (var u : this.playerUpdates) {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package nl.andrewlalis.aos_core.net.data.tool;
|
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.Grenade;
|
||||||
|
import nl.andrewlalis.aos_core.model.tools.Tool;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
@ -18,6 +20,14 @@ public class GrenadeData extends ToolData {
|
||||||
this.maxGrenades = grenade.getMaxGrenades();
|
this.maxGrenades = grenade.getMaxGrenades();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getGrenades() {
|
||||||
|
return grenades;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxGrenades() {
|
||||||
|
return maxGrenades;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getByteSize() {
|
public int getByteSize() {
|
||||||
return 2 * Integer.BYTES;
|
return 2 * Integer.BYTES;
|
||||||
|
@ -34,4 +44,9 @@ public class GrenadeData extends ToolData {
|
||||||
this.grenades = buffer.getInt();
|
this.grenades = buffer.getInt();
|
||||||
this.maxGrenades = buffer.getInt();
|
this.maxGrenades = buffer.getInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Tool toTool(World world) {
|
||||||
|
return new Grenade(this.grenades, this.maxGrenades);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
package nl.andrewlalis.aos_core.net.data.tool;
|
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.Gun;
|
||||||
|
import nl.andrewlalis.aos_core.model.tools.Tool;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class GunData extends ToolData {
|
public class GunData extends ToolData {
|
||||||
|
private byte typeId;
|
||||||
private boolean reloading;
|
private boolean reloading;
|
||||||
private int clipCount;
|
private int clipCount;
|
||||||
private int currentClipBulletCount;
|
private int currentClipBulletCount;
|
||||||
|
@ -18,6 +21,7 @@ public class GunData extends ToolData {
|
||||||
|
|
||||||
public GunData(Gun gun) {
|
public GunData(Gun gun) {
|
||||||
this();
|
this();
|
||||||
|
this.typeId = gun.getType().id();
|
||||||
this.reloading = gun.isReloading();
|
this.reloading = gun.isReloading();
|
||||||
this.clipCount = gun.getClipCount();
|
this.clipCount = gun.getClipCount();
|
||||||
this.currentClipBulletCount = gun.getCurrentClipBulletCount();
|
this.currentClipBulletCount = gun.getCurrentClipBulletCount();
|
||||||
|
@ -26,6 +30,10 @@ public class GunData extends ToolData {
|
||||||
this.maxClipCount = gun.getType().maxClipCount();
|
this.maxClipCount = gun.getType().maxClipCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte getTypeId() {
|
||||||
|
return typeId;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isReloading() {
|
public boolean isReloading() {
|
||||||
return reloading;
|
return reloading;
|
||||||
}
|
}
|
||||||
|
@ -52,11 +60,12 @@ public class GunData extends ToolData {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getByteSize() {
|
public int getByteSize() {
|
||||||
return 1 + 5 * Integer.BYTES;
|
return 2 * Byte.BYTES + 5 * Integer.BYTES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void putData(ByteBuffer buffer) {
|
protected void putData(ByteBuffer buffer) {
|
||||||
|
buffer.put(this.getTypeId());
|
||||||
buffer.put((byte) (this.reloading ? 1 : 0));
|
buffer.put((byte) (this.reloading ? 1 : 0));
|
||||||
buffer.putInt(this.clipCount);
|
buffer.putInt(this.clipCount);
|
||||||
buffer.putInt(this.currentClipBulletCount);
|
buffer.putInt(this.currentClipBulletCount);
|
||||||
|
@ -67,6 +76,7 @@ public class GunData extends ToolData {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void getData(ByteBuffer buffer) {
|
protected void getData(ByteBuffer buffer) {
|
||||||
|
this.typeId = buffer.get();
|
||||||
this.reloading = buffer.get() == 1;
|
this.reloading = buffer.get() == 1;
|
||||||
this.clipCount = buffer.getInt();
|
this.clipCount = buffer.getInt();
|
||||||
this.currentClipBulletCount = buffer.getInt();
|
this.currentClipBulletCount = buffer.getInt();
|
||||||
|
@ -74,4 +84,9 @@ public class GunData extends ToolData {
|
||||||
this.clipSize = buffer.getInt();
|
this.clipSize = buffer.getInt();
|
||||||
this.maxClipCount = 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,8 @@
|
||||||
package nl.andrewlalis.aos_core.net.data.tool;
|
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.nio.ByteBuffer;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -9,6 +12,7 @@ public abstract class ToolData {
|
||||||
static {
|
static {
|
||||||
dataMapping.put((byte) 0, GunData.class);
|
dataMapping.put((byte) 0, GunData.class);
|
||||||
dataMapping.put((byte) 1, GrenadeData.class);
|
dataMapping.put((byte) 1, GrenadeData.class);
|
||||||
|
dataMapping.put((byte) 2, KnifeData.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final byte toolType;
|
private final byte toolType;
|
||||||
|
@ -52,4 +56,11 @@ public abstract class ToolData {
|
||||||
* @param buffer The byte buffer to read data from.
|
* @param buffer The byte buffer to read data from.
|
||||||
*/
|
*/
|
||||||
protected abstract void getData(ByteBuffer buffer);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
-
|
2
pom.xml
2
pom.xml
|
@ -7,7 +7,7 @@
|
||||||
<groupId>nl.andrewlalis</groupId>
|
<groupId>nl.andrewlalis</groupId>
|
||||||
<artifactId>ace-of-shades</artifactId>
|
<artifactId>ace-of-shades</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<version>0.5.0</version>
|
<version>0.6.0</version>
|
||||||
<modules>
|
<modules>
|
||||||
<module>server</module>
|
<module>server</module>
|
||||||
<module>client</module>
|
<module>client</module>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>ace-of-shades</artifactId>
|
<artifactId>ace-of-shades</artifactId>
|
||||||
<groupId>nl.andrewlalis</groupId>
|
<groupId>nl.andrewlalis</groupId>
|
||||||
<version>0.5.0</version>
|
<version>0.6.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>ace-of-shades</artifactId>
|
<artifactId>ace-of-shades</artifactId>
|
||||||
<groupId>nl.andrewlalis</groupId>
|
<groupId>nl.andrewlalis</groupId>
|
||||||
<version>0.5.0</version>
|
<version>0.6.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
package nl.andrewlalis.aos_server;
|
package nl.andrewlalis.aos_server;
|
||||||
|
|
||||||
import nl.andrewlalis.aos_core.geom.Vec2;
|
import nl.andrewlalis.aos_core.geom.Vec2;
|
||||||
import nl.andrewlalis.aos_core.model.*;
|
import nl.andrewlalis.aos_core.model.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.GunCategory;
|
||||||
import nl.andrewlalis.aos_core.model.tools.GunType;
|
import nl.andrewlalis.aos_core.model.tools.GunType;
|
||||||
import nl.andrewlalis.aos_core.net.Message;
|
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.Type;
|
||||||
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
|
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
|
||||||
import nl.andrewlalis.aos_core.net.data.DataTypes;
|
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.PlayerDetailUpdate;
|
||||||
import nl.andrewlalis.aos_core.net.data.WorldUpdate;
|
import nl.andrewlalis.aos_core.net.data.WorldUpdate;
|
||||||
import nl.andrewlalis.aos_core.util.ByteUtils;
|
import nl.andrewlalis.aos_core.util.ByteUtils;
|
||||||
|
@ -59,8 +65,10 @@ public class Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initWorld() {
|
private void initWorld() {
|
||||||
|
byte gunTypeId = 0;
|
||||||
for (var gs : this.settings.getGunSettings()) {
|
for (var gs : this.settings.getGunSettings()) {
|
||||||
this.world.getGunTypes().put(gs.getName(), new GunType(
|
this.world.getGunTypes().put(gs.getName(), new GunType(
|
||||||
|
gunTypeId++,
|
||||||
gs.getName(),
|
gs.getName(),
|
||||||
GunCategory.valueOf(gs.getCategory().toUpperCase()),
|
GunCategory.valueOf(gs.getCategory().toUpperCase()),
|
||||||
gs.getColor(),
|
gs.getColor(),
|
||||||
|
@ -136,7 +144,9 @@ public class Server {
|
||||||
team = t;
|
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);
|
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));
|
||||||
|
@ -204,7 +214,6 @@ public class Server {
|
||||||
for (Team t : this.world.getTeams().values()) {
|
for (Team t : this.world.getTeams().values()) {
|
||||||
t.resetScore();
|
t.resetScore();
|
||||||
for (Player p : t.getPlayers()) {
|
for (Player p : t.getPlayers()) {
|
||||||
p.resetStats();
|
|
||||||
p.respawn(settings.getPlayerSettings().getMaxHealth());
|
p.respawn(settings.getPlayerSettings().getMaxHealth());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package nl.andrewlalis.aos_server;
|
||||||
|
|
||||||
import nl.andrewlalis.aos_core.geom.Vec2;
|
import nl.andrewlalis.aos_core.geom.Vec2;
|
||||||
import nl.andrewlalis.aos_core.model.*;
|
import nl.andrewlalis.aos_core.model.*;
|
||||||
|
import nl.andrewlalis.aos_core.model.tools.Gun;
|
||||||
import nl.andrewlalis.aos_core.model.tools.GunCategory;
|
import nl.andrewlalis.aos_core.model.tools.GunCategory;
|
||||||
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
|
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
|
||||||
import nl.andrewlalis.aos_core.net.data.SoundData;
|
import nl.andrewlalis.aos_core.net.data.SoundData;
|
||||||
|
@ -71,7 +72,7 @@ public class WorldUpdater extends Thread {
|
||||||
private void updatePlayers(float t) {
|
private void updatePlayers(float t) {
|
||||||
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.updatePlayerInteraction(p);
|
||||||
p.setHealth(Math.min(p.getHealth() + server.getSettings().getPlayerSettings().getHealthRegenRate() * t, server.getSettings().getPlayerSettings().getMaxHealth()));
|
p.setHealth(Math.min(p.getHealth() + server.getSettings().getPlayerSettings().getHealthRegenRate() * t, server.getSettings().getPlayerSettings().getMaxHealth()));
|
||||||
this.worldUpdate.addPlayer(p);
|
this.worldUpdate.addPlayer(p);
|
||||||
}
|
}
|
||||||
|
@ -183,31 +184,38 @@ public class WorldUpdater extends Thread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePlayerShooting(Player p) {
|
private void updatePlayerInteraction(Player p) {
|
||||||
if (p.canUseGun()) {
|
if ((p.getState().isSelectingNextTool() ^ p.getState().isSelectingPreviousTool()) && p.canChangeSelectedTool()) {
|
||||||
for (int i = 0; i < p.getGun().getType().bulletsPerRound(); i++) {
|
if (p.getState().isSelectingNextTool()) p.selectNextTool();
|
||||||
Bullet b = new Bullet(p, server.getSettings().getPlayerSettings().getSneakAccuracyModifier(), server.getSettings().getPlayerSettings().getSprintAccuracyModifier());
|
if (p.getState().isSelectingPreviousTool()) p.selectPreviousTool();
|
||||||
this.world.getBullets().add(b);
|
return; // Don't immediately do any action with the newly-selected tool.
|
||||||
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())));
|
|
||||||
}
|
}
|
||||||
if (p.getState().isReloading() && !p.isReloading() && p.getGun().canReload()) {
|
if (p.getSelectedTool() instanceof Gun gun) {
|
||||||
p.startReloading();
|
if (p.canUseGun()) {
|
||||||
}
|
for (int i = 0; i < gun.getType().bulletsPerRound(); i++) {
|
||||||
if (p.isReloading() && p.isReloadingComplete()) {
|
Bullet b = new Bullet(p, gun, server.getSettings().getPlayerSettings().getSneakAccuracyModifier(), server.getSettings().getPlayerSettings().getSprintAccuracyModifier());
|
||||||
p.finishReloading();
|
this.world.getBullets().add(b);
|
||||||
this.worldUpdate.addSound(new SoundData(p.getPosition(), 1.0f, SoundType.RELOAD));
|
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());
|
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 SoundData(p.getPosition(), 1.0f, SoundType.DEATH));
|
this.worldUpdate.addSound(new SoundData(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());
|
this.worldUpdate.addTeam(shooter.getTeam());
|
||||||
}
|
}
|
||||||
p.incrementDeathCount();
|
|
||||||
p.respawn(server.getSettings().getPlayerSettings().getMaxHealth());
|
p.respawn(server.getSettings().getPlayerSettings().getMaxHealth());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,6 @@ import nl.andrewlalis.aos_core.model.tools.GunType;
|
||||||
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
|
import nl.andrewlalis.aos_core.net.chat.SystemChatMessage;
|
||||||
import nl.andrewlalis.aos_server.ClientHandler;
|
import nl.andrewlalis.aos_server.ClientHandler;
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
public class GunCommand implements ChatCommand {
|
public class GunCommand implements ChatCommand {
|
||||||
@Override
|
@Override
|
||||||
public void execute(ClientHandler handler, Player player, String[] args) {
|
public void execute(ClientHandler handler, Player player, String[] args) {
|
||||||
|
@ -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."));
|
handler.send(new SystemChatMessage(SystemChatMessage.Level.WARNING, "Unknown gun name. Use /guns to see available guns."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
player.setGun(new Gun(gunType));
|
boolean gunSet = false;
|
||||||
handler.send(new SystemChatMessage(SystemChatMessage.Level.INFO, "Changed gun to " + player.getGun().getType().name() + "."));
|
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() + "."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,8 @@ import nl.andrewlalis.aos_server.ClientHandler;
|
||||||
public class KillDeathRatioCommand implements ChatCommand {
|
public class KillDeathRatioCommand implements ChatCommand {
|
||||||
@Override
|
@Override
|
||||||
public void execute(ClientHandler handler, Player player, String[] args) {
|
public void execute(ClientHandler handler, Player player, String[] args) {
|
||||||
float ratio = player.getKillCount() / ((float) player.getDeathCount());
|
// 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.INFO, String.format("Your Kill/Death ratio is %.2f.", ratio)));
|
||||||
|
handler.send(new SystemChatMessage(SystemChatMessage.Level.WARNING, "K/D command not yet implemented."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue