diff --git a/CommonCore/SQL/src/de/steamwar/sql/Leaderboard.java b/CommonCore/SQL/src/de/steamwar/sql/Leaderboard.java
deleted file mode 100644
index 16ee2a41..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/Leaderboard.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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/CommonCore/SQL/src/de/steamwar/sql/Leaderboard.kt b/CommonCore/SQL/src/de/steamwar/sql/Leaderboard.kt
new file mode 100644
index 00000000..d3399e5d
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/Leaderboard.kt
@@ -0,0 +1,96 @@
+/*
+ * 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.useDb
+import org.jetbrains.exposed.v1.core.SortOrder
+import org.jetbrains.exposed.v1.core.and
+import org.jetbrains.exposed.v1.core.count
+import org.jetbrains.exposed.v1.core.dao.id.CompositeID
+import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.eq
+import org.jetbrains.exposed.v1.core.lessSubQuery
+import org.jetbrains.exposed.v1.dao.CompositeEntity
+import org.jetbrains.exposed.v1.dao.CompositeEntityClass
+import org.jetbrains.exposed.v1.javatime.CurrentTimestamp
+import org.jetbrains.exposed.v1.javatime.timestamp
+import org.jetbrains.exposed.v1.jdbc.select
+
+object LeaderboardTable : CompositeIdTable("Leaderboard") {
+ val userId = reference("UserId", SteamwarUserTable)
+ val name = varchar("Name", 64).entityId()
+ val time = long("Time")
+ val updatedAt = timestamp("UpdatedAt").defaultExpression(CurrentTimestamp)
+ val bestTime = bool("BestTime")
+}
+
+class Leaderboard(id: EntityID) : CompositeEntity(id) {
+ companion object : CompositeEntityClass(LeaderboardTable) {
+ @JvmStatic
+ fun getLeaderboard(name: String) = useDb {
+ find { LeaderboardTable.name eq name }.orderBy(LeaderboardTable.time to SortOrder.ASC).limit(5).toList()
+ }
+
+ @JvmStatic
+ fun getPlayerTime(user: SteamwarUser, name: String) = useDb {
+ findById(CompositeID {
+ it[LeaderboardTable.userId] = user.id.value
+ it[LeaderboardTable.name] = name
+ })
+ }
+
+ @JvmStatic
+ fun getPlayerPlacement(user: SteamwarUser, name: String) = useDb {
+ LeaderboardTable.select(LeaderboardTable.time.count())
+ .where {
+ (LeaderboardTable.name eq name) and (LeaderboardTable.time lessSubQuery LeaderboardTable.select(
+ LeaderboardTable.time
+ ).where { (LeaderboardTable.userId eq user.id.value) and (LeaderboardTable.name eq name) })
+ }
+ .firstOrNull()?.get(LeaderboardTable.time.count())?.toInt() ?: Int.MAX_VALUE
+ }
+
+ @JvmStatic
+ fun upsert(userId: Int, name: String, time: Long, bestTime: Boolean) = useDb {
+ findByIdAndUpdate(CompositeID {
+ it[LeaderboardTable.userId] = userId
+ it[LeaderboardTable.name] = name
+ }) {
+ it.time = time
+ it.bestTime = bestTime
+ } ?: new(
+ CompositeID {
+ it[LeaderboardTable.userId] = userId
+ it[LeaderboardTable.name] = name
+ }
+ ) {
+ this.time = time
+ this.bestTime = bestTime
+ }
+ }
+ }
+
+ val user by LeaderboardTable.userId.transform({ EntityID(it, SteamwarUserTable) }, { it.value })
+ val name by LeaderboardTable.name
+ var time by LeaderboardTable.time
+ var updatedAt by LeaderboardTable.updatedAt
+ var bestTime by LeaderboardTable.bestTime
+}
\ No newline at end of file
diff --git a/LobbySystem/src/de/steamwar/lobby/util/LeaderboardManager.java b/LobbySystem/src/de/steamwar/lobby/util/LeaderboardManager.java
index 50121e05..d5eb8cf9 100644
--- a/LobbySystem/src/de/steamwar/lobby/util/LeaderboardManager.java
+++ b/LobbySystem/src/de/steamwar/lobby/util/LeaderboardManager.java
@@ -50,7 +50,7 @@ public class LeaderboardManager implements Listener {
this.server = server;
this.configKey = configKey;
this.location = location;
- Bukkit.getPluginManager().registerEvents(this, LobbySystem.getPlugin());
+ Bukkit.getPluginManager().registerEvents(this, LobbySystem.getInstance());
update();
}
@@ -63,7 +63,7 @@ public class LeaderboardManager implements Listener {
for (int i = 0; i < leaderboard.size(); 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);
+ SteamwarUser user = SteamwarUser.byId(entry.getUser());
String color = "§7";
if (i == 0) {
color = "§6§l";