Switch from UUID to Player & add scoreboard for teams

Replaced UUID-based logic with Player objects across all game systems. Added team scorebaord sfor colors in tab and clarity for players as to who is in the laed
This commit is contained in:
Teriuihi 2025-02-15 03:53:35 +01:00
parent 6893e07619
commit 400032a94c
12 changed files with 88 additions and 31 deletions

View File

@ -58,7 +58,7 @@ public class ChangeTeam extends SubCommand {
}
private void changeTeam(CommandSender commandSender, Player player, Team team) {
Optional<Team> optionalOldTeam = gameManager.getTeam(player.getUniqueId());
Optional<Team> optionalOldTeam = gameManager.getTeam(player);
if (optionalOldTeam.isPresent()) {
moveBetweenTeams(commandSender, player, team, optionalOldTeam.get());
return;

View File

@ -76,7 +76,8 @@ public class CreateTeam extends SubCommand {
int highestId = gameManager.getMaxTeamId();
Team team = new Team(MiniMessage.miniMessage().deserialize(String.format("<color:%s>%s</color>", color, name)),
highestId + 1, player.getLocation(), player.getLocation(), player.getLocation(), teamColor, Material.RED_BANNER);
highestId + 1, player.getLocation(), player.getLocation(), player.getLocation(), teamColor,
Material.RED_BANNER, "§c");
return consumer.apply(team);
}

View File

@ -40,7 +40,7 @@ public class SelectClass extends SubCommand {
return 0;
}
GamePhase gamePhase = optionalGamePhase.get();
Optional<TeamPlayer> optionalTeamPlayer = gameManager.getTeamPlayer(player.getUniqueId());
Optional<TeamPlayer> optionalTeamPlayer = gameManager.getTeamPlayer(player);
if (optionalTeamPlayer.isEmpty()) {
commandSender.sendRichMessage("<red>You have to be in a CTF team to select a class.</red>");
return 0;

View File

@ -55,7 +55,7 @@ public class OnPlayerDeath implements Listener {
log.warn("Player {} died while the game wasn't running", player.getName());
return;
}
Optional<TeamPlayer> optionalTeamPlayer = gameManager.getTeamPlayer(player.getUniqueId());
Optional<TeamPlayer> optionalTeamPlayer = gameManager.getTeamPlayer(player);
if (optionalTeamPlayer.isEmpty()) {
return;
}

View File

@ -51,7 +51,7 @@ public class OnPlayerOnlineStatus implements Listener {
if (gamePhase.equals(GamePhase.ENDED)) {
return;
}
Optional<TeamPlayer> optionalTeamPlayer = gameManager.getTeamPlayer(player.getUniqueId());
Optional<TeamPlayer> optionalTeamPlayer = gameManager.getTeamPlayer(player);
TeamPlayer teamPlayer;
if (optionalTeamPlayer.isEmpty()) {
Optional<Team> min = gameManager.getTeams().stream().min(Comparator.comparingInt(team -> team.getPlayers().size()));
@ -59,7 +59,7 @@ public class OnPlayerOnlineStatus implements Listener {
log.error("No team found when attempting to add freshly joined player to a team");
return;
}
teamPlayer = min.get().addPlayer(player.getUniqueId());
teamPlayer = min.get().addPlayer(player);
} else {
teamPlayer = optionalTeamPlayer.get();
}

View File

@ -89,7 +89,7 @@ public class SnowballEvent implements Listener {
return;
}
Optional<TeamPlayer> teamPlayer = gameManager.getTeamPlayer(shooter.getUniqueId());
Optional<TeamPlayer> teamPlayer = gameManager.getTeamPlayer(shooter);
if (teamPlayer.isEmpty()) {
log.debug("The shooter that threw a snowball was not a team player");
return;
@ -127,13 +127,13 @@ public class SnowballEvent implements Listener {
return;
}
Optional<TeamPlayer> teamPlayerShooter = gameManager.getTeamPlayer(shooter.getUniqueId());
Optional<TeamPlayer> teamPlayerShooter = gameManager.getTeamPlayer(shooter);
if (teamPlayerShooter.isEmpty()) {
log.debug("The shooter that hit a player with a snowball was not a team player");
return;
}
Optional<TeamPlayer> teamPlayerHit = gameManager.getTeamPlayer(hitPlayer.getUniqueId());
Optional<TeamPlayer> teamPlayerHit = gameManager.getTeamPlayer(hitPlayer);
if (teamPlayerHit.isEmpty()) {
log.debug("The shooter that hit a player with a snowball was not a team player");
return;

View File

@ -52,6 +52,7 @@ public class Flag implements Runnable {
throw new IllegalStateException(String.format("Tried to spawn flag in world [%s] that doesn't exist", GameConfig.FLAG.world));
}
this.flagLocation = new Location(world, GameConfig.FLAG.x, GameConfig.FLAG.y, GameConfig.FLAG.z);
gameManager.getTeams().forEach(team -> team.setScore(0));
}
private BossBar createBossBar() {
@ -158,7 +159,7 @@ public class Flag implements Runnable {
miniMessage.deserialize("<red>kill <player> before they bring it to their base.</red>",
Placeholder.component("player", flagCarrier.displayName())));
Bukkit.getOnlinePlayers().forEach(player ->
gameManager.getTeam(player.getUniqueId()).ifPresent(team ->
gameManager.getTeam(player).ifPresent(team ->
player.showTitle(team.getId() == winningTeam.getId() ? capturingTeamTitle : huntingTeamTitle)));
}
@ -211,9 +212,10 @@ public class Flag implements Runnable {
spawnFlag(GameConfig.FLAG.MATERIAL);
wins.merge(winningTeam.getId(), 1, Integer::sum);
wins.forEach((id, score) -> gameManager.getTeam(id).ifPresent(team -> team.setScore(score)));
flagCarrier.getInventory().setItem(EquipmentSlot.HEAD, null);
gameManager.getTeamPlayer(flagCarrier.getUniqueId())
gameManager.getTeamPlayer(flagCarrier)
.ifPresent(teamPlayer -> teamPlayer.getGameClass().setArmor(flagCarrier, teamPlayer));
resetFlagCarrier();
@ -274,7 +276,7 @@ public class Flag implements Runnable {
*/
private boolean updateScoreBasedOnNearbyPlayers(Collection<Player> players) {
List<TeamPlayer> nearbyPlayers = players.stream()
.map(player -> gameManager.getTeamPlayer(player.getUniqueId()))
.map(gameManager::getTeamPlayer)
.filter(Optional::isPresent)
.map(Optional::get)
.toList();
@ -376,7 +378,7 @@ public class Flag implements Runnable {
}
resetFlagCarrier();
spawnFlag(GameConfig.FLAG.MATERIAL);
gameManager.getTeam(player.getUniqueId())
gameManager.getTeam(player)
.ifPresentOrElse(team -> Bukkit.broadcast(MiniMessage.miniMessage()
.deserialize("<red><team>'s flag carrier died! The flag has respawned",
Placeholder.component("team", team.getName()))),

View File

@ -37,7 +37,7 @@ public class FlagTryCaptureEvent implements Listener {
return;
}
Player player = event.getPlayer();
Optional<TeamPlayer> teamPlayer = winningTeam.getPlayer(player.getUniqueId());
Optional<TeamPlayer> teamPlayer = winningTeam.getPlayer(player);
if (teamPlayer.isEmpty()) {
return;
}

View File

@ -39,11 +39,11 @@ public class GameManager {
public void registerPlayer(Team team, Player player) {
unregisterPlayer(player);
teams.get(team.getId()).addPlayer(player.getUniqueId());
teams.get(team.getId()).addPlayer(player);
}
public void unregisterPlayer(Player player) {
teams.values().forEach(team -> team.removePlayer(player.getUniqueId()));
teams.values().forEach(team -> team.removePlayer(player));
}
public void registerTeam(Team team) {
@ -54,17 +54,17 @@ public class GameManager {
return teams.values();
}
public Optional<Team> getTeam(@NotNull UUID uuid) {
return getTeams().stream().filter(filterTeam -> filterTeam.getPlayer(uuid).isPresent()).findAny();
public Optional<Team> getTeam(@NotNull Player player) {
return getTeams().stream().filter(filterTeam -> filterTeam.getPlayer(player).isPresent()).findAny();
}
public Optional<Team> getTeam(int teamId) {
return getTeams().stream().filter(filterTeam -> filterTeam.getId() == teamId).findAny();
}
public Optional<TeamPlayer> getTeamPlayer(@NotNull UUID uuid) {
public Optional<TeamPlayer> getTeamPlayer(@NotNull Player player) {
return getTeams().stream()
.map(team -> team.getPlayer(uuid))
.map(team -> team.getPlayer(player))
.filter(Optional::isPresent)
.findFirst()
.orElseGet(Optional::empty);

View File

@ -59,10 +59,10 @@ public class ClassSelectionPhase implements GamePhaseExecutor {
Collections.shuffle(players);
players.stream()
.filter(player -> !player.hasPermission("ctf.bypass"))
.filter(player -> gameManager.getTeamPlayer(player.getUniqueId()).isEmpty())
.filter(player -> gameManager.getTeamPlayer(player).isEmpty())
.forEach(player -> {
Team team = teamCircularIterator.next();
team.addPlayer(player.getUniqueId());
team.addPlayer(player);
player.sendRichMessage("You joined <team>!", Placeholder.component("team", team.getName()));
});
} else {
@ -73,7 +73,7 @@ public class ClassSelectionPhase implements GamePhaseExecutor {
private void teleportPlayersToStartingZone() {
Bukkit.getOnlinePlayers().forEach(player -> {
Optional<TeamPlayer> teamPlayer = gameManager.getTeamPlayer(player.getUniqueId());
Optional<TeamPlayer> teamPlayer = gameManager.getTeamPlayer(player);
if (teamPlayer.isEmpty()) {
log.warn("{} is not a team player when teleporting to starting zone", player.getName());
return;

View File

@ -7,8 +7,16 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.scoreboard.*;
import org.jetbrains.annotations.NotNull;
import java.util.*;
@ -18,6 +26,8 @@ import java.util.*;
@AllArgsConstructor
public class Team {
@JsonIgnore
private final static Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
@JsonIgnore
private final HashMap<UUID, TeamPlayer> players = new HashMap<>();
@JsonProperty("name")
@ -47,15 +57,23 @@ public class Team {
@NotNull
@Getter
private Material flagMaterial;
@JsonProperty("legacyTeamColor")
@NotNull
@Getter
private String legacyTeamColor;
public TeamPlayer addPlayer(UUID uuid) {
public TeamPlayer addPlayer(Player player) {
removeFromScoreBoard(player);
UUID uuid = player.getUniqueId();
TeamPlayer teamPlayer = new TeamPlayer(uuid, this);
players.put(uuid, teamPlayer);
log.debug("Added player with uuid {} to team with id {}", uuid, id);
addToScoreboard(player);
log.debug("Added player {} to team with id {}", player.getName(), id);
return teamPlayer;
}
public Optional<TeamPlayer> getPlayer(@NotNull UUID uuid) {
public Optional<TeamPlayer> getPlayer(@NotNull Player player) {
UUID uuid = player.getUniqueId();
if (!players.containsKey(uuid))
return Optional.empty();
return Optional.of(players.get(uuid));
@ -65,13 +83,49 @@ public class Team {
return players.values();
}
public void removePlayer(@NotNull UUID uuid) {
TeamPlayer remove = players.remove(uuid);
public void removePlayer(@NotNull Player player) {
removeFromScoreBoard(player);
TeamPlayer remove = players.remove(player.getUniqueId());
if (remove != null) {
log.debug("Removed player with uuid {} from team with id {}", uuid, id);
log.debug("Removed player {} from team with id {}", player.getName(), id);
}
}
private void addToScoreboard(Player player) {
org.bukkit.scoreboard.Team team = scoreboard.getTeam("ctf_" + id);
if (team == null) {
team = scoreboard.registerNewTeam("ctf_" + id);
team.displayName(name);
NamedTextColor namedTextColor = NamedTextColor.nearestTo(TextColor.color(color.r(), color.g(), color.b()));
team.color(namedTextColor);
}
team.addPlayer(player);
player.setScoreboard(scoreboard);
}
private void removeFromScoreBoard(Player player) {
scoreboard.getTeams().stream()
.filter(team -> team.getName().startsWith("ctf_"))
.filter(team -> team.hasPlayer(player))
.forEach(team -> team.removePlayer(player));
}
public void setScore(int newScore) {
Objective objective = getOrCreateObjective();
Score score = objective.getScore(legacyTeamColor + PlainTextComponentSerializer.plainText().serialize(name));
score.setScore(newScore);
}
private Objective getOrCreateObjective() {
Objective objective = scoreboard.getObjective("teamScores");
if (objective == null) {
objective = scoreboard.registerNewObjective("teamScores", Criteria.DUMMY,
MiniMessage.miniMessage().deserialize("<gold>CTF score</gold>"));
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
}
return objective;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {

View File

@ -1,3 +1,3 @@
#Tue Feb 11 22:21:13 CET 2025
buildNumber=45
#Sat Feb 15 03:47:20 CET 2025
buildNumber=50
version=0.1