From 9e9f405e30fa9bf8b9f5d33347d65e4439168915 Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Mon, 20 Oct 2025 16:39:35 +0200 Subject: [PATCH] Refactor leaderboard management: replace `UserConfig`-based implementation with new `Leaderboard` SQL class, update related classes to use `LeaderboardManager`, and fix query/logic for best time retrieval. --- .../SQL/src/de/steamwar/sql/Leaderboard.java | 73 +++++++++++++++++++ .../de/steamwar/lobby/boatrace/BoatRace.java | 20 ++--- .../steamwar/lobby/jumpandrun/JumpAndRun.java | 20 ++--- ...aderboard.java => LeaderboardManager.java} | 66 ++++++----------- 4 files changed, 115 insertions(+), 64 deletions(-) create mode 100644 CommonCore/SQL/src/de/steamwar/sql/Leaderboard.java rename LobbySystem/src/de/steamwar/lobby/util/{Leaderboard.java => LeaderboardManager.java} (73%) diff --git a/CommonCore/SQL/src/de/steamwar/sql/Leaderboard.java b/CommonCore/SQL/src/de/steamwar/sql/Leaderboard.java new file mode 100644 index 00000000..16ee2a41 --- /dev/null +++ b/CommonCore/SQL/src/de/steamwar/sql/Leaderboard.java @@ -0,0 +1,73 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2025 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.sql; + +import de.steamwar.sql.internal.Field; +import de.steamwar.sql.internal.SelectStatement; +import de.steamwar.sql.internal.Statement; +import de.steamwar.sql.internal.Table; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.sql.Timestamp; +import java.util.List; + +@AllArgsConstructor +@Getter +public class Leaderboard { + private static final Table table = new Table<>(Leaderboard.class); + + private static final SelectStatement LEADERBOARD = new SelectStatement<>(table, "SELECT * from Leaderboard WHERE LeaderboardName = ? ORDER BY Time ASC LIMIT 5"); + private static final SelectStatement PLAYER_TIME = new SelectStatement<>(table, "SELECT * FROM Leaderboard WHERE LeaderboardName = ? AND UserId = ?"); + private static final Statement PLAYER_PLACEMENT = new Statement("SELECT COUNT(*) AS Placement FROM Leaderboard WHERE LeaderboardName = ? AND time < (SELECT time FROM UserConfig WHERE WHERE = ? AND LeaderboardName = ?)"); + + private static final Statement INSERT = new Statement("INSERT INTO Leaderboard (UserId, LeaderboardName, Time, BestTime) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE Time = VALUES(Time), BestTime = VALUES(BestTime)"); + + public static List getLeaderboard(String leaderboardName) { + return LEADERBOARD.listSelect(leaderboardName); + } + + public static Leaderboard getPlayerTime(SteamwarUser user, String leaderboardName) { + return PLAYER_TIME.select(leaderboardName, user); + } + + public static int getPlayerPlacement(SteamwarUser user, String leaderboardName) { + return PLAYER_PLACEMENT.select(rs -> { + if(!rs.next()) + return Integer.MAX_VALUE; + return rs.getInt("Placement"); + }, leaderboardName, user, leaderboardName); + } + + public static void upsert(int userId, String leaderboardName, long time, boolean bestTime) { + INSERT.update(userId, leaderboardName, time, bestTime); + } + + @Field(keys = Table.PRIMARY) + private final int userId; + @Field(keys = Table.PRIMARY) + private final String leaderboardName; + @Field + private final long time; + @Field + private final Timestamp updatedAt; + @Field + private final boolean bestTime; +} diff --git a/LobbySystem/src/de/steamwar/lobby/boatrace/BoatRace.java b/LobbySystem/src/de/steamwar/lobby/boatrace/BoatRace.java index 55c6daf7..e61533e0 100644 --- a/LobbySystem/src/de/steamwar/lobby/boatrace/BoatRace.java +++ b/LobbySystem/src/de/steamwar/lobby/boatrace/BoatRace.java @@ -22,8 +22,9 @@ package de.steamwar.lobby.boatrace; import de.steamwar.entity.REntity; import de.steamwar.entity.REntityServer; import de.steamwar.lobby.LobbySystem; -import de.steamwar.lobby.util.Leaderboard; -import de.steamwar.sql.UserConfig; +import de.steamwar.lobby.util.LeaderboardManager; +import de.steamwar.sql.Leaderboard; +import de.steamwar.sql.SteamwarUser; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Sound; @@ -43,16 +44,18 @@ import org.bukkit.scheduler.BukkitTask; import java.util.EventListener; -import static de.steamwar.lobby.util.Leaderboard.renderTime; +import static de.steamwar.lobby.util.LeaderboardManager.renderTime; public class BoatRace implements EventListener, Listener { + private static final String CONFIG_KEY = "lobby@boatrace"; + private static final double MIN_HEIGHT = 4.3; public static final REntityServer boatNpcServer; private static boolean oneNotStarted = false; - private static final Leaderboard leaderboard; + private static final LeaderboardManager leaderboard; static { boatNpcServer = new REntityServer(); @@ -65,7 +68,7 @@ public class BoatRace implements EventListener, Listener { new BoatRace(player); } }); - leaderboard = new Leaderboard(boatNpcServer, "lobby@boatrace", BoatRacePositions.LEADERBOARD, 5); + leaderboard = new LeaderboardManager(boatNpcServer, CONFIG_KEY, BoatRacePositions.LEADERBOARD); } private final Player player; @@ -123,12 +126,11 @@ public class BoatRace implements EventListener, Listener { HandlerList.unregisterAll(this); task.cancel(); LobbySystem.getMessage().send("BOAT_RACE_TIME", player, renderTime(time)); - String conf = UserConfig.getConfig(player.getUniqueId(), "lobby@boatrace"); - long best = Long.parseLong(conf == null ? String.valueOf(Long.MAX_VALUE) : conf); + SteamwarUser user = SteamwarUser.get(player.getUniqueId()); + long best = leaderboard.getPlayerTime(user); if (time < best) { LobbySystem.getMessage().send("BOAT_RACE_NEW_BEST", player); - UserConfig.updatePlayerConfig(player.getUniqueId(), "lobby@boatrace", String.valueOf(time)); - leaderboard.update(); + leaderboard.updateBestTime(user, time); } } else { player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 1); diff --git a/LobbySystem/src/de/steamwar/lobby/jumpandrun/JumpAndRun.java b/LobbySystem/src/de/steamwar/lobby/jumpandrun/JumpAndRun.java index adc63951..274a2b7f 100644 --- a/LobbySystem/src/de/steamwar/lobby/jumpandrun/JumpAndRun.java +++ b/LobbySystem/src/de/steamwar/lobby/jumpandrun/JumpAndRun.java @@ -22,8 +22,8 @@ package de.steamwar.lobby.jumpandrun; import de.steamwar.linkage.Linked; import de.steamwar.lobby.LobbySystem; import de.steamwar.lobby.listener.PlayerSpawn; -import de.steamwar.lobby.util.Leaderboard; -import de.steamwar.sql.UserConfig; +import de.steamwar.lobby.util.LeaderboardManager; +import de.steamwar.sql.SteamwarUser; import net.md_5.bungee.api.ChatMessageType; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -58,7 +58,7 @@ public class JumpAndRun implements Listener { private static final Map CLICKED = new HashMap<>(); private static final Map CLICKED_COUNT = new HashMap<>(); - private static final Leaderboard LEADERBOARD = new Leaderboard(LobbySystem.getEntityServer(false), JUMP_AND_RUN_CONFIG, new Location(Bukkit.getWorlds().get(0), 2338.5, 42.5, 1231.5), 5); + private static final LeaderboardManager LEADERBOARD = new LeaderboardManager(LobbySystem.getEntityServer(false), JUMP_AND_RUN_CONFIG, new Location(Bukkit.getWorlds().get(0), 2338.5, 42.5, 1231.5)); { Bukkit.getScheduler().runTaskTimer(LobbySystem.getInstance(), () -> { @@ -161,18 +161,14 @@ public class JumpAndRun implements Listener { } private void updateJumpAndRunTime(Player player, long time) { - String jumpAndRunTimeConfig = UserConfig.getConfig(player.getUniqueId(), JUMP_AND_RUN_CONFIG); - if (jumpAndRunTimeConfig == null) { - UserConfig.updatePlayerConfig(player.getUniqueId(), JUMP_AND_RUN_CONFIG, time + ""); - } else { - long jumpAndRunTime = Long.parseLong(jumpAndRunTimeConfig); - if (time < jumpAndRunTime) { + long best = LEADERBOARD.getPlayerTime(SteamwarUser.get(player.getUniqueId())); + if (time < best) { + if (best != Long.MAX_VALUE) { SimpleDateFormat format = new SimpleDateFormat(LobbySystem.getMessage().parse("JUMP_AND_RUN_TIME", player), Locale.ROOT); - String parsed = format.format(new Date(jumpAndRunTime - time)); + String parsed = format.format(new Date(best - time)); LobbySystem.getMessage().sendPrefixless("JUMP_AND_RUN_PERSONAL_BEST", player, parsed); - UserConfig.updatePlayerConfig(player.getUniqueId(), JUMP_AND_RUN_CONFIG, time + ""); - LEADERBOARD.update(); } + LEADERBOARD.updateBestTime(SteamwarUser.get(player.getUniqueId()), time); } } diff --git a/LobbySystem/src/de/steamwar/lobby/util/Leaderboard.java b/LobbySystem/src/de/steamwar/lobby/util/LeaderboardManager.java similarity index 73% rename from LobbySystem/src/de/steamwar/lobby/util/Leaderboard.java rename to LobbySystem/src/de/steamwar/lobby/util/LeaderboardManager.java index f0a33a4a..7bfebbab 100644 --- a/LobbySystem/src/de/steamwar/lobby/util/Leaderboard.java +++ b/LobbySystem/src/de/steamwar/lobby/util/LeaderboardManager.java @@ -23,9 +23,8 @@ import de.steamwar.entity.RArmorStand; import de.steamwar.entity.REntity; import de.steamwar.entity.REntityServer; import de.steamwar.lobby.LobbySystem; +import de.steamwar.sql.Leaderboard; 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; @@ -39,25 +38,18 @@ 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 = ?)"); - +public class LeaderboardManager implements Listener { 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) { + public LeaderboardManager(REntityServer server, String configKey, Location location) { this.server = server; this.configKey = configKey; this.location = location; - this.best = best; Bukkit.getPluginManager().registerEvents(this, LobbySystem.getInstance()); update(); } @@ -65,11 +57,11 @@ public class Leaderboard implements Listener { public void update() { entities.forEach(REntity::die); entities.clear(); - List leaderboard = getLeaderboard(); + List leaderboard = getLeaderboard(); if (leaderboard.isEmpty()) return; - bestTime = leaderboard.get(0).time; + bestTime = leaderboard.get(0).getTime(); for (int i = 0; i < leaderboard.size(); i++) { - LeaderboardEntry entry = leaderboard.get(i); + Leaderboard 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.byId(entry.user); String color = "§7"; @@ -78,7 +70,7 @@ public class Leaderboard implements Listener { } else if (i < 3) { color = "§e"; } - entity.setDisplayName(calcName(user, color, i + 1, entry.time)); + entity.setDisplayName(calcName(user, color, i + 1, entry.getTime())); entity.setInvisible(true); entities.add(entity); } @@ -135,32 +127,27 @@ public class Leaderboard implements Listener { 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 boolean isNewBestTime(long time) { + return time < bestTime; } - private long getPlayerTime(SteamwarUser user) { - return PLAYER_TIME.select(resultSet -> { - if (!resultSet.next()) { - return Long.MAX_VALUE; - } - return resultSet.getLong("Time"); - }, configKey, user.getId()); + public void updateBestTime(SteamwarUser user, long time) { + Leaderboard.upsert(user.getId(), configKey, time, isNewBestTime(time)); + update(); + } + + private List getLeaderboard() { + return Leaderboard.getLeaderboard(configKey); + } + + public long getPlayerTime(SteamwarUser user) { + Leaderboard lb = Leaderboard.getPlayerTime(user, configKey); + if(lb != null) return lb.getTime(); + return 0; } 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()); + return Leaderboard.getPlayerPlacement(user, configKey); } public static String renderTime(long time) { @@ -178,13 +165,6 @@ public class Leaderboard implements Listener { 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());