diff --git a/BedWars.iml b/BedWars.iml
index f570be0..b74e7bb 100644
--- a/BedWars.iml
+++ b/BedWars.iml
@@ -41,5 +41,6 @@
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index e266c31..7b6930a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -130,5 +130,13 @@
provided
+
+
+ club.frozed.tablist
+ FrozedTablist
+ 4.0-SNAPSHOT
+ compile
+
+
diff --git a/src/main/java/rip/tilly/bedwars/BedWars.java b/src/main/java/rip/tilly/bedwars/BedWars.java
index 5f52723..24ac1ac 100644
--- a/src/main/java/rip/tilly/bedwars/BedWars.java
+++ b/src/main/java/rip/tilly/bedwars/BedWars.java
@@ -1,5 +1,6 @@
package rip.tilly.bedwars;
+import club.frozed.tablist.FrozedTablist;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
@@ -9,8 +10,8 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import rip.tilly.bedwars.game.Game;
-import rip.tilly.bedwars.listeners.game.*;
import rip.tilly.bedwars.listeners.*;
+import rip.tilly.bedwars.listeners.game.*;
import rip.tilly.bedwars.managers.CommandManager;
import rip.tilly.bedwars.managers.GameManager;
import rip.tilly.bedwars.managers.PlayerDataManager;
@@ -23,10 +24,11 @@ import rip.tilly.bedwars.managers.mongo.MongoManager;
import rip.tilly.bedwars.managers.party.PartyManager;
import rip.tilly.bedwars.managers.queue.QueueManager;
import rip.tilly.bedwars.menusystem.PlayerMenuUtil;
+import rip.tilly.bedwars.providers.placeholderapi.PlaceholderAPIProvider;
import rip.tilly.bedwars.providers.scoreboard.ScoreboardProvider;
+import rip.tilly.bedwars.providers.tablist.TablistProvider;
import rip.tilly.bedwars.utils.CC;
-import rip.tilly.bedwars.utils.assemble.Assemble;
-import rip.tilly.bedwars.utils.assemble.AssembleStyle;
+import rip.tilly.bedwars.utils.aether.Aether;
import rip.tilly.bedwars.utils.config.file.Config;
import java.util.Arrays;
@@ -57,7 +59,7 @@ public final class BedWars extends JavaPlugin {
private PartyManager partyManager;
private QueueManager queueManager;
- private final HashMap playerMenuUtilMap = new HashMap();
+ private final HashMap playerMenuUtilMap = new HashMap<>();
@Override
public void onEnable() {
@@ -75,10 +77,18 @@ public final class BedWars extends JavaPlugin {
this.loadManagers();
this.loadListeners();
+ this.loadRunnables();
+ /*
Assemble assemble = new Assemble(this, new ScoreboardProvider());
assemble.setTicks(2);
assemble.setAssembleStyle(AssembleStyle.VIPER);
+ */
+
+ if (this.getServer().getPluginManager().getPlugin("PlaceholderAPI") != null) {
+ new PlaceholderAPIProvider(this).register();
+ Bukkit.getConsoleSender().sendMessage(CC.translate("&aPlaceholderAPI successfully registered!"));
+ }
for (World world : Bukkit.getWorlds()) {
for (Entity entity : world.getEntities()) {
@@ -132,12 +142,17 @@ public final class BedWars extends JavaPlugin {
private void loadListeners() {
Arrays.asList(
- new PlayerDataListener(), new RandomListeners(), new InteractListener(), new ButtonListener(), new MenuListener(),
- new GameStartListener(), new GameEndListener(), new WorldListener(), new MovementListener(),
- new PlayerKillListener()
+ new PlayerDataListener(), new RandomListeners(), new InteractListener(), new ButtonListener(),
+ new MenuListener(), new GameStartListener(), new GameEndListener(), new WorldListener(),
+ new MovementListener(), new PlayerKillListener(), new DamageListener()
).forEach(listener -> this.getServer().getPluginManager().registerEvents(listener, this));
}
+ private void loadRunnables() {
+ new Aether(this, new ScoreboardProvider());
+ new FrozedTablist(this, new TablistProvider(), 0, 20);
+ }
+
public PlayerMenuUtil getPlayerMenuUtil(Player player) {
PlayerMenuUtil playerMenuUtil;
diff --git a/src/main/java/rip/tilly/bedwars/listeners/game/DamageListener.java b/src/main/java/rip/tilly/bedwars/listeners/game/DamageListener.java
new file mode 100644
index 0000000..857fd5d
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/listeners/game/DamageListener.java
@@ -0,0 +1,126 @@
+package rip.tilly.bedwars.listeners.game;
+
+import org.bukkit.Location;
+import org.bukkit.entity.Arrow;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.Projectile;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDamageByEntityEvent;
+import org.bukkit.event.entity.EntityDamageEvent;
+import rip.tilly.bedwars.BedWars;
+import rip.tilly.bedwars.events.PlayerKillEvent;
+import rip.tilly.bedwars.game.Game;
+import rip.tilly.bedwars.game.GameState;
+import rip.tilly.bedwars.playerdata.PlayerData;
+import rip.tilly.bedwars.utils.CC;
+
+public class DamageListener implements Listener {
+
+ private final BedWars plugin = BedWars.getInstance();
+
+ @EventHandler
+ public void onEntityDamage(EntityDamageEvent event) {
+ if (!(event.getEntity() instanceof Player)) {
+ return;
+ }
+
+ Player player = (Player) event.getEntity();
+ PlayerData playerData = this.plugin.getPlayerDataManager().getPlayerData(player.getUniqueId());
+ EntityDamageEvent.DamageCause cause = event.getCause();
+ Game game = this.plugin.getGameManager().getGame(player.getUniqueId());
+ switch (playerData.getPlayerState()) {
+ case PLAYING:
+ if (game.getGameState() != GameState.FIGHTING) {
+ event.setCancelled(true);
+ }
+ break;
+ case RESPAWNING:
+ if (cause == EntityDamageEvent.DamageCause.VOID) {
+ Location gameLocation = playerData.getTeamId() == 1 ? game.getCopiedArena().getA().toBukkitLocation() : game.getCopiedArena().getB().toBukkitLocation();
+ player.teleport(gameLocation);
+ }
+ event.setCancelled(true);
+ break;
+ case SPECTATING:
+ if (cause == EntityDamageEvent.DamageCause.VOID) {
+ Game spectatingGame = this.plugin.getGameManager().getSpectatingGame(player.getUniqueId());
+ Location location = spectatingGame.getCopiedArena().getA().toBukkitLocation();
+ player.teleport(location);
+ }
+ event.setCancelled(true);
+ break;
+ default:
+ if (cause == EntityDamageEvent.DamageCause.VOID) {
+ Location spawnLocation = this.plugin.getSpawnManager().getSpawnLocation().toBukkitLocation();
+ player.teleport(spawnLocation);
+ }
+ event.setCancelled(true);
+ break;
+ }
+ }
+
+ @EventHandler
+ public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
+ if (!(event.getEntity() instanceof Player)) {
+ return;
+ }
+
+ Player player = (Player) event.getEntity();
+ Player damager;
+
+ if (event.getDamager() instanceof Player) {
+ damager = (Player) event.getDamager();
+ } else if (event.getDamager() instanceof Arrow && ((Projectile) event.getDamager()).getShooter() != ((Player) event.getEntity()).getPlayer()) {
+ damager = (Player) ((Projectile) event.getDamager()).getShooter();
+ } else {
+ return;
+ }
+
+ if (!player.canSee(damager) && damager.canSee(player)) {
+ event.setCancelled(true);
+ return;
+ }
+
+ PlayerData playerData = this.plugin.getPlayerDataManager().getPlayerData(player.getUniqueId());
+ PlayerData damagerData = this.plugin.getPlayerDataManager().getPlayerData(damager.getUniqueId());
+
+ Game game = this.plugin.getGameManager().getGame(player.getUniqueId());
+ if (game == null) {
+ event.setDamage(0);
+ return;
+ }
+
+ if (playerData.getPlayerTeam() == damagerData.getPlayerTeam()) {
+ event.setCancelled(true);
+ return;
+ }
+
+ playerData.setLastDamager(damager);
+ double health = player.getHealth() - event.getFinalDamage();
+ if (health < 0) {
+ this.plugin.getServer().getPluginManager().callEvent(new PlayerKillEvent(player, damager));
+ }
+
+ if (!(event.getDamager() instanceof Arrow)) {
+ return;
+ }
+
+ Arrow arrow = (Arrow) event.getDamager();
+ if (!(arrow.getShooter() instanceof Player)) {
+ return;
+ }
+
+ Player shooter = (Player) arrow.getShooter();
+ if (player.getName().equals(shooter.getName())) {
+ return;
+ }
+
+ if (health < 0) {
+ event.setCancelled(true);
+ this.plugin.getServer().getPluginManager().callEvent(new PlayerKillEvent(player, shooter));
+ } else {
+ shooter.sendMessage(CC.translate("&d" + player.getName() + " &eis now at &c" + health + "❤&e."));
+ }
+ }
+}
diff --git a/src/main/java/rip/tilly/bedwars/listeners/game/WorldListener.java b/src/main/java/rip/tilly/bedwars/listeners/game/WorldListener.java
index 738aaf9..2743f42 100644
--- a/src/main/java/rip/tilly/bedwars/listeners/game/WorldListener.java
+++ b/src/main/java/rip/tilly/bedwars/listeners/game/WorldListener.java
@@ -15,6 +15,8 @@ import rip.tilly.bedwars.game.GameTeam;
import rip.tilly.bedwars.playerdata.PlayerData;
import rip.tilly.bedwars.playerdata.PlayerState;
+import java.util.Objects;
+
public class WorldListener implements Listener {
private final BedWars plugin = BedWars.getInstance();
@@ -74,7 +76,8 @@ public class WorldListener implements Listener {
playerData.setGameBedsDestroyed(playerData.getGameBedsDestroyed() + 1);
playerData.setBedsDestroyed(playerData.getBedsDestroyed() + 1);
- block.getDrops().clear();
+ block.getDrops().removeIf(Objects::nonNull);
+
Location location = block.getLocation();
World world = location.getWorld();
world.playEffect(location, Effect.CRIT, 1, 400);
diff --git a/src/main/java/rip/tilly/bedwars/managers/GameManager.java b/src/main/java/rip/tilly/bedwars/managers/GameManager.java
index 8a04c13..4435ffc 100644
--- a/src/main/java/rip/tilly/bedwars/managers/GameManager.java
+++ b/src/main/java/rip/tilly/bedwars/managers/GameManager.java
@@ -113,6 +113,10 @@ public class GameManager {
}, 100L).getTaskId());
}
+ public Game getSpectatingGame(UUID uuid) {
+ return this.games.get(this.spectators.get(uuid));
+ }
+
public void removePlayerFromGame(Player player, PlayerData playerData, boolean spectatorDeath) {
Game game = this.games.get(playerData.getCurrentGameId());
Player killer = playerData.getLastDamager();
diff --git a/src/main/java/rip/tilly/bedwars/playerdata/PlayerData.java b/src/main/java/rip/tilly/bedwars/playerdata/PlayerData.java
index d017b21..003af61 100644
--- a/src/main/java/rip/tilly/bedwars/playerdata/PlayerData.java
+++ b/src/main/java/rip/tilly/bedwars/playerdata/PlayerData.java
@@ -52,7 +52,7 @@ public class PlayerData {
this.xp += xp;
- player.sendMessage(CC.translate("&b&l+" + ((int) (xp * 100)) + "&b&l% xp"));
+ player.sendMessage(CC.translate("&b&l+" + ((int) (xp * 100)) + "&b&l% XP"));
if (this.xp >= 1) {
this.level += 1;
diff --git a/src/main/java/rip/tilly/bedwars/providers/placeholderapi/PlaceholderAPIProvider.java b/src/main/java/rip/tilly/bedwars/providers/placeholderapi/PlaceholderAPIProvider.java
new file mode 100644
index 0000000..4f8a092
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/providers/placeholderapi/PlaceholderAPIProvider.java
@@ -0,0 +1,70 @@
+package rip.tilly.bedwars.providers.placeholderapi;
+
+import me.clip.placeholderapi.expansion.PlaceholderExpansion;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import rip.tilly.bedwars.BedWars;
+import rip.tilly.bedwars.playerdata.PlayerData;
+
+public class PlaceholderAPIProvider extends PlaceholderExpansion {
+
+ final private BedWars plugin;
+
+ public PlaceholderAPIProvider(BedWars plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public String getIdentifier() {
+ return this.plugin.getDescription().getName().toLowerCase();
+ }
+
+ @Override
+ public String getAuthor() {
+ return this.plugin.getDescription().getAuthors().get(0);
+ }
+
+ @Override
+ public String getVersion() {
+ return this.plugin.getDescription().getVersion();
+ }
+
+ @Override
+ public boolean persist() {
+ return true;
+ }
+
+ @Override
+ public String onPlaceholderRequest(Player player, String identifier) {
+ if (player == null) {
+ return ChatColor.RED + "No data saved!";
+ }
+
+ PlayerData playerData = this.plugin.getPlayerDataManager().getPlayerData(player.getUniqueId());
+ if (playerData == null) {
+ return ChatColor.RED + "No data saved!";
+ }
+
+ // %bedwars_kills% would show the players kills.
+ switch (identifier.toLowerCase()) {
+ case "kills":
+ return String.valueOf(playerData.getKills());
+ case "deaths":
+ return String.valueOf(playerData.getDeaths());
+ case "xp":
+ return String.valueOf(playerData.getXp());
+ case "level":
+ return String.valueOf(playerData.getLevel());
+ case "wins":
+ return String.valueOf(playerData.getWins());
+ case "losses":
+ return String.valueOf(playerData.getLosses());
+ case "gamesplayed":
+ return String.valueOf(playerData.getGamesPlayed());
+ case "bedsdestroyed":
+ return String.valueOf(playerData.getBedsDestroyed());
+ }
+
+ return ChatColor.RED + "No data saved!";
+ }
+}
diff --git a/src/main/java/rip/tilly/bedwars/providers/scoreboard/ScoreboardProvider.java b/src/main/java/rip/tilly/bedwars/providers/scoreboard/ScoreboardProvider.java
index fc4f02e..272cf5a 100644
--- a/src/main/java/rip/tilly/bedwars/providers/scoreboard/ScoreboardProvider.java
+++ b/src/main/java/rip/tilly/bedwars/providers/scoreboard/ScoreboardProvider.java
@@ -1,24 +1,35 @@
package rip.tilly.bedwars.providers.scoreboard;
+import me.clip.placeholderapi.PlaceholderAPI;
+import org.apache.commons.lang3.StringEscapeUtils;
import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import org.bukkit.scoreboard.DisplaySlot;
+import org.bukkit.scoreboard.Objective;
+import org.bukkit.scoreboard.Scoreboard;
+import org.bukkit.scoreboard.Team;
+import rip.tilly.bedwars.BedWars;
import rip.tilly.bedwars.game.Game;
import rip.tilly.bedwars.game.GameTeam;
import rip.tilly.bedwars.managers.party.Party;
import rip.tilly.bedwars.managers.queue.QueueEntry;
-import rip.tilly.bedwars.playerdata.PlayerState;
-import rip.tilly.bedwars.utils.TimeUtils;
-import rip.tilly.bedwars.utils.assemble.AssembleAdapter;
-import org.bukkit.entity.Player;
-import rip.tilly.bedwars.BedWars;
import rip.tilly.bedwars.playerdata.PlayerData;
+import rip.tilly.bedwars.playerdata.PlayerState;
import rip.tilly.bedwars.utils.CC;
+import rip.tilly.bedwars.utils.TimeUtils;
+import rip.tilly.bedwars.utils.aether.scoreboard.Board;
+import rip.tilly.bedwars.utils.aether.scoreboard.BoardAdapter;
+import rip.tilly.bedwars.utils.aether.scoreboard.cooldown.BoardCooldown;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
+import java.util.UUID;
-public class ScoreboardProvider implements AssembleAdapter {
+public class ScoreboardProvider implements BoardAdapter {
- private BedWars main = BedWars.getInstance();
+ private final BedWars plugin = BedWars.getInstance();
@Override
public String getTitle(Player player) {
@@ -26,8 +37,12 @@ public class ScoreboardProvider implements AssembleAdapter {
}
@Override
- public List getLines(Player player) {
- PlayerData playerData = this.main.getPlayerDataManager().getPlayerData(player.getUniqueId());
+ public List getScoreboard(Player player, Board board, Set cooldowns) {
+ PlayerData playerData = this.plugin.getPlayerDataManager().getPlayerData(player.getUniqueId());
+
+ if (playerData == null) {
+ return null;
+ }
if (!playerData.getPlayerSettings().isScoreboardEnabled()) {
return null;
@@ -41,19 +56,106 @@ public class ScoreboardProvider implements AssembleAdapter {
case PLAYING:
return this.playingScoreboard(playerData);
case SPECTATING:
- return null;
+ return this.spectatingScoreboard(playerData);
}
return null;
}
+ @Override
+ public void onScoreboardCreate(Player player, Scoreboard scoreboard) {
+ if (scoreboard != null) {
+ Team red = scoreboard.getTeam("red");
+ if (red == null) {
+ red = scoreboard.registerNewTeam("red");
+ }
+
+ Team green = scoreboard.getTeam("green");
+ if (green == null) {
+ green = scoreboard.registerNewTeam("green");
+ }
+
+ red.setPrefix(String.valueOf(ChatColor.RED));
+ green.setPrefix(String.valueOf(ChatColor.GREEN));
+
+ PlayerData playerData = this.plugin.getPlayerDataManager().getPlayerData(player.getUniqueId());
+ if (playerData.getPlayerState() != PlayerState.PLAYING) {
+ Objective objective = player.getScoreboard().getObjective(DisplaySlot.BELOW_NAME);
+ if (objective != null) {
+ objective.unregister();
+ }
+
+ for (String entry : red.getEntries()) {
+ red.removeEntry(entry);
+ }
+
+ for (String entry : green.getEntries()) {
+ green.removeEntry(entry);
+ }
+
+ for (Player online : Bukkit.getOnlinePlayers()) {
+ if (online == null) return;
+
+ Team spawn = scoreboard.getTeam(online.getName());
+ if (spawn == null) {
+ spawn = scoreboard.registerNewTeam(online.getName());
+ }
+
+ if (online == player) {
+ spawn.setPrefix(CC.translate(PlaceholderAPI.setPlaceholders(player, "%aqua_player_color%")));
+ } else {
+ spawn.setPrefix(CC.translate(PlaceholderAPI.setPlaceholders(online, "%aqua_player_color%")));
+ }
+
+ String onlinePlayer = online.getName();
+ if (spawn.hasEntry(onlinePlayer)) {
+ continue;
+ }
+ spawn.addEntry(onlinePlayer);
+
+ return;
+ }
+ }
+
+ Game game = this.plugin.getGameManager().getGame(player.getUniqueId());
+ Objective objective = player.getScoreboard().getObjective(DisplaySlot.BELOW_NAME);
+ if (objective == null) {
+ objective = player.getScoreboard().registerNewObjective("showhealth", "health");
+ }
+
+ objective.setDisplaySlot(DisplaySlot.BELOW_NAME);
+ objective.setDisplayName(ChatColor.RED + StringEscapeUtils.unescapeJava("\u2764"));
+ objective.getScore(player.getName()).setScore((int) Math.floor(player.getHealth()));
+
+ for (GameTeam team : game.getTeams()) {
+ for (UUID teamUUID : team.getPlayingPlayers()) {
+ Player teamPlayer = this.plugin.getServer().getPlayer(teamUUID);
+ if (teamPlayer != null) {
+ String teamPlayerName = teamPlayer.getName();
+ if (team.getId() == 1) {
+ if (green.hasEntry(teamPlayerName)) {
+ continue;
+ }
+ green.addEntry(teamPlayerName);
+ } else {
+ if (red.hasEntry(teamPlayerName)) {
+ continue;
+ }
+ red.addEntry(teamPlayerName);
+ }
+ }
+ }
+ }
+ }
+ }
+
private List spawnScoreboard(PlayerData playerData) {
- List lines = new ArrayList();
+ List lines = new ArrayList<>();
lines.add(CC.scoreboardBar);
- if (this.main.getPartyManager().getParty(playerData.getUniqueId()) != null) {
- Party party = this.main.getPartyManager().getParty(playerData.getUniqueId());
+ if (this.plugin.getPartyManager().getParty(playerData.getUniqueId()) != null) {
+ Party party = this.plugin.getPartyManager().getParty(playerData.getUniqueId());
lines.add("&9Party Leader: &d" + Bukkit.getPlayer(party.getLeader()).getName());
lines.add("&9Party Members: &d" + party.getMembers().size() + "&7/&d" + party.getLimit());
@@ -61,10 +163,10 @@ public class ScoreboardProvider implements AssembleAdapter {
}
if (playerData.getPlayerState() == PlayerState.QUEUE) {
- QueueEntry queueEntry = this.main.getQueueManager().getQueueEntry(playerData.getUniqueId());
+ QueueEntry queueEntry = this.plugin.getQueueManager().getQueueEntry(playerData.getUniqueId());
if (queueEntry != null) {
- long queueTime = System.currentTimeMillis() - (this.main.getQueueManager().getPlayerQueueTime(playerData.getUniqueId()));
+ long queueTime = System.currentTimeMillis() - (this.plugin.getQueueManager().getPlayerQueueTime(playerData.getUniqueId()));
String formattedQueueTime = TimeUtils.formatIntoMMSS(Math.round(queueTime / 1000L));
@@ -74,9 +176,9 @@ public class ScoreboardProvider implements AssembleAdapter {
}
}
- lines.add("&fOnline: &d" + this.main.getServer().getOnlinePlayers().size());
- lines.add("&fQueueing: &d" + this.main.getQueueManager().getAllQueueSize());
- lines.add("&fPlaying: &d" + this.main.getGameManager().getPlaying());
+ lines.add("&fOnline: &d" + this.plugin.getServer().getOnlinePlayers().size());
+ lines.add("&fQueueing: &d" + this.plugin.getQueueManager().getAllQueueSize());
+ lines.add("&fPlaying: &d" + this.plugin.getGameManager().getPlaying());
lines.add(" ");
@@ -106,8 +208,8 @@ public class ScoreboardProvider implements AssembleAdapter {
}
private List playingScoreboard(PlayerData playerData) {
- List lines = new ArrayList();
- Game game = this.main.getGameManager().getGame(playerData);
+ List lines = new ArrayList<>();
+ Game game = this.plugin.getGameManager().getGame(playerData);
GameTeam yourTeam = game.getTeamByName(playerData.getPlayerTeam().getName());
GameTeam opposingTeam = game.getTeams().get(playerData.getTeamId() == 1 ? 0 : 1);
@@ -139,7 +241,7 @@ public class ScoreboardProvider implements AssembleAdapter {
}
private List spectatingScoreboard(PlayerData playerData) {
- List lines = new ArrayList();
+ List lines = new ArrayList<>();
lines.add(CC.scoreboardBar);
lines.add(CC.scoreboardBar);
diff --git a/src/main/java/rip/tilly/bedwars/providers/scoreboard/old/ScoreboardProvider.java b/src/main/java/rip/tilly/bedwars/providers/scoreboard/old/ScoreboardProvider.java
new file mode 100644
index 0000000..5b7cd3f
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/providers/scoreboard/old/ScoreboardProvider.java
@@ -0,0 +1,149 @@
+package rip.tilly.bedwars.providers.scoreboard.old;
+
+import org.bukkit.Bukkit;
+import rip.tilly.bedwars.game.Game;
+import rip.tilly.bedwars.game.GameTeam;
+import rip.tilly.bedwars.managers.party.Party;
+import rip.tilly.bedwars.managers.queue.QueueEntry;
+import rip.tilly.bedwars.playerdata.PlayerState;
+import rip.tilly.bedwars.utils.TimeUtils;
+import rip.tilly.bedwars.utils.assemble.AssembleAdapter;
+import org.bukkit.entity.Player;
+import rip.tilly.bedwars.BedWars;
+import rip.tilly.bedwars.playerdata.PlayerData;
+import rip.tilly.bedwars.utils.CC;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ScoreboardProvider implements AssembleAdapter {
+
+ private BedWars main = BedWars.getInstance();
+
+ @Override
+ public String getTitle(Player player) {
+ return CC.translate("&d&lBedWars");
+ }
+
+ @Override
+ public List getLines(Player player) {
+ PlayerData playerData = this.main.getPlayerDataManager().getPlayerData(player.getUniqueId());
+
+ if (!playerData.getPlayerSettings().isScoreboardEnabled()) {
+ return null;
+ }
+
+ switch (playerData.getPlayerState()) {
+ case SPAWN:
+ case QUEUE:
+ return this.spawnScoreboard(playerData);
+ case RESPAWNING:
+ case PLAYING:
+ return this.playingScoreboard(playerData);
+ case SPECTATING:
+ return null;
+ }
+
+ return null;
+ }
+
+ private List spawnScoreboard(PlayerData playerData) {
+ List lines = new ArrayList();
+
+ lines.add(CC.scoreboardBar);
+
+ if (this.main.getPartyManager().getParty(playerData.getUniqueId()) != null) {
+ Party party = this.main.getPartyManager().getParty(playerData.getUniqueId());
+
+ lines.add("&9Party Leader: &d" + Bukkit.getPlayer(party.getLeader()).getName());
+ lines.add("&9Party Members: &d" + party.getMembers().size() + "&7/&d" + party.getLimit());
+ lines.add(CC.scoreboardBar);
+ }
+
+ if (playerData.getPlayerState() == PlayerState.QUEUE) {
+ QueueEntry queueEntry = this.main.getQueueManager().getQueueEntry(playerData.getUniqueId());
+
+ if (queueEntry != null) {
+ long queueTime = System.currentTimeMillis() - (this.main.getQueueManager().getPlayerQueueTime(playerData.getUniqueId()));
+
+ String formattedQueueTime = TimeUtils.formatIntoMMSS(Math.round(queueTime / 1000L));
+
+ lines.add("&e" + queueEntry.getGameType().getName() + " Queue");
+ lines.add("&fTime: &d" + formattedQueueTime);
+ lines.add(CC.scoreboardBar);
+ }
+ }
+
+ lines.add("&fOnline: &d" + this.main.getServer().getOnlinePlayers().size());
+ lines.add("&fQueueing: &d" + this.main.getQueueManager().getAllQueueSize());
+ lines.add("&fPlaying: &d" + this.main.getGameManager().getPlaying());
+
+ lines.add(" ");
+
+ lines.add("&fLevel: &d" + playerData.getLevel());
+ String finishedProgress = "";
+ int notFinishedProgress = 10;
+ for (int i = 0; i < playerData.getXp() * 100; i++) {
+ if (i % 10 == 0) {
+ finishedProgress += "⬛";
+
+ notFinishedProgress--;
+ }
+ }
+
+ String leftOverProgress = "";
+ for (int i = 1; i <= notFinishedProgress; i++) {
+ leftOverProgress += "⬛";
+ }
+
+ lines.add("&8" + finishedProgress + "&7" + leftOverProgress + " &7(" + ((int) (playerData.getXp() * 100)) + "%&7)");
+
+ lines.add(" ");
+ lines.add("&dtilly.rip");
+ lines.add(CC.scoreboardBar);
+
+ return CC.translate(lines);
+ }
+
+ private List playingScoreboard(PlayerData playerData) {
+ List lines = new ArrayList();
+ Game game = this.main.getGameManager().getGame(playerData);
+ GameTeam yourTeam = game.getTeamByName(playerData.getPlayerTeam().getName());
+ GameTeam opposingTeam = game.getTeams().get(playerData.getTeamId() == 1 ? 0 : 1);
+
+ lines.add(CC.scoreboardBar);
+ lines.add("&fDuration: &d" + game.getDuration());
+ lines.add(" ");
+ if (yourTeam.isHasBed()) {
+ lines.add("&7[" + yourTeam.getPlayerTeam().getChatColor() + yourTeam.getPlayerTeam().getSmallName() + "&7] &a&l✓ &7(You)");
+ } else if (yourTeam.getPlayingPlayers().size() > 0) {
+ lines.add("&7[" + yourTeam.getPlayerTeam().getChatColor() + yourTeam.getPlayerTeam().getSmallName() + "&7] &f" + yourTeam.getPlayingPlayers().size() + " &7(YOU)");
+ } else {
+ lines.add("&7[" + yourTeam.getPlayerTeam().getChatColor() + yourTeam.getPlayerTeam().getSmallName() + "&7] &c&l✗ &7(You)");
+ }
+ if (opposingTeam.isHasBed()) {
+ lines.add("&7[" + opposingTeam.getPlayerTeam().getChatColor() + opposingTeam.getPlayerTeam().getSmallName() + "&7] &a&l✓");
+ } else if (opposingTeam.getPlayingPlayers().size() > 0) {
+ lines.add("&7[" + opposingTeam.getPlayerTeam().getChatColor() + opposingTeam.getPlayerTeam().getSmallName() + "&7] &f" + yourTeam.getPlayingPlayers().size());
+ } else {
+ lines.add("&7[" + opposingTeam.getPlayerTeam().getChatColor() + opposingTeam.getPlayerTeam().getSmallName() + "&7] &c&l✗");
+ }
+ lines.add(" ");
+ lines.add("&fKills: &d" + playerData.getGameKills());
+ lines.add("&fBeds Destroyed: &d" + playerData.getGameBedsDestroyed());
+ lines.add(" ");
+ lines.add("&dtilly.rip");
+ lines.add(CC.scoreboardBar);
+
+ return CC.translate(lines);
+ }
+
+ private List spectatingScoreboard(PlayerData playerData) {
+ List lines = new ArrayList();
+
+ lines.add(CC.scoreboardBar);
+ lines.add(CC.scoreboardBar);
+
+ return CC.translate(lines);
+ }
+}
diff --git a/src/main/java/rip/tilly/bedwars/providers/tablist/TablistProvider.java b/src/main/java/rip/tilly/bedwars/providers/tablist/TablistProvider.java
new file mode 100644
index 0000000..a5b2b97
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/providers/tablist/TablistProvider.java
@@ -0,0 +1,52 @@
+package rip.tilly.bedwars.providers.tablist;
+
+import club.frozed.tablist.adapter.TabAdapter;
+import club.frozed.tablist.entry.TabEntry;
+import club.frozed.tablist.skin.Skin;
+import com.google.common.collect.Lists;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import rip.tilly.bedwars.BedWars;
+import rip.tilly.bedwars.utils.CC;
+
+import java.util.List;
+
+public class TablistProvider implements TabAdapter {
+
+ private final BedWars plugin = BedWars.getInstance();
+
+ @Override
+ public String getHeader(Player player) {
+ return CC.translate("&d&lTilly RIP &7┃ &fBedWars");
+ }
+
+ @Override
+ public String getFooter(Player player) {
+ return CC.translate("&7tilly.rip");
+ }
+
+ @Override
+ public List getLines(Player player) {
+ List lines = Lists.newArrayList();
+ int column = 0;
+ int row = 0;
+ for (Player online : Bukkit.getOnlinePlayers()) {
+ GameProfile skin = ((CraftPlayer) online).getProfile();
+ Property property = skin.getProperties().get("textures").stream().findFirst().orElse(null);
+ lines.add(new TabEntry(column, row, player.getDisplayName()).setPing(((CraftPlayer) online).getHandle().ping).setSkin(new Skin(property.getValue(), property.getSignature())));
+ if (column++ < 2) {
+ continue;
+ }
+ column = 0;
+
+ if (row++ < 19) {
+ continue;
+ }
+ row = 0;
+ }
+ return lines;
+ }
+}
diff --git a/src/main/java/rip/tilly/bedwars/runnables/RespawnRunnable.java b/src/main/java/rip/tilly/bedwars/runnables/RespawnRunnable.java
index 01be62c..58edec7 100644
--- a/src/main/java/rip/tilly/bedwars/runnables/RespawnRunnable.java
+++ b/src/main/java/rip/tilly/bedwars/runnables/RespawnRunnable.java
@@ -37,7 +37,8 @@ public class RespawnRunnable extends BukkitRunnable {
}
if (this.respawnTime <= 1) {
- this.playerData.setPlayerState(PlayerState.PLAYING);
+ this.plugin.getServer().getScheduler().runTaskLater(this.plugin, () -> this.playerData.setPlayerState(PlayerState.PLAYING), 20L);
+
this.game.getTeams().forEach(team -> team.playingPlayers().forEach(gamePlayer -> gamePlayer.showPlayer(this.player)));
this.player.teleport(this.gameTeam.getId() == 1 ? this.game.getCopiedArena().getA().toBukkitLocation() : this.game.getCopiedArena().getB().toBukkitLocation());
@@ -45,10 +46,10 @@ public class RespawnRunnable extends BukkitRunnable {
this.player.sendMessage(CC.translate("&aYou have respawned!"));
this.player.playSound(this.player.getLocation(), Sound.ORB_PICKUP, 10F, 1F);
+ this.player.getInventory().setArmorContents(this.plugin.getGameManager().getGameArmor(playerData));
for (ItemStack stack : this.plugin.getGameManager().getGameItems()) {
this.player.getInventory().addItem(stack);
}
- this.player.getInventory().setArmorContents(this.plugin.getGameManager().getGameArmor(playerData));
this.game.getTeams().forEach(team -> team.playingPlayers().filter(player1 -> !this.player.equals(player1))
.forEach(matchplayer -> matchplayer.sendMessage(CC.translate(this.gameTeam.getPlayerTeam().getChatColor() + this.player.getName() + " &ehas respawned!"))));
diff --git a/src/main/java/rip/tilly/bedwars/utils/aether/Aether.java b/src/main/java/rip/tilly/bedwars/utils/aether/Aether.java
new file mode 100644
index 0000000..de2961a
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/utils/aether/Aether.java
@@ -0,0 +1,180 @@
+package rip.tilly.bedwars.utils.aether;
+
+import lombok.Getter;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.scoreboard.DisplaySlot;
+import org.bukkit.scoreboard.Objective;
+import org.bukkit.scoreboard.Score;
+import org.bukkit.scoreboard.Scoreboard;
+import rip.tilly.bedwars.utils.aether.event.BoardCreateEvent;
+import rip.tilly.bedwars.utils.aether.scoreboard.Board;
+import rip.tilly.bedwars.utils.aether.scoreboard.BoardAdapter;
+import rip.tilly.bedwars.utils.aether.scoreboard.BoardEntry;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import static rip.tilly.bedwars.utils.aether.AetherOptions.defaultOptions;
+
+public class Aether implements Listener {
+
+ @Getter
+ BoardAdapter adapter;
+ @Getter private JavaPlugin plugin;
+ @Getter private AetherOptions options;
+
+ public Aether(JavaPlugin plugin, BoardAdapter adapter, AetherOptions options) {
+ this.options = options;
+ this.plugin = plugin;
+
+ Bukkit.getPluginManager().registerEvents(this, plugin);
+
+ setAdapter(adapter);
+ run();
+ }
+
+ public Aether(JavaPlugin plugin, BoardAdapter adapter) {
+ this(plugin, adapter, defaultOptions());
+ }
+
+ public Aether(JavaPlugin plugin) {
+ this(plugin, null, defaultOptions());
+ }
+
+ private void run() {
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ if (adapter == null) return;
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ Board board = Board.getByPlayer(player);
+ if (board != null) {
+ List scores = adapter.getScoreboard(player, board, board.getCooldowns());
+ List translatedScores = new ArrayList<>();
+ if (scores == null) {
+ if (!board.getEntries().isEmpty()) {
+ for (BoardEntry boardEntry : board.getEntries()) {
+ boardEntry.remove();
+ }
+ board.getEntries().clear();
+ }
+ continue;
+ }
+
+ for (String line : scores) {
+ translatedScores.add(ChatColor.translateAlternateColorCodes('&', line));
+ }
+
+ if (!options.scoreDirectionDown()) {
+ Collections.reverse(scores);
+ }
+
+ Scoreboard scoreboard = board.getScoreboard();
+ Objective objective = board.getObjective();
+
+ if (!(objective.getDisplayName().equals(adapter.getTitle(player)))) {
+ objective.setDisplayName(ChatColor.translateAlternateColorCodes('&', adapter.getTitle(player)));
+ }
+
+ outer:
+ for (int i = 0; i < scores.size(); i++) {
+ String text = scores.get(i);
+ int position;
+ if (options.scoreDirectionDown()) {
+ position = 15 - i;
+ } else {
+ position = i + 1;
+ }
+
+ Iterator iterator = new ArrayList<>(board.getEntries()).iterator();
+ while (iterator.hasNext()) {
+ BoardEntry boardEntry = iterator.next();
+ Score score = objective.getScore(boardEntry.getKey());
+
+ if (score != null && boardEntry.getText().equals(ChatColor.translateAlternateColorCodes('&', text))) {
+ if (score.getScore() == position) {
+ continue outer;
+ }
+ }
+ }
+
+ int positionToSearch = options.scoreDirectionDown() ? 15 - position : position - 1;
+
+ iterator = board.getEntries().iterator();
+ while (iterator.hasNext()) {
+ BoardEntry boardEntry = iterator.next();
+ int entryPosition = scoreboard.getObjective(DisplaySlot.SIDEBAR).getScore(boardEntry.getKey()).getScore();
+
+ if (!options.scoreDirectionDown()) {
+ if (entryPosition > scores.size()) {
+ iterator.remove();
+ boardEntry.remove();
+ }
+ }
+
+ }
+
+ BoardEntry entry = board.getByPosition(positionToSearch);
+
+ if (entry == null) {
+ new BoardEntry(board, text).send(position);
+ } else {
+ entry.setText(text).setup().send(position);
+ }
+
+ if (board.getEntries().size() > scores.size()) {
+ iterator = board.getEntries().iterator();
+ while (iterator.hasNext()) {
+ BoardEntry boardEntry = iterator.next();
+ if ((!translatedScores.contains(boardEntry.getText())) || Collections.frequency(board.getBoardEntriesFormatted(), boardEntry.getText()) > 1) {
+ iterator.remove();
+ boardEntry.remove();
+ }
+ }
+ }
+ }
+ adapter.onScoreboardCreate(player, scoreboard);
+ player.setScoreboard(scoreboard);
+ }
+ }
+ }
+ }.runTaskTimerAsynchronously(plugin, 20L, 2L);
+ }
+
+ public void setAdapter(BoardAdapter adapter) {
+ this.adapter = adapter;
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ Board board = Board.getByPlayer(player);
+ if (board != null) {
+ Board.getBoards().remove(board);
+ }
+ Bukkit.getPluginManager().callEvent(new BoardCreateEvent(new Board(player, this, options), player));
+ }
+ }
+
+ @EventHandler
+ public void onPlayerJoinEvent(PlayerJoinEvent event) {
+ if (Board.getByPlayer(event.getPlayer()) == null) {
+ Bukkit.getPluginManager().callEvent(new BoardCreateEvent(new Board(event.getPlayer(), this, options), event.getPlayer()));
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onPlayerQuitEvent(PlayerQuitEvent event) {
+ Board board = Board.getByPlayer(event.getPlayer());
+ if (board != null) {
+ Board.getBoards().remove(board);
+ }
+ }
+}
diff --git a/src/main/java/rip/tilly/bedwars/utils/aether/AetherOptions.java b/src/main/java/rip/tilly/bedwars/utils/aether/AetherOptions.java
new file mode 100644
index 0000000..3a5167c
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/utils/aether/AetherOptions.java
@@ -0,0 +1,18 @@
+package rip.tilly.bedwars.utils.aether;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+@Getter
+@Setter
+@Accessors(chain = true, fluent = true)
+public class AetherOptions {
+
+ private boolean hook;
+ private boolean scoreDirectionDown;
+
+ static AetherOptions defaultOptions() {
+ return new AetherOptions().hook(false).scoreDirectionDown(false);
+ }
+}
diff --git a/src/main/java/rip/tilly/bedwars/utils/aether/event/BoardCreateEvent.java b/src/main/java/rip/tilly/bedwars/utils/aether/event/BoardCreateEvent.java
new file mode 100644
index 0000000..2c81cc6
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/utils/aether/event/BoardCreateEvent.java
@@ -0,0 +1,27 @@
+package rip.tilly.bedwars.utils.aether.event;
+
+import lombok.Getter;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import rip.tilly.bedwars.utils.aether.scoreboard.Board;
+
+public class BoardCreateEvent extends Event {
+
+ private static final HandlerList HANDLERS = new HandlerList();
+ @Getter private final Board board;
+ @Getter private final Player player;
+
+ public BoardCreateEvent(Board board, Player player) {
+ this.board = board;
+ this.player = player;
+ }
+
+ public static HandlerList getHandlerList() {
+ return HANDLERS;
+ }
+
+ public HandlerList getHandlers() {
+ return HANDLERS;
+ }
+}
diff --git a/src/main/java/rip/tilly/bedwars/utils/aether/scoreboard/Board.java b/src/main/java/rip/tilly/bedwars/utils/aether/scoreboard/Board.java
new file mode 100644
index 0000000..4fa5015
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/utils/aether/scoreboard/Board.java
@@ -0,0 +1,129 @@
+package rip.tilly.bedwars.utils.aether.scoreboard;
+
+import io.netty.util.internal.ConcurrentSet;
+import lombok.Getter;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import org.bukkit.scoreboard.DisplaySlot;
+import org.bukkit.scoreboard.Objective;
+import org.bukkit.scoreboard.Scoreboard;
+import rip.tilly.bedwars.utils.aether.Aether;
+import rip.tilly.bedwars.utils.aether.AetherOptions;
+import rip.tilly.bedwars.utils.aether.scoreboard.cooldown.BoardCooldown;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+public class Board {
+
+ @Getter private static Set boards = new ConcurrentSet<>();
+
+ private final Aether aether;
+ private final AetherOptions options;
+
+ @Getter private Scoreboard scoreboard;
+ @Getter private Player player;
+ @Getter private Objective objective;
+ @Getter private Set keys;
+ @Getter private List entries;
+
+ private Set cooldowns;
+
+ public Board(Player player, Aether aether, AetherOptions options) {
+ this.player = player;
+ this.aether = aether;
+ this.options = options;
+
+ this.keys = new ConcurrentSet<>();
+ this.entries = new ArrayList<>();
+
+ this.cooldowns = new ConcurrentSet<>();
+
+ setup();
+ }
+
+ public static Board getByPlayer(Player player) {
+ for (Board board : boards) {
+ if (board.getPlayer().getName().equals(player.getName())) {
+ return board;
+ }
+ }
+
+ return null;
+ }
+
+ private void setup() {
+ if (options.hook() && !player.getScoreboard().equals(Bukkit.getScoreboardManager().getMainScoreboard())) {
+ scoreboard = player.getScoreboard();
+ } else {
+ scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
+ }
+
+ objective = scoreboard.registerNewObjective("glaedr_is_shit", "dummy");
+ objective.setDisplaySlot(DisplaySlot.SIDEBAR);
+
+ if (aether.getAdapter() != null) {
+ objective.setDisplayName(ChatColor.translateAlternateColorCodes('&', aether.getAdapter().getTitle(player)));
+ } else {
+ objective.setDisplayName("Default Title");
+ }
+
+ boards.add(this);
+ }
+
+ public String getNewKey(BoardEntry entry) {
+ for (ChatColor color : ChatColor.values()) {
+ String colorText = color + "" + ChatColor.WHITE;
+ if (entry.getText().length() > 16) {
+ String sub = entry.getText().substring(0, 16);
+ colorText = colorText + ChatColor.getLastColors(sub);
+ }
+
+ if (!keys.contains(colorText)) {
+ keys.add(colorText);
+ return colorText;
+ }
+ }
+
+ throw new IndexOutOfBoundsException("No more keys available!");
+ }
+
+ public List getBoardEntriesFormatted() {
+ List toReturn = new ArrayList<>();
+ for (BoardEntry entry : new ArrayList<>(entries)) {
+ toReturn.add(entry.getText());
+ }
+
+ return toReturn;
+ }
+
+ public BoardEntry getByPosition(int position) {
+ int i = 0;
+
+ for (BoardEntry board : entries) {
+ if (i == position) {
+ return board;
+ }
+ i++;
+ }
+
+ return null;
+ }
+
+ public BoardCooldown getCooldown(String id) {
+ for (BoardCooldown cooldown : getCooldowns()) {
+ if (cooldown.getId().equals(id)) {
+ return cooldown;
+ }
+ }
+
+ return null;
+ }
+
+ public Set getCooldowns() {
+ cooldowns.removeIf(cooldown -> System.currentTimeMillis() >= cooldown.getEnd());
+ return cooldowns;
+ }
+}
diff --git a/src/main/java/rip/tilly/bedwars/utils/aether/scoreboard/BoardAdapter.java b/src/main/java/rip/tilly/bedwars/utils/aether/scoreboard/BoardAdapter.java
new file mode 100644
index 0000000..1ee19d6
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/utils/aether/scoreboard/BoardAdapter.java
@@ -0,0 +1,17 @@
+package rip.tilly.bedwars.utils.aether.scoreboard;
+
+import org.bukkit.entity.Player;
+import org.bukkit.scoreboard.Scoreboard;
+import rip.tilly.bedwars.utils.aether.scoreboard.cooldown.BoardCooldown;
+
+import java.util.List;
+import java.util.Set;
+
+public interface BoardAdapter {
+
+ String getTitle(Player player);
+
+ List getScoreboard(Player player, Board board, Set cooldowns);
+
+ void onScoreboardCreate(Player player, Scoreboard board);
+}
diff --git a/src/main/java/rip/tilly/bedwars/utils/aether/scoreboard/BoardEntry.java b/src/main/java/rip/tilly/bedwars/utils/aether/scoreboard/BoardEntry.java
new file mode 100644
index 0000000..8e96a82
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/utils/aether/scoreboard/BoardEntry.java
@@ -0,0 +1,90 @@
+package rip.tilly.bedwars.utils.aether.scoreboard;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import org.bukkit.ChatColor;
+import org.bukkit.scoreboard.Objective;
+import org.bukkit.scoreboard.Score;
+import org.bukkit.scoreboard.Scoreboard;
+import org.bukkit.scoreboard.Team;
+
+@Accessors(chain = true)
+public class BoardEntry {
+
+ @Getter private Board board;
+ @Getter @Setter private String text;
+ @Getter private String originalText;
+ @Getter private String key;
+ @Getter private Team team;
+
+ public BoardEntry(Board board, String text) {
+ this.board = board;
+ this.text = text;
+ this.originalText = text;
+ this.key = board.getNewKey(this);
+
+ setup();
+ }
+
+ public BoardEntry setup() {
+ Scoreboard scoreboard = board.getScoreboard();
+
+ text = ChatColor.translateAlternateColorCodes('&', text);
+
+ String teamName = key;
+
+ if (teamName.length() > 16) {
+ teamName = teamName.substring(0, 16);
+ }
+
+ if (scoreboard.getTeam(teamName) != null) {
+ team = scoreboard.getTeam(teamName);
+ } else {
+ team = scoreboard.registerNewTeam(teamName);
+ }
+
+ if (!(team.getEntries().contains(key))) {
+ team.addEntry(key);
+ }
+
+ if (!(board.getEntries().contains(this))) {
+ board.getEntries().add(this);
+ }
+
+ return this;
+ }
+
+ public BoardEntry send(int position) {
+ Objective objective = board.getObjective();
+
+ if (text.length() > 16) {
+ boolean fix = text.toCharArray()[15] == ChatColor.COLOR_CHAR;
+
+ String prefix = fix ? text.substring(0, 15) : text.substring(0, 16);
+ String suffix = fix ? text.substring(15) : ChatColor.getLastColors(prefix) + text.substring(16);
+
+ team.setPrefix(prefix);
+
+ if (suffix.length() > 16) {
+ team.setSuffix(suffix.substring(0, 16));
+ } else {
+ team.setSuffix(suffix);
+ }
+ } else {
+ team.setPrefix(text);
+ team.setSuffix("");
+ }
+
+ Score score = objective.getScore(key);
+ score.setScore(position);
+
+ return this;
+ }
+
+ public void remove() {
+ board.getKeys().remove(key);
+ board.getScoreboard().resetScores(key);
+ }
+
+}
diff --git a/src/main/java/rip/tilly/bedwars/utils/aether/scoreboard/cooldown/BoardCooldown.java b/src/main/java/rip/tilly/bedwars/utils/aether/scoreboard/cooldown/BoardCooldown.java
new file mode 100644
index 0000000..c51c659
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/utils/aether/scoreboard/cooldown/BoardCooldown.java
@@ -0,0 +1,42 @@
+package rip.tilly.bedwars.utils.aether.scoreboard.cooldown;
+
+import lombok.Getter;
+import org.apache.commons.lang.time.DurationFormatUtils;
+import rip.tilly.bedwars.utils.aether.scoreboard.Board;
+
+import java.text.DecimalFormat;
+
+public class BoardCooldown {
+
+ private static final DecimalFormat SECONDS_FORMATTER = new DecimalFormat("#0.0");
+
+ @Getter private final Board board;
+ @Getter private final String id;
+ @Getter private final double duration;
+ @Getter private final long end;
+
+ public BoardCooldown(Board board, String id, double duration) {
+ this.board = board;
+ this.id = id;
+ this.duration = duration;
+ this.end = (long) (System.currentTimeMillis() + (duration * 1000));
+
+ board.getCooldowns().add(this);
+ }
+
+ public String getFormattedString(BoardFormat format) {
+ if (format == null) {
+ throw new NullPointerException();
+ }
+ if (format == BoardFormat.SECONDS) {
+ return SECONDS_FORMATTER.format(((end - System.currentTimeMillis()) / 1000.0f));
+ } else {
+ return DurationFormatUtils.formatDuration(end - System.currentTimeMillis(), "mm:ss");
+ }
+ }
+
+ public void cancel() {
+ board.getCooldowns().remove(this);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/rip/tilly/bedwars/utils/aether/scoreboard/cooldown/BoardFormat.java b/src/main/java/rip/tilly/bedwars/utils/aether/scoreboard/cooldown/BoardFormat.java
new file mode 100644
index 0000000..52f9004
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/utils/aether/scoreboard/cooldown/BoardFormat.java
@@ -0,0 +1,5 @@
+package rip.tilly.bedwars.utils.aether.scoreboard.cooldown;
+
+public enum BoardFormat {
+ SECONDS, MINUTES, HOURS
+}