Added ability to change teams, and removed teams from creative and spectator players.

This commit is contained in:
Andrew Lalis 2022-08-02 09:54:14 +02:00
parent 352faff005
commit 20295596fa
9 changed files with 142 additions and 39 deletions

View File

@ -156,6 +156,14 @@ public class Client implements Runnable {
});
} else if (msg instanceof PlayerLeaveMessage leaveMessage) {
runLater(() -> players.remove(leaveMessage.id()));
} else if (msg instanceof PlayerTeamUpdateMessage teamUpdateMessage) {
runLater(() -> {
OtherPlayer op = players.get(teamUpdateMessage.playerId());
Team team = teamUpdateMessage.teamId() == -1 ? null : teams.get(teamUpdateMessage.teamId());
if (op != null) {
op.setTeam(team);
}
});
} else if (msg instanceof SoundMessage soundMessage) {
if (soundManager != null) {
soundManager.play(

View File

@ -26,29 +26,37 @@ public final class Net {
private static final Serializer serializer = new Serializer();
static {
serializer.registerType(1, ConnectRequestMessage.class);
serializer.registerType(2, ConnectAcceptMessage.class);
serializer.registerType(3, ConnectRejectMessage.class);
serializer.registerType(4, DatagramInit.class);
serializer.registerType(5, ChunkHashMessage.class);
serializer.registerType(6, ChunkDataMessage.class);
serializer.registerType(7, ChunkUpdateMessage.class);
serializer.registerType(8, ClientInputState.class);
serializer.registerType(9, ClientOrientationState.class);
serializer.registerType(10, PlayerUpdateMessage.class);
serializer.registerType(11, PlayerJoinMessage.class);
serializer.registerType(12, PlayerLeaveMessage.class);
int i = 1;
// Basic protocol messages.
serializer.registerType(i++, ConnectRequestMessage.class);
serializer.registerType(i++, ConnectAcceptMessage.class);
serializer.registerType(i++, ConnectRejectMessage.class);
serializer.registerType(i++, DatagramInit.class);
// World messages.
serializer.registerType(i++, ChunkHashMessage.class);
serializer.registerType(i++, ChunkDataMessage.class);
serializer.registerType(i++, ChunkUpdateMessage.class);
serializer.registerType(i++, ProjectileMessage.class);
// Player/client messages.
serializer.registerType(i++, ClientInputState.class);
serializer.registerType(i++, ClientOrientationState.class);
serializer.registerType(i++, ClientHealthMessage.class);
serializer.registerType(i++, PlayerUpdateMessage.class);
serializer.registerType(i++, PlayerJoinMessage.class);
serializer.registerType(i++, PlayerLeaveMessage.class);
serializer.registerType(i++, PlayerTeamUpdateMessage.class);
serializer.registerType(i++, BlockColorMessage.class);
serializer.registerType(i++, InventorySelectedStackMessage.class);
serializer.registerType(i++, ChatMessage.class);
serializer.registerType(i++, ChatWrittenMessage.class);
serializer.registerType(i++, ClientRecoilMessage.class);
// Separate serializers for client inventory messages.
serializer.registerTypeSerializer(13, new InventorySerializer());
serializer.registerTypeSerializer(14, new ItemStackSerializer());
serializer.registerType(15, InventorySelectedStackMessage.class);
serializer.registerType(16, SoundMessage.class);
serializer.registerType(17, ProjectileMessage.class);
serializer.registerType(18, ClientHealthMessage.class);
serializer.registerType(19, BlockColorMessage.class);
serializer.registerType(20, ChatMessage.class);
serializer.registerType(21, ChatWrittenMessage.class);
serializer.registerType(22, ClientRecoilMessage.class);
serializer.registerTypeSerializer(i++, new InventorySerializer());
serializer.registerTypeSerializer(i++, new ItemStackSerializer());
serializer.registerType(i++, SoundMessage.class);
}
public static ExtendedDataInputStream getInputStream(InputStream in) {

View File

@ -0,0 +1,13 @@
package nl.andrewl.aos_core.net.client;
import nl.andrewl.record_net.Message;
/**
* A message that's sent by the server to announce that a player has changed to
* a specified team. Both the player and team should already be recognized by
* all clients; otherwise they can ignore this.
*/
public record PlayerTeamUpdateMessage(
int playerId,
int teamId
) implements Message {}

View File

@ -30,21 +30,26 @@ public class PlayerManager {
}
public synchronized ServerPlayer register(ClientCommunicationHandler handler, String username) {
ServerPlayer player = new ServerPlayer(nextClientId++, username);
Team team = findBestTeamForNewPlayer();
ServerPlayer player = new ServerPlayer(nextClientId++, username, team, PlayerMode.NORMAL);
var inv = player.getInventory();
inv.getItemStacks().add(new GunItemStack(ItemTypes.RIFLE));
inv.getItemStacks().add(new GunItemStack(ItemTypes.AK_47));
inv.getItemStacks().add(new GunItemStack(ItemTypes.WINCHESTER));
inv.getItemStacks().add(new BlockItemStack(ItemTypes.BLOCK, 50, (byte) 1));
inv.setSelectedIndex(0);
System.out.printf("Registered player \"%s\" with id %d.%n", player.getUsername(), player.getId());
players.put(player.getId(), player);
clientHandlers.put(player.getId(), handler);
String joinMessage;
Team team = findBestTeamForNewPlayer();
if (team != null) {
player.setTeam(team);
System.out.printf("Player \"%s\" joined the \"%s\" team.%n", player.getUsername(), team.getName());
joinMessage = String.format("%s joined the %s team.", username, team.getName());
if (player.getTeam() != null) {
System.out.printf("Player \"%s\" joined the \"%s\" team.%n", player.getUsername(), player.getTeam().getName());
joinMessage = String.format("%s joined the %s team.", username, player.getTeam().getName());
} else {
joinMessage = username + " joined the game.";
}
player.setPosition(getBestSpawnPoint(player));
setMode(player, PlayerMode.NORMAL);
// Tell all other players that this one has joined.
broadcastTcpMessageToAllBut(new PlayerJoinMessage(
player.getId(), player.getUsername(), player.getTeam() == null ? -1 : player.getTeam().getId(),
@ -163,12 +168,9 @@ public class PlayerManager {
*/
public void playerKilled(ServerPlayer player, ServerPlayer killedBy) {
Vector3f deathPosition = new Vector3f(player.getPosition());
player.setPosition(getBestSpawnPoint(player));
player.setVelocity(new Vector3f(0));
player.incrementDeathCount();
resupply(player);
broadcastUdpMessage(player.getUpdateMessage(System.currentTimeMillis()));
broadcastUdpMessage(new SoundMessage("death", 1, deathPosition));
respawn(player);
String deathMessage;
if (killedBy != null) {
killedBy.incrementKillCount();
@ -198,8 +200,16 @@ public class PlayerManager {
handler.sendTcpMessage(ChatMessage.privateMessage("You've been resupplied at your team base."));
}
public void respawn(ServerPlayer player) {
player.setPosition(getBestSpawnPoint(player));
player.setVelocity(new Vector3f(0));
broadcastUdpMessage(player.getUpdateMessage(System.currentTimeMillis()));
resupply(player);
}
public void setMode(ServerPlayer player, PlayerMode mode) {
player.setMode(mode);
var handler = getHandler(player);
var inv = player.getInventory();
inv.clear();
if (mode == PlayerMode.NORMAL || mode == PlayerMode.CREATIVE) {
@ -208,7 +218,31 @@ public class PlayerManager {
inv.getItemStacks().add(new GunItemStack(ItemTypes.WINCHESTER));
inv.getItemStacks().add(new BlockItemStack(ItemTypes.BLOCK, 50, (byte) 1));
inv.setSelectedIndex(0);
handler.sendTcpMessage(new ClientInventoryMessage(inv));
broadcastUdpMessage(player.getUpdateMessage(System.currentTimeMillis()));
}
if (mode != PlayerMode.NORMAL) {
player.setTeam(null);
broadcastTcpMessage(new PlayerTeamUpdateMessage(player.getId(), -1));
} else {
player.setTeam(findBestTeamForNewPlayer());
broadcastTcpMessage(new PlayerTeamUpdateMessage(player.getId(), player.getTeam() == null ? -1 : player.getTeam().getId()));
}
handler.sendTcpMessage(ChatMessage.privateMessage("Your mode has been updated to " + mode.name() + "."));
}
public void setTeam(ServerPlayer player, Team team) {
if (Objects.equals(team, player.getTeam()) || player.getMode() != PlayerMode.NORMAL) return;
player.setTeam(team);
broadcastUdpMessage(new PlayerTeamUpdateMessage(player.getId(), team == null ? -1 : team.getId()));
respawn(player);
String chatMessage;
if (team != null) {
chatMessage = "%s has changed to the %s team.".formatted(player.getUsername(), team.getName());
} else {
chatMessage = "%s has changed to not be on a team.".formatted(player.getUsername());
}
broadcastTcpMessage(ChatMessage.announce(chatMessage));
}
public void handleUdpInit(DatagramInit init, DatagramPacket packet) {

View File

@ -33,6 +33,9 @@ public class TeamManager {
for (var team : teams.values()) {
if (team.getName().equals(ident)) return Optional.of(team);
}
for (var team : teams.values()) {// Try again ignoring case.
if (team.getName().equalsIgnoreCase(ident)) return Optional.of(team);
}
try {
int id = Integer.parseInt(ident);
for (var team : teams.values()) {

View File

@ -5,6 +5,7 @@ import nl.andrewl.aos2_server.Server;
import nl.andrewl.aos2_server.cli.ingame.commands.KillCommand;
import nl.andrewl.aos2_server.cli.ingame.commands.KillDeathRatioCommand;
import nl.andrewl.aos2_server.cli.ingame.commands.PlayerModeCommand;
import nl.andrewl.aos2_server.cli.ingame.commands.TeamsCommand;
import nl.andrewl.aos2_server.model.ServerPlayer;
import nl.andrewl.aos_core.net.client.ChatMessage;
@ -27,6 +28,7 @@ public class PlayerCommandHandler {
commands.put("kd", new KillDeathRatioCommand());
commands.put("kill", new KillCommand());
commands.put("mode", new PlayerModeCommand());
commands.put("teams", new TeamsCommand());
}
public void handle(String rawCommand, ServerPlayer player, ClientCommunicationHandler handler) {

View File

@ -6,7 +6,6 @@ import nl.andrewl.aos2_server.cli.ingame.PlayerCommand;
import nl.andrewl.aos2_server.model.ServerPlayer;
import nl.andrewl.aos_core.model.PlayerMode;
import nl.andrewl.aos_core.net.client.ChatMessage;
import nl.andrewl.aos_core.net.client.ClientInventoryMessage;
public class PlayerModeCommand implements PlayerCommand {
@Override
@ -19,9 +18,6 @@ public class PlayerModeCommand implements PlayerCommand {
try {
PlayerMode mode = PlayerMode.valueOf(modeText);
server.getPlayerManager().setMode(player, mode);
handler.sendTcpMessage(new ClientInventoryMessage(player.getInventory()));
server.getPlayerManager().broadcastUdpMessage(player.getUpdateMessage(System.currentTimeMillis()));
handler.sendTcpMessage(ChatMessage.privateMessage("Your mode has been updated to " + mode.name() + "."));
} catch (IllegalArgumentException e) {
handler.sendTcpMessage(ChatMessage.privateMessage("Invalid mode. Should be NORMAL, CREATIVE, or SPECTATOR."));
}

View File

@ -0,0 +1,37 @@
package nl.andrewl.aos2_server.cli.ingame.commands;
import nl.andrewl.aos2_server.ClientCommunicationHandler;
import nl.andrewl.aos2_server.Server;
import nl.andrewl.aos2_server.cli.ingame.PlayerCommand;
import nl.andrewl.aos2_server.model.ServerPlayer;
import nl.andrewl.aos_core.model.Team;
import nl.andrewl.aos_core.net.client.ChatMessage;
import java.util.stream.Collectors;
public class TeamsCommand implements PlayerCommand {
@Override
public void handle(String[] args, ServerPlayer player, ClientCommunicationHandler handler, Server server) {
if (args.length == 0) {
String teamsString = server.getTeamManager().getTeams().stream()
.map(Team::getName).collect(Collectors.joining(", "));
handler.sendTcpMessage(ChatMessage.privateMessage(teamsString));
} else {
String cmd = args[0].trim().toLowerCase();
if (cmd.equals("set")) {
if (args.length >= 2) {
String teamIdent = args[1].trim();
server.getTeamManager().findByIdOrName(teamIdent)
.ifPresentOrElse(
team -> server.getPlayerManager().setTeam(player, team),
() -> handler.sendTcpMessage(ChatMessage.privateMessage("Unknown team."))
);
} else {
handler.sendTcpMessage(ChatMessage.privateMessage("Missing required team identifier."));
}
} else {
handler.sendTcpMessage(ChatMessage.privateMessage("Unknown subcommand."));
}
}
}
}

View File

@ -2,6 +2,8 @@ package nl.andrewl.aos2_server.model;
import nl.andrewl.aos2_server.logic.PlayerActionManager;
import nl.andrewl.aos_core.model.Player;
import nl.andrewl.aos_core.model.PlayerMode;
import nl.andrewl.aos_core.model.Team;
import nl.andrewl.aos_core.model.item.Inventory;
import nl.andrewl.aos_core.net.client.PlayerUpdateMessage;
@ -24,8 +26,8 @@ public class ServerPlayer extends Player {
private int deathCount;
private int killCount;
public ServerPlayer(int id, String username) {
super(id, username);
public ServerPlayer(int id, String username, Team team, PlayerMode mode) {
super(id, username, team, mode);
this.inventory = new Inventory(new ArrayList<>(), 0);
this.health = 1f;
this.actionManager = new PlayerActionManager(this);