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.

This commit is contained in:
2025-10-20 16:39:35 +02:00
committed by Chaoscaot
parent e6848b27a0
commit 9e9f405e30
4 changed files with 115 additions and 64 deletions
@@ -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 <https://www.gnu.org/licenses/>.
*/
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<Leaderboard> table = new Table<>(Leaderboard.class);
private static final SelectStatement<Leaderboard> LEADERBOARD = new SelectStatement<>(table, "SELECT * from Leaderboard WHERE LeaderboardName = ? ORDER BY Time ASC LIMIT 5");
private static final SelectStatement<Leaderboard> 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<Leaderboard> 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;
}
@@ -22,8 +22,9 @@ package de.steamwar.lobby.boatrace;
import de.steamwar.entity.REntity; import de.steamwar.entity.REntity;
import de.steamwar.entity.REntityServer; import de.steamwar.entity.REntityServer;
import de.steamwar.lobby.LobbySystem; import de.steamwar.lobby.LobbySystem;
import de.steamwar.lobby.util.Leaderboard; import de.steamwar.lobby.util.LeaderboardManager;
import de.steamwar.sql.UserConfig; import de.steamwar.sql.Leaderboard;
import de.steamwar.sql.SteamwarUser;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Sound; import org.bukkit.Sound;
@@ -43,16 +44,18 @@ import org.bukkit.scheduler.BukkitTask;
import java.util.EventListener; 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 { public class BoatRace implements EventListener, Listener {
private static final String CONFIG_KEY = "lobby@boatrace";
private static final double MIN_HEIGHT = 4.3; private static final double MIN_HEIGHT = 4.3;
public static final REntityServer boatNpcServer; public static final REntityServer boatNpcServer;
private static boolean oneNotStarted = false; private static boolean oneNotStarted = false;
private static final Leaderboard leaderboard; private static final LeaderboardManager leaderboard;
static { static {
boatNpcServer = new REntityServer(); boatNpcServer = new REntityServer();
@@ -65,7 +68,7 @@ public class BoatRace implements EventListener, Listener {
new BoatRace(player); new BoatRace(player);
} }
}); });
leaderboard = new Leaderboard(boatNpcServer, "lobby@boatrace", BoatRacePositions.LEADERBOARD, 5); leaderboard = new LeaderboardManager(boatNpcServer, CONFIG_KEY, BoatRacePositions.LEADERBOARD);
} }
private final Player player; private final Player player;
@@ -123,12 +126,11 @@ public class BoatRace implements EventListener, Listener {
HandlerList.unregisterAll(this); HandlerList.unregisterAll(this);
task.cancel(); task.cancel();
LobbySystem.getMessage().send("BOAT_RACE_TIME", player, renderTime(time)); LobbySystem.getMessage().send("BOAT_RACE_TIME", player, renderTime(time));
String conf = UserConfig.getConfig(player.getUniqueId(), "lobby@boatrace"); SteamwarUser user = SteamwarUser.get(player.getUniqueId());
long best = Long.parseLong(conf == null ? String.valueOf(Long.MAX_VALUE) : conf); long best = leaderboard.getPlayerTime(user);
if (time < best) { if (time < best) {
LobbySystem.getMessage().send("BOAT_RACE_NEW_BEST", player); LobbySystem.getMessage().send("BOAT_RACE_NEW_BEST", player);
UserConfig.updatePlayerConfig(player.getUniqueId(), "lobby@boatrace", String.valueOf(time)); leaderboard.updateBestTime(user, time);
leaderboard.update();
} }
} else { } else {
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 1); player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 1);
@@ -22,8 +22,8 @@ package de.steamwar.lobby.jumpandrun;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import de.steamwar.lobby.LobbySystem; import de.steamwar.lobby.LobbySystem;
import de.steamwar.lobby.listener.PlayerSpawn; import de.steamwar.lobby.listener.PlayerSpawn;
import de.steamwar.lobby.util.Leaderboard; import de.steamwar.lobby.util.LeaderboardManager;
import de.steamwar.sql.UserConfig; import de.steamwar.sql.SteamwarUser;
import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.ChatMessageType;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@@ -58,7 +58,7 @@ public class JumpAndRun implements Listener {
private static final Map<Player, Long> CLICKED = new HashMap<>(); private static final Map<Player, Long> CLICKED = new HashMap<>();
private static final Map<Player, Integer> CLICKED_COUNT = new HashMap<>(); private static final Map<Player, Integer> 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(), () -> { Bukkit.getScheduler().runTaskTimer(LobbySystem.getInstance(), () -> {
@@ -161,18 +161,14 @@ public class JumpAndRun implements Listener {
} }
private void updateJumpAndRunTime(Player player, long time) { private void updateJumpAndRunTime(Player player, long time) {
String jumpAndRunTimeConfig = UserConfig.getConfig(player.getUniqueId(), JUMP_AND_RUN_CONFIG); long best = LEADERBOARD.getPlayerTime(SteamwarUser.get(player.getUniqueId()));
if (jumpAndRunTimeConfig == null) { if (time < best) {
UserConfig.updatePlayerConfig(player.getUniqueId(), JUMP_AND_RUN_CONFIG, time + ""); if (best != Long.MAX_VALUE) {
} else {
long jumpAndRunTime = Long.parseLong(jumpAndRunTimeConfig);
if (time < jumpAndRunTime) {
SimpleDateFormat format = new SimpleDateFormat(LobbySystem.getMessage().parse("JUMP_AND_RUN_TIME", player), Locale.ROOT); 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); 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);
} }
} }
@@ -23,9 +23,8 @@ import de.steamwar.entity.RArmorStand;
import de.steamwar.entity.REntity; import de.steamwar.entity.REntity;
import de.steamwar.entity.REntityServer; import de.steamwar.entity.REntityServer;
import de.steamwar.lobby.LobbySystem; import de.steamwar.lobby.LobbySystem;
import de.steamwar.sql.Leaderboard;
import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.internal.Statement;
import lombok.AllArgsConstructor;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -39,25 +38,18 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public class Leaderboard implements Listener { public class LeaderboardManager 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 REntityServer server;
private final String configKey; private final String configKey;
private final Location location; private final Location location;
private final int best;
private long bestTime; private long bestTime;
private final List<REntity> entities = new ArrayList<>(); private final List<REntity> entities = new ArrayList<>();
private final Map<Integer, REntityServer> playerPlacements = new HashMap<>(); private final Map<Integer, REntityServer> 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.server = server;
this.configKey = configKey; this.configKey = configKey;
this.location = location; this.location = location;
this.best = best;
Bukkit.getPluginManager().registerEvents(this, LobbySystem.getInstance()); Bukkit.getPluginManager().registerEvents(this, LobbySystem.getInstance());
update(); update();
} }
@@ -65,11 +57,11 @@ public class Leaderboard implements Listener {
public void update() { public void update() {
entities.forEach(REntity::die); entities.forEach(REntity::die);
entities.clear(); entities.clear();
List<LeaderboardEntry> leaderboard = getLeaderboard(); List<Leaderboard> leaderboard = getLeaderboard();
if (leaderboard.isEmpty()) return; if (leaderboard.isEmpty()) return;
bestTime = leaderboard.get(0).time; bestTime = leaderboard.get(0).getTime();
for (int i = 0; i < leaderboard.size(); i++) { 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); 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); SteamwarUser user = SteamwarUser.byId(entry.user);
String color = "§7"; String color = "§7";
@@ -78,7 +70,7 @@ public class Leaderboard implements Listener {
} else if (i < 3) { } else if (i < 3) {
color = "§e"; color = "§e";
} }
entity.setDisplayName(calcName(user, color, i + 1, entry.time)); entity.setDisplayName(calcName(user, color, i + 1, entry.getTime()));
entity.setInvisible(true); entity.setInvisible(true);
entities.add(entity); entities.add(entity);
} }
@@ -135,32 +127,27 @@ public class Leaderboard implements Listener {
return st.toString(); return st.toString();
} }
private List<LeaderboardEntry> getLeaderboard() { private boolean isNewBestTime(long time) {
return LEADERBOARD.select(resultSet -> { return time < bestTime;
List<LeaderboardEntry> 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) { public void updateBestTime(SteamwarUser user, long time) {
return PLAYER_TIME.select(resultSet -> { Leaderboard.upsert(user.getId(), configKey, time, isNewBestTime(time));
if (!resultSet.next()) { update();
return Long.MAX_VALUE; }
}
return resultSet.getLong("Time"); private List<Leaderboard> getLeaderboard() {
}, configKey, user.getId()); 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) { private int getPlayerPlacement(SteamwarUser user) {
return PLAYER_PLACEMENT.select(resultSet -> { return Leaderboard.getPlayerPlacement(user, configKey);
if (!resultSet.next()) {
return Integer.MAX_VALUE;
}
return resultSet.getInt("Placement");
}, configKey, configKey, user.getId());
} }
public static String renderTime(long time) { public static String renderTime(long time) {
@@ -178,13 +165,6 @@ public class Leaderboard implements Listener {
time % 1000); time % 1000);
} }
@AllArgsConstructor
private class LeaderboardEntry {
private final int user;
private final long time;
}
@EventHandler @EventHandler
public void onPlayerJoin(PlayerJoinEvent event) { public void onPlayerJoin(PlayerJoinEvent event) {
SteamwarUser steamwarUser = SteamwarUser.get(event.getPlayer().getUniqueId()); SteamwarUser steamwarUser = SteamwarUser.get(event.getPlayer().getUniqueId());