Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 71 additions & 7 deletions src/main/java/com/Lino/battlePass/gui/LeaderboardGui.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public void open() {

setupTitleItem(gui);
setupLeaderboard(gui);
setupPlayerRank(gui);

if (plugin.getConfigManager().isShopEnabled()) {
setupCoinsInfo(gui);
Expand Down Expand Up @@ -61,15 +62,16 @@ private void setupTitleItem(Inventory gui) {
}

private void setupLeaderboard(Inventory gui) {
int leaderboardSize = plugin.getConfigManager().getLeaderboardSize();
int xpPerLevel = plugin.getConfigManager().getXpPerLevel();

plugin.getDatabaseManager().getTop10Players().thenAccept(topPlayers -> {
Bukkit.getScheduler().runTask(plugin, () -> {
int[] slots = {19, 20, 21, 22, 23, 24, 25, 28, 29, 30};

for (int i = 0; i < topPlayers.size() && i < 10; i++) {
// Row 2 (slots 9-17), Row 3 (slots 18-26), Row 4 (slots 27+)
for (int i = 0; i < topPlayers.size() && i < leaderboardSize; i++) {
PlayerData topPlayer = topPlayers.get(i);
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(topPlayer.uuid);

// FIX: Controllo se il nome è null per evitare il crash
String playerName = offlinePlayer.getName();
if (playerName == null) {
playerName = "Unknown";
Expand All @@ -92,22 +94,70 @@ private void setupLeaderboard(Inventory gui) {
plugin.getMessageManager().getMessage("items.leaderboard-status.you") :
plugin.getMessageManager().getMessage("items.leaderboard-status.other");

String progressBar = createProgressBar(topPlayer.xp, xpPerLevel);

List<String> lore = new ArrayList<>();
for (String line : plugin.getMessageManager().getMessagesConfig().getStringList("items.leaderboard-player.lore")) {
String processedLine = line
.replace("%level%", String.valueOf(topPlayer.level))
.replace("%total_levels%", String.valueOf(topPlayer.totalLevels))
.replace("%xp%", String.valueOf(topPlayer.xp))
.replace("%xp_needed%", String.valueOf(xpPerLevel))
.replace("%progress_bar%", progressBar)
.replace("%coins%", String.valueOf(topPlayer.battleCoins))
.replace("%status%", status);
lore.add(GradientColorParser.parse(processedLine));
}

skullMeta.setLore(lore);
skull.setItemMeta(skullMeta);
gui.setItem(slots[i], skull);
// Slots: 9-17 (row 2), 18-26 (row 3), 27-35 (row 4)
gui.setItem(9 + i, skull);
}

if (player.getOpenInventory().getTitle().equals(title)) {
player.updateInventory();
}
});
});
}

private void setupPlayerRank(Inventory gui) {
int xpPerLevel = plugin.getConfigManager().getXpPerLevel();
int minLevel = plugin.getConfigManager().getLeaderboardMinLevel();

plugin.getDatabaseManager().getPlayerRankInfo(player.getUniqueId()).thenAccept(rankInfo -> {
Bukkit.getScheduler().runTask(plugin, () -> {
int rank = rankInfo[0];
int total = rankInfo[1];

PlayerData data = plugin.getPlayerDataManager().getPlayerData(player.getUniqueId());
if (data == null) return;

ItemStack item = new ItemStack(Material.RECOVERY_COMPASS);
ItemMeta meta = item.getItemMeta();
meta.setDisplayName(plugin.getMessageManager().getMessage("items.player-rank.name"));

String progressBar = createProgressBar(data.xp, xpPerLevel);
String lorePath = rank > 0 ? "items.player-rank.lore-ranked" : "items.player-rank.lore-unranked";

List<String> lore = new ArrayList<>();
for (String line : plugin.getMessageManager().getMessagesConfig().getStringList(lorePath)) {
String processedLine = line
.replace("%rank%", rank > 0 ? String.valueOf(rank) : "-")
.replace("%total%", String.valueOf(total))
.replace("%level%", String.valueOf(data.level))
.replace("%xp%", String.valueOf(data.xp))
.replace("%xp_needed%", String.valueOf(xpPerLevel))
.replace("%progress_bar%", progressBar)
.replace("%min_level%", String.valueOf(minLevel));
lore.add(GradientColorParser.parse(processedLine));
}

meta.setLore(lore);
item.setItemMeta(meta);
gui.setItem(31, item);

if (player.getOpenInventory().getTitle().equals(title)) {
player.updateInventory();
}
Expand All @@ -131,6 +181,20 @@ private void setupCoinsInfo(Inventory gui) {

meta.setLore(lore);
coinsInfo.setItemMeta(meta);
gui.setItem(40, coinsInfo);
gui.setItem(34, coinsInfo);
}

private String createProgressBar(int current, int max) {
int totalBars = 10;
int filled;
if (max <= 0) {
filled = 0;
} else {
filled = Math.min(totalBars, (int) Math.round((double) current / max * totalBars));
}
StringBuilder bar = new StringBuilder();
for (int i = 0; i < filled; i++) bar.append("&a█");
for (int i = filled; i < totalBars; i++) bar.append("&8░");
return bar.toString();
}
}
}
30 changes: 30 additions & 0 deletions src/main/java/com/Lino/battlePass/managers/ConfigManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ public class ConfigManager {
private int coinsDistributionHours = 24;
private int missionResetHours = 24;
private boolean customItemSoundsEnabled = true;
private String leaderboardSortBy = "level";
private String leaderboardTiebreaker = "xp";
private int leaderboardMinLevel = 2;
private int leaderboardSize = 20;
private boolean resetTotalLevelsOnSeasonEnd = true;

private Material guiFreeLockedMaterial = Material.GRAY_STAINED_GLASS;
private Material guiPremiumLockedMaterial = Material.GRAY_STAINED_GLASS;
Expand Down Expand Up @@ -65,6 +70,11 @@ public void reload() {
coinsDistributionHours = config.getInt("battle-coins.distribution-hours", 24);
missionResetHours = config.getInt("missions.reset-hours", 24);
customItemSoundsEnabled = config.getBoolean("custom-items.sounds-enabled", true);
leaderboardSortBy = config.getString("leaderboard.sort-by", "level").toLowerCase();
leaderboardTiebreaker = config.getString("leaderboard.tiebreaker", "xp").toLowerCase();
leaderboardMinLevel = config.getInt("leaderboard.min-level", 2);
leaderboardSize = Math.min(config.getInt("leaderboard.size", 20), 27);
resetTotalLevelsOnSeasonEnd = config.getBoolean("leaderboard.reset-total-levels-on-season-end", true);

databaseType = config.getString("database.type", "SQLITE");
dbHost = config.getString("database.host", "localhost");
Expand Down Expand Up @@ -268,4 +278,24 @@ public String getDbPrefix() {
public int getDbPoolSize() {
return dbPoolSize;
}

public String getLeaderboardSortBy() {
return leaderboardSortBy;
}

public String getLeaderboardTiebreaker() {
return leaderboardTiebreaker;
}

public int getLeaderboardMinLevel() {
return leaderboardMinLevel;
}

public int getLeaderboardSize() {
return leaderboardSize;
}

public boolean isResetTotalLevelsOnSeasonEnd() {
return resetTotalLevelsOnSeasonEnd;
}
}
102 changes: 98 additions & 4 deletions src/main/java/com/Lino/battlePass/managers/DatabaseManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -371,15 +371,34 @@ public CompletableFuture<Void> updatePlayerCoins(UUID uuid, int amount) {
}, databaseExecutor);
}

private String mapSortColumn(String configValue) {
switch (configValue) {
case "level": return "level";
case "total_levels": return "total_levels";
case "xp": return "xp";
case "battle_coins": return "battle_coins";
default: return "level";
}
}

public CompletableFuture<List<PlayerData>> getTop10Players() {
return CompletableFuture.supplyAsync(() -> {
List<PlayerData> allPlayers = new ArrayList<>();
Connection conn = null;
boolean shouldClose = isMySQL;

String sortBy = mapSortColumn(plugin.getConfigManager().getLeaderboardSortBy());
String tiebreaker = mapSortColumn(plugin.getConfigManager().getLeaderboardTiebreaker());
int minLevel = plugin.getConfigManager().getLeaderboardMinLevel();
int limit = plugin.getConfigManager().getLeaderboardSize();

String query = "SELECT * FROM " + prefix + "players WHERE exclude_from_top = 0 AND level >= ? ORDER BY " + sortBy + " DESC, " + tiebreaker + " DESC LIMIT ?";

try {
conn = getConnection();
try (PreparedStatement ps = conn.prepareStatement("SELECT * FROM " + prefix + "players WHERE exclude_from_top = 0 ORDER BY total_levels DESC, level DESC, xp DESC LIMIT 10")) {
try (PreparedStatement ps = conn.prepareStatement(query)) {
ps.setInt(1, minLevel);
ps.setInt(2, limit);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
PlayerData data = new PlayerData(UUID.fromString(rs.getString("uuid")));
Expand All @@ -403,6 +422,76 @@ public CompletableFuture<List<PlayerData>> getTop10Players() {
}, databaseExecutor);
}

/**
* Returns [rank, totalEligiblePlayers]. rank=-1 if player is not eligible.
*/
public CompletableFuture<int[]> getPlayerRankInfo(UUID uuid) {
return CompletableFuture.supplyAsync(() -> {
int[] result = new int[]{-1, 0};
Connection conn = null;
boolean shouldClose = isMySQL;

String sortBy = mapSortColumn(plugin.getConfigManager().getLeaderboardSortBy());
String tiebreaker = mapSortColumn(plugin.getConfigManager().getLeaderboardTiebreaker());
int minLevel = plugin.getConfigManager().getLeaderboardMinLevel();

try {
conn = getConnection();

// Get player's own values
int playerLevel = 0, playerSortVal = 0, playerTieVal = 0;
boolean excluded = false;
boolean found = false;
try (PreparedStatement ps = conn.prepareStatement(
"SELECT level, xp, total_levels, battle_coins, exclude_from_top FROM " + prefix + "players WHERE uuid = ?")) {
ps.setString(1, uuid.toString());
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
found = true;
playerLevel = rs.getInt("level");
playerSortVal = rs.getInt(sortBy);
playerTieVal = rs.getInt(tiebreaker);
excluded = rs.getInt("exclude_from_top") == 1;
}
}
}

// Get total eligible players
try (PreparedStatement ps = conn.prepareStatement(
"SELECT COUNT(*) FROM " + prefix + "players WHERE exclude_from_top = 0 AND level >= ?")) {
ps.setInt(1, minLevel);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) result[1] = rs.getInt(1);
}
}

if (!found || excluded || playerLevel < minLevel) {
return result;
}

// Count players ranked higher
String rankQuery = "SELECT COUNT(*) FROM " + prefix + "players WHERE exclude_from_top = 0 AND level >= ? AND (" +
sortBy + " > ? OR (" + sortBy + " = ? AND " + tiebreaker + " > ?))";
try (PreparedStatement ps = conn.prepareStatement(rankQuery)) {
ps.setInt(1, minLevel);
ps.setInt(2, playerSortVal);
ps.setInt(3, playerSortVal);
ps.setInt(4, playerTieVal);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) result[0] = rs.getInt(1) + 1;
}
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (shouldClose && conn != null) {
try { conn.close(); } catch (SQLException e) {}
}
}
return result;
}, databaseExecutor);
}

public CompletableFuture<Void> saveSeasonData(LocalDateTime endDate, LocalDateTime missionResetTime, String currentMissionDate) {
return CompletableFuture.runAsync(() -> {
Connection conn = null;
Expand Down Expand Up @@ -670,12 +759,17 @@ public CompletableFuture<Void> resetSeason() {
conn = getConnection();
try (Statement stmt = conn.createStatement()) {
boolean resetCoins = plugin.getConfigManager().isResetCoinsOnSeasonEnd();
boolean resetTotalLevels = plugin.getConfigManager().isResetTotalLevelsOnSeasonEnd();

StringBuilder sql = new StringBuilder("UPDATE " + prefix + "players SET xp = 0, level = 1, claimed_free = '', claimed_premium = '', has_premium = 0, last_daily_reward = 0");
if (resetCoins) {
stmt.executeUpdate("UPDATE " + prefix + "players SET xp = 0, level = 1, claimed_free = '', claimed_premium = '', has_premium = 0, last_daily_reward = 0, battle_coins = 0");
} else {
stmt.executeUpdate("UPDATE " + prefix + "players SET xp = 0, level = 1, claimed_free = '', claimed_premium = '', has_premium = 0, last_daily_reward = 0");
sql.append(", battle_coins = 0");
}
if (resetTotalLevels) {
sql.append(", total_levels = 0");
}
stmt.executeUpdate(sql.toString());

stmt.executeUpdate("DELETE FROM " + prefix + "missions");
stmt.executeUpdate("DELETE FROM " + prefix + "daily_missions");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,15 +160,10 @@ public String onRequest(OfflinePlayer player, String identifier) {
}

private String getPlayerRank(UUID uuid) {
CompletableFuture<List<PlayerData>> future = plugin.getDatabaseManager().getTop10Players();
List<PlayerData> topPlayers = future.join();

for (int i = 0; i < topPlayers.size(); i++) {
if (topPlayers.get(i).uuid.equals(uuid)) {
return String.valueOf(i + 1);
}
int[] rankInfo = plugin.getDatabaseManager().getPlayerRankInfo(uuid).join();
if (rankInfo[0] > 0) {
return String.valueOf(rankInfo[0]);
}

return "Unranked";
}

Expand Down Expand Up @@ -207,7 +202,8 @@ private String getTopPlayerPlaceholder(String identifier) {
String[] parts = identifier.split("_");
int position = Integer.parseInt(parts[0]);

if (position < 1 || position > 10) {
int maxPosition = plugin.getConfigManager().getLeaderboardSize();
if (position < 1 || position > maxPosition) {
return "";
}

Expand Down
8 changes: 8 additions & 0 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ battle-coins:
9: 2
10: 1

# Leaderboard configuration
leaderboard:
sort-by: level
tiebreaker: xp
min-level: 2
size: 20
reset-total-levels-on-season-end: true

# Shop configuration
shop:
enabled: true
Expand Down