package de.steamwar.lobby.util; import de.steamwar.entity.RArmorStand; import de.steamwar.entity.REntity; import de.steamwar.entity.REntityServer; import de.steamwar.lobby.LobbySystem; import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.internal.Statement; import lombok.AllArgsConstructor; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class Leaderboard implements Listener { private static final Statement LEADERBOARD = new Statement("SELECT User, CAST(Value as integer) AS Time from UserConfig WHERE Config = ? ORDER BY CAST(Value as integer) ASC LIMIT ?"); private static final Statement PLAYER_TIME = new Statement("SELECT CAST(Value as integer) AS Time FROM UserConfig WHERE Config = ? AND User = ?"); private static final Statement PLAYER_PLACEMENT = new Statement("SELECT COUNT(*) AS Placement FROM UserConfig WHERE Config = ? AND CAST(Value as integer) < (SELECT CAST(Value as integer) AS Time FROM UserConfig WHERE Config = ? AND User = ?)"); private final REntityServer server; private final String configKey; private final Location location; private final int best; private long bestTime; private final List entities = new ArrayList<>(); private final Map playerPlacements = new HashMap<>(); public Leaderboard(REntityServer server, String configKey, Location location, int best) { this.server = server; this.configKey = configKey; this.location = location; this.best = best; Bukkit.getPluginManager().registerEvents(this, LobbySystem.getInstance()); update(); } public void update() { entities.forEach(REntity::die); entities.clear(); List leaderboard = getLeaderboard(); if (leaderboard.isEmpty()) return; bestTime = leaderboard.get(0).time; for (int i = 0; i < leaderboard.size(); i++) { LeaderboardEntry entry = leaderboard.get(i); RArmorStand entity = new RArmorStand(server, location.clone().add(0, (leaderboard.size() - i - 1) * 0.32, 0), RArmorStand.Size.MARKER); SteamwarUser user = SteamwarUser.get(entry.user); String color = "§7"; if (i == 0) { color = "§6§l"; } else if (i < 3) { color = "§e"; } entity.setDisplayName(calcName(user, color, i + 1, entry.time)); entity.setInvisible(true); entities.add(entity); } Bukkit.getOnlinePlayers().forEach(player -> { updatePlayerPlacement(player, SteamwarUser.get(player.getUniqueId())); }); } private void updatePlayerPlacement(Player player, SteamwarUser steamwarUser) { if (server.getEntities().isEmpty()) return; int placement = getPlayerPlacement(steamwarUser); if (placement < 5) { REntityServer entityServer = playerPlacements.remove(steamwarUser.getId()); if (entityServer == null) return; entityServer.getEntities().forEach(rEntity -> rEntity.hide(true)); return; } REntityServer entityServer = playerPlacements.computeIfAbsent(steamwarUser.getId(), ignore -> { REntityServer server = new REntityServer(); server.addPlayer(player); return server; }); List entities = entityServer.getEntities(); RArmorStand entity; if (entities.isEmpty()) { entity = new RArmorStand(entityServer, location.clone().add(0, -2 * 0.32, 0), RArmorStand.Size.MARKER); entity.setInvisible(true); } else { entity = (RArmorStand) entities.get(0); entity.hide(false); } long time = getPlayerTime(steamwarUser); entity.setDisplayName(calcName(steamwarUser, "§f", placement, time)); } private String calcName(SteamwarUser user, String color, int placement, long time) { StringBuilder st = new StringBuilder(); st.append(color); if (placement == Integer.MAX_VALUE) { st.append("???").append(". ").append(user.getUserName()); } else { st.append(placement).append(". ").append(user.getUserName()); } st.append(" §8• ").append(color); if (placement == Integer.MAX_VALUE) { st.append("??:??,???"); } else { st.append(renderTime(time)); } if (time != bestTime && placement != Integer.MAX_VALUE) { st.append(" §8• "); st.append(color).append("+").append(renderShortTime(time - bestTime)); } return st.toString(); } private List getLeaderboard() { return LEADERBOARD.select(resultSet -> { List leaderboard = new ArrayList<>(); while (resultSet.next()) { leaderboard.add(new LeaderboardEntry(resultSet.getInt("User"), resultSet.getLong("Time"))); } return leaderboard; }, configKey, best); } private long getPlayerTime(SteamwarUser user) { return PLAYER_TIME.select(resultSet -> { if (!resultSet.next()) { return Long.MAX_VALUE; } return resultSet.getLong("Time"); }, configKey, user.getId()); } private int getPlayerPlacement(SteamwarUser user) { return PLAYER_PLACEMENT.select(resultSet -> { if (!resultSet.next()) { return Integer.MAX_VALUE; } return resultSet.getInt("Placement"); }, configKey, configKey, user.getId()); } public static String renderTime(long time) { return String.format( "%d:%02d.%03d", time / 60000, (time / 1000) % 60, time % 1000); } public static String renderShortTime(long time) { return String.format( "%d.%03d", time / 1000, time % 1000); } @AllArgsConstructor private class LeaderboardEntry { private final int user; private final long time; } @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { SteamwarUser steamwarUser = SteamwarUser.get(event.getPlayer().getUniqueId()); updatePlayerPlacement(event.getPlayer(), steamwarUser); } @EventHandler public void onPlayerQuit(PlayerQuitEvent event) { SteamwarUser steamwarUser = SteamwarUser.get(event.getPlayer().getUniqueId()); REntityServer entityServer = playerPlacements.remove(steamwarUser.getId()); if (entityServer == null) return; entityServer.close(); } }