From 16af5e2bfd38fa4c230e43addb3374af852eacca Mon Sep 17 00:00:00 2001 From: cervinakuy <16023430+cervinakuy@users.noreply.github.com> Date: Sun, 25 Apr 2021 23:13:23 -0700 Subject: [PATCH] Added Leaderboards and modified internal stats fetching --- .../java/com/planetgallium/kitpvp/Game.java | 24 ++-- .../com/planetgallium/kitpvp/game/Arena.java | 24 ++-- .../planetgallium/kitpvp/game/Cooldowns.java | 7 +- .../planetgallium/kitpvp/game/Infobase.java | 95 +++++++++---- .../com/planetgallium/kitpvp/game/Kits.java | 4 +- .../kitpvp/game/Leaderboards.java | 127 ++++++++++++++++++ .../com/planetgallium/kitpvp/game/Levels.java | 89 ------------ .../com/planetgallium/kitpvp/game/Stats.java | 117 +++++++++------- .../kitpvp/listener/ChatListener.java | 2 +- .../kitpvp/listener/DeathListener.java | 8 +- .../kitpvp/util/CacheManager.java | 3 + .../kitpvp/util/Placeholders.java | 78 ++++++----- .../kitpvp/util/PlayerEntry.java | 23 ++++ src/main/java/com/zp4rker/localdb/Table.java | 32 ++++- 14 files changed, 386 insertions(+), 247 deletions(-) create mode 100644 src/main/java/com/planetgallium/kitpvp/game/Leaderboards.java delete mode 100644 src/main/java/com/planetgallium/kitpvp/game/Levels.java create mode 100644 src/main/java/com/planetgallium/kitpvp/util/PlayerEntry.java diff --git a/src/main/java/com/planetgallium/kitpvp/Game.java b/src/main/java/com/planetgallium/kitpvp/Game.java index eae718b..01b464a 100644 --- a/src/main/java/com/planetgallium/kitpvp/Game.java +++ b/src/main/java/com/planetgallium/kitpvp/Game.java @@ -23,11 +23,11 @@ import com.planetgallium.kitpvp.util.*; public class Game extends JavaPlugin implements Listener { private static Game instance; - private static String prefix; + private static String prefix = "None"; private Arena arena; private Infobase database; - private Resources resources = new Resources(this); + private Resources resources; private String updateVersion = "Error"; private boolean needsUpdate = false; @@ -36,9 +36,11 @@ public class Game extends JavaPlugin implements Listener { @Override public void onEnable() { - + + Toolkit.printToConsole("&7[&b&lKIT-PVP&7] &7Enabling &bKitPvP &7version &b" + this.getDescription().getVersion() + "&7..."); + instance = this; - resources.load(); + resources = new Resources(this); prefix = resources.getMessages().getString("Messages.General.Prefix"); database = new Infobase(this); arena = new Arena(this, resources); @@ -65,34 +67,28 @@ public class Game extends JavaPlugin implements Listener { getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); getCommand("kitpvp").setExecutor(new MainCommand(this)); - - Bukkit.getConsoleSender().sendMessage(Toolkit.translate("&7[&b&lKIT-PVP&7] &7Enabling &bKitPvP &7version &b" + this.getDescription().getVersion() + "&7...")); new Metrics(this); new BukkitRunnable() { - @Override public void run() { - checkUpdate(); - } - }.runTaskAsynchronously(this); if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { - Bukkit.getConsoleSender().sendMessage(Toolkit.translate("[&b&lKIT-PVP&7] &7Discovered &bPlaceholderAPI&7, now hooking into it.")); + Bukkit.getConsoleSender().sendMessage(Toolkit.translate("[&b&lKIT-PVP&7] &7Hooking into &bPlaceholderAPI&7...")); new Placeholders(this).register(); hasPlaceholderAPI = true; } if (Bukkit.getPluginManager().isPluginEnabled("WorldGuard")) { - Bukkit.getConsoleSender().sendMessage(Toolkit.translate("[&b&lKIT-PVP&7] &7Discovered &bWorldGuard&7, now hooking into it.")); + Bukkit.getConsoleSender().sendMessage(Toolkit.translate("[&b&lKIT-PVP&7] &7Hooking into &bWorldGuard&7...")); hasWorldGuard = true; } - - Bukkit.getConsoleSender().sendMessage(Toolkit.translate("&7[&b&lKIT-PVP&7] &aDone!")); + + Toolkit.printToConsole("&7[&b&lKIT-PVP&7] &aDone!"); } diff --git a/src/main/java/com/planetgallium/kitpvp/game/Arena.java b/src/main/java/com/planetgallium/kitpvp/game/Arena.java index 84c2877..4f50ff8 100644 --- a/src/main/java/com/planetgallium/kitpvp/game/Arena.java +++ b/src/main/java/com/planetgallium/kitpvp/game/Arena.java @@ -27,10 +27,10 @@ public class Arena { private final Map hitCache; + private final Leaderboards leaderboards; private final Stats stats; private final Kits kits; private final KillStreaks killstreaks; - private final Levels levels; private final Cooldowns cooldowns; private final Menus menus; @@ -43,10 +43,10 @@ public class Arena { this.hitCache = new HashMap<>(); - this.stats = new Stats(plugin); + this.leaderboards = new Leaderboards(plugin); + this.stats = new Stats(plugin, this); this.kits = new Kits(plugin, this); this.killstreaks = new KillStreaks(resources); - this.levels = new Levels(this, resources); this.cooldowns = new Cooldowns(plugin); this.menus = new Menus(resources); } @@ -197,11 +197,11 @@ public class Arena { text = PlaceholderAPI.setPlaceholders(p, text); } - return replacePlaceholderIfPresent(text, p.getName(), p.getUniqueId().toString()); + return replacePlaceholderIfPresent(text, p.getName()); } - public String replacePlaceholderIfPresent(String s, String username, String uuid) { + public String replacePlaceholderIfPresent(String s, String username) { // The reason I'm doing all these if statements rather than a more concise code solution is to reduce // the amount of data that is unnecessarily fetched (ex by using .replace) to improve performance @@ -216,11 +216,11 @@ public class Arena { } if (s.contains("%xp%")) { - s = s.replace("%xp%", String.valueOf(getLevels().getExperience(uuid))); + s = s.replace("%xp%", String.valueOf(stats.getStat("experience", username))); } if (s.contains("%level%")) { - s = s.replace("%level%", String.valueOf(levels.getLevel(uuid))); + s = s.replace("%level%", String.valueOf(stats.getStat("level", username))); } if (s.contains("%max_xp%")) { @@ -232,15 +232,15 @@ public class Arena { } if (s.contains("%kd%")) { - s = s.replace("%kd%", String.valueOf(getStats().getKDRatio(uuid))); + s = s.replace("%kd%", String.valueOf(getStats().getKDRatio(username))); } if (s.contains("%kills%")) { - s = s.replace("%kills%", String.valueOf(getStats().getKills(uuid.toString()))); + s = s.replace("%kills%", String.valueOf(stats.getStat("kills", username))); } if (s.contains("%deaths%")) { - s = s.replace("%deaths%", String.valueOf(getStats().getDeaths(uuid))); + s = s.replace("%deaths%", String.valueOf(stats.getStat("deaths", username))); } if (s.contains("%kit%")) { @@ -282,13 +282,13 @@ public class Arena { public Map getHitCache() { return hitCache; } public Stats getStats() { return stats; } + + public Leaderboards getLeaderboards() { return leaderboards; } public Kits getKits() { return kits; } public KillStreaks getKillStreaks() { return killstreaks; } - public Levels getLevels() { return levels; } - public Cooldowns getCooldowns() { return cooldowns; } public Menus getMenus() { return menus; } diff --git a/src/main/java/com/planetgallium/kitpvp/game/Cooldowns.java b/src/main/java/com/planetgallium/kitpvp/game/Cooldowns.java index 8000940..85f885d 100644 --- a/src/main/java/com/planetgallium/kitpvp/game/Cooldowns.java +++ b/src/main/java/com/planetgallium/kitpvp/game/Cooldowns.java @@ -22,9 +22,8 @@ public class Cooldowns { CacheManager.getPlayerAbilityCooldowns(playerName).put(abilityName, (System.currentTimeMillis() / 1000)); } - public void setKitCooldown(UUID uuid, String kitName) { - database.setData(kitName + "_cooldowns", "last_used", (System.currentTimeMillis() / 1000), DataType.INTEGER, uuid.toString()); - System.out.println("Done"); + public void setKitCooldown(String username, String kitName) { + database.setData(kitName + "_cooldowns", "last_used", (System.currentTimeMillis() / 1000), DataType.INTEGER, username); } public Cooldown getRemainingCooldown(Player p, Object type) { @@ -39,7 +38,7 @@ public class Cooldowns { Kit kit = (Kit) type; if (kit.getCooldown() == null) return noCooldown; - Object timeLastUsedResult = database.getData(kit.getName() + "_cooldowns", "last_used", p.getUniqueId().toString()); + Object timeLastUsedResult = database.getData(kit.getName() + "_cooldowns", "last_used", p.getName()); if (timeLastUsedResult != null) { timeLastUsedSeconds = (int) timeLastUsedResult; } else { diff --git a/src/main/java/com/planetgallium/kitpvp/game/Infobase.java b/src/main/java/com/planetgallium/kitpvp/game/Infobase.java index c1aa0eb..e793766 100644 --- a/src/main/java/com/planetgallium/kitpvp/game/Infobase.java +++ b/src/main/java/com/planetgallium/kitpvp/game/Infobase.java @@ -1,9 +1,7 @@ package com.planetgallium.kitpvp.game; import com.planetgallium.kitpvp.Game; -import com.planetgallium.kitpvp.util.Resource; -import com.planetgallium.kitpvp.util.Resources; -import com.planetgallium.kitpvp.util.Toolkit; +import com.planetgallium.kitpvp.util.*; import com.zp4rker.localdb.Column; import com.zp4rker.localdb.DataType; import com.zp4rker.localdb.Database; @@ -20,9 +18,13 @@ public class Infobase { private final Database database; private final Map kitCooldownTables; - // TODO: add cooldown table when kit is created - // TODO: eventually fork localDB and add these helper methods ig? - // TODO: use this to make leaderboards (use table.search for a kills column for example) + // TODO: implement database plan as specified via email + // TODO: possibly build some of these methods into Table, or Database? maybe publish separately + // TODO: as your own but with original credits to use in future projects or help other ppl? + // TODO: caching for levels in stats fetching? That way when players are talking in chat + // the level isn't constantly being fetche dform the database + // TODO: fix needing to provide username and UUID in parameters. It should only be username, and then translated + // to UUID in the final fetch stages that get in this class public Infobase(Game plugin) { @@ -57,7 +59,7 @@ public class Infobase { public void createPlayerStats(Player p) { - if (databaseTableContainsUUID("stats", p.getUniqueId().toString())) { + if (databaseTableContainsPlayer("stats", p.getName())) { return; } @@ -102,7 +104,12 @@ public class Infobase { deaths.setValue(playerSection.getInt("Deaths")); experience.setValue(playerSection.getInt("Experience")); level.setValue(playerSection.getInt("Level")); - statsTable.insert(uuidColumn, username, kills, deaths, experience, level); + + if (statsTable.containsColumn(uuidColumn)) { + statsTable.update(uuidColumn, username, kills, deaths, experience, level); + } else { + statsTable.insert(uuidColumn, username, kills, deaths, experience, level); + } } statsResource.getFile().delete(); @@ -125,11 +132,13 @@ public class Infobase { cleanupUnusedKitCooldownTables(); } - public boolean databaseTableContainsUUID(String tableName, String uuid) { + public boolean databaseTableContainsPlayer(String tableName, String username) { Table table = getTableByName(tableName); if (table == null) return false; + String uuid = usernameToUUID(username); + Column uuidColumn = new Column("uuid", DataType.STRING, 0); uuidColumn.setValue(uuid); @@ -137,22 +146,48 @@ public class Infobase { } - public String usernameToUUID(String tableName, String username) { + public String usernameToUUID(String username) { - Table table = getTableByName(tableName); - if (table == null) return null; - - Column usernameColumn = new Column("username", DataType.STRING); - usernameColumn.setValue(username); - - List> results = table.search(usernameColumn); - if (results.size() > 0 && results.get(0).size() > 0) { - return (String) table.search(usernameColumn).get(0).get(0).getValue(); - } - return null; + return CacheManager.getUUIDCache().get(username); } +// public String usernameToUUID(String tableName, String username) { +// +// // make cache for this in CacheManager hashmap? +// +// Table table = getTableByName(tableName); +// if (table == null) return null; +// +// Column usernameColumn = new Column("username", DataType.STRING); +// usernameColumn.setValue(username); +// +// List> results = table.search(usernameColumn); +// if (results.size() > 0 && results.get(0).size() > 0) { +// return (String) table.search(usernameColumn).get(0).get(0).getValue(); +// } +// return null; +// +// } + +// public String uuidToUsername(String tableName, String uuid) { +// +// // make cache for this? +// +// Table table = getTableByName(tableName); +// if (table == null) return null; +// +// Column uuidColumn = new Column("uuid", DataType.STRING); +// uuidColumn.setValue(uuid); +// +// List> results = table.search(uuidColumn); +// if (results.size() > 0 && results.get(0).size() > 0) { +// return (String) table.search(uuidColumn).get(0).get(1).getValue(); +// } +// return null; +// +// } + public void cleanupUnusedKitCooldownTables() { for (Table table : database.getTables()) { @@ -167,11 +202,11 @@ public class Infobase { } - public String getTopNStat(int n, String identifier) { + public List getTopNStats(String identifier, int n) { - // update topN results when a player dies + Column usernameColumn = new Column("username", DataType.STRING); Column numberColumn = new Column(identifier, DataType.INTEGER); - return getTableByName("stats").getTopN(numberColumn, n).get(n - 1); + return getTableByName("stats").getTopN(numberColumn, usernameColumn, n); } @@ -216,18 +251,20 @@ public class Infobase { } - public void setData(String tableName, String identifier, Object data, DataType type, String uuid) { + public void setData(String tableName, String identifier, Object data, DataType type, String username) { Table table = getTableByName(tableName); if (table == null) return; + String uuid = usernameToUUID(username); + Column dataColumn = new Column(identifier.toLowerCase(), type, 0); dataColumn.setValue(data); Column uuidColumn = new Column("uuid", DataType.STRING, 0); uuidColumn.setValue(uuid); - if (databaseTableContainsUUID(tableName, uuid)) { + if (databaseTableContainsPlayer(tableName, uuid)) { table.update(uuidColumn, dataColumn); } else { table.insert(uuidColumn, dataColumn); @@ -235,9 +272,11 @@ public class Infobase { } - public Object getData(String tableName, String identifier, String uuid) { + public Object getData(String tableName, String identifier, String username) { - if (databaseTableContainsUUID(tableName, uuid)) { + String uuid = usernameToUUID(username); + + if (databaseTableContainsPlayer(tableName, username)) { return getColumnByName(tableName, identifier, uuid).getValue(); } return null; diff --git a/src/main/java/com/planetgallium/kitpvp/game/Kits.java b/src/main/java/com/planetgallium/kitpvp/game/Kits.java index d2395b4..24c2562 100644 --- a/src/main/java/com/planetgallium/kitpvp/game/Kits.java +++ b/src/main/java/com/planetgallium/kitpvp/game/Kits.java @@ -195,7 +195,7 @@ public class Kits { } if (!(Toolkit.getPermissionAmount(p, "kp.levelbypass.", 0) >= kit.getLevel() || - arena.getLevels().getLevel(p.getUniqueId().toString()) >= kit.getLevel())) { + arena.getStats().getStat("level", p.getName()) >= kit.getLevel())) { p.sendMessage(messages.getString("Messages.Other.Needed").replace("%level%", String.valueOf(kit.getLevel()))); return; } @@ -226,7 +226,7 @@ public class Kits { Cooldown kitCooldown = kit.getCooldown(); if (kitCooldown != null && kitCooldown.toSeconds() > 0 && !p.hasPermission("kp.cooldownbypass")) { - arena.getCooldowns().setKitCooldown(p.getUniqueId(), kit.getName()); + arena.getCooldowns().setKitCooldown(p.getName(), kit.getName()); } Resource kitResource = resources.getKit(kit.getName()); diff --git a/src/main/java/com/planetgallium/kitpvp/game/Leaderboards.java b/src/main/java/com/planetgallium/kitpvp/game/Leaderboards.java new file mode 100644 index 0000000..b3b1ea1 --- /dev/null +++ b/src/main/java/com/planetgallium/kitpvp/game/Leaderboards.java @@ -0,0 +1,127 @@ +package com.planetgallium.kitpvp.game; + +import com.planetgallium.kitpvp.Game; +import com.planetgallium.kitpvp.util.PlayerEntry; +import com.planetgallium.kitpvp.util.Toolkit; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Leaderboards { + + private final Infobase database; + private final Map> leaderboards; + + public Leaderboards(Game plugin) { + this.database = plugin.getDatabase(); + this.leaderboards = new HashMap<>(); + + Toolkit.printToConsole("&7[&b&lKIT-PVP&7] &7Loading Leaderboard caches...."); + registerCache("kills", 25); + registerCache("deaths", 25); + registerCache("level", 25); + } + + private void registerCache(String key, int size) { + leaderboards.put(key, new ArrayList<>()); + leaderboards.get(key).addAll(database.getTopNStats(key, size)); + } + + public void updateCache(String key, PlayerEntry playerEntry) { + + if (!isValidCacheType(key)) return; + + List leaderboard = getLeaderboard(key); + PlayerEntry lowestRankingPlayer = leaderboard.get(leaderboard.size() - 1); + + // If updated player entry has a higher data value than the lowest ranking player in a leaderboard + if (playerEntry.getData() > lowestRankingPlayer.getData()) { + if (!cacheContainsPlayer(leaderboard, playerEntry.getUsername())) { + // If not already in the leaderboard, add them + leaderboard.add(playerEntry); + } else { + // If already in the leaderboard, update their player entry with the latest data + updatePlayerEntry(leaderboard, playerEntry); + } + // Sort the leaderboard based on the new insertion / data + insertionSort(leaderboard); + } else { + // If updated player entry does not have a higher data value than the lowest ranking player in the leaderboard + if (cacheContainsPlayer(leaderboard, playerEntry.getUsername())) { + // If they are in the leaderboard, remove them and resort + removePlayerFromCache(leaderboard, playerEntry.getUsername()); + insertionSort(leaderboard); // idk if this sort is necessary + } + } + + } + + private boolean isValidCacheType(String identifier) { + return identifier.equals("kills") || identifier.equals("deaths") || identifier.equals("level"); + } + + private boolean cacheContainsPlayer(List leaderboard, String username) { + + for (PlayerEntry entry : leaderboard) { + if (entry.getUsername().equals(username)) { + return true; + } + } + return false; + + } + + private void updatePlayerEntry(List leaderboard, PlayerEntry playerEntry) { + + for (PlayerEntry entry : leaderboard) { + if (entry.getUsername().equals(playerEntry.getUsername())) { + entry.setData(playerEntry.getData()); + break; + } + } + + } + + private void removePlayerFromCache(List leaderboard, String username) { + + for (PlayerEntry entry : leaderboard) { + if (entry.getUsername().equals(username)) { + leaderboard.remove(entry); + break; + } + } + + } + + private void insertionSort(List leaderboard) { + + for (int i = 1; i < leaderboard.size(); ++i) { + PlayerEntry currentEntry = leaderboard.get(i); + int j = i - 1; + + while (j >= 0 && leaderboard.get(j).getData() < currentEntry.getData()) { + leaderboard.set(j + 1, leaderboard.get(j)); + j -= 1; + } + + leaderboard.set(j + 1, currentEntry); + } + + } + + public PlayerEntry getTopN(String key, int rank) { + + List leaderboard = getLeaderboard(key); + int rankIndex = rank - 1; + + return rankIndex < leaderboard.size() ? leaderboard.get(rankIndex) : new PlayerEntry("N / A", 0); + + } + + private List getLeaderboard(String key) { + return leaderboards.get(key); + } + +} diff --git a/src/main/java/com/planetgallium/kitpvp/game/Levels.java b/src/main/java/com/planetgallium/kitpvp/game/Levels.java deleted file mode 100644 index fafd8c0..0000000 --- a/src/main/java/com/planetgallium/kitpvp/game/Levels.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.planetgallium.kitpvp.game; - -import java.util.List; - -import com.cryptomorin.xseries.XSound; -import com.planetgallium.kitpvp.util.Resource; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - -import com.planetgallium.kitpvp.api.PlayerLevelUpEvent; -import com.planetgallium.kitpvp.util.Resources; -import com.planetgallium.kitpvp.util.Toolkit; - -public class Levels { - - private final Arena arena; - private final Resources resources; - private final Resource levels; - - public Levels(Arena arena, Resources resources) { - this.arena = arena; - this.resources = resources; - this.levels = resources.getLevels(); - } - - public void addExperience(Player p, int experience) { - - if (levels.getBoolean("Levels.Levels.Enabled")) { - - arena.getStats().addExperience(p.getUniqueId().toString(), experience); - - if (arena.getLevels().getExperience(p.getUniqueId().toString()) >= levels.getInt("Levels.Options.Experience-To-Level-Up")) { - - arena.getLevels().levelUp(p); - Bukkit.getPluginManager().callEvent(new PlayerLevelUpEvent(p, getLevel(p.getUniqueId().toString()))); - - } - - } - - } - - public void removeExperience(Player p, int experience) { - - if (levels.getBoolean("Levels.Levels.Enabled")) { - - arena.getStats().removeExperience(p.getUniqueId().toString(), experience); - - } - - } - - public void levelUp(Player p) { - - if (arena.getStats().getLevel(p.getUniqueId().toString()) != levels.getInt("Levels.Options.Maximum-Level")) { - - arena.getStats().setLevel(p.getUniqueId().toString(), arena.getLevels().getLevel(p.getUniqueId().toString()) + 1); - arena.getStats().setExperience(p.getUniqueId().toString(), 0); - - String newLevel = String.valueOf(getLevel(p.getUniqueId().toString())); - - List levelUpCommands = levels.getStringList("Levels.Commands-On-Level-Up"); - Toolkit.runCommands(p, levelUpCommands, "%level%", newLevel); - - if (levels.contains("Levels.Levels." + newLevel + ".Commands")) { - List commandsList = levels.getStringList("Levels.Levels." + newLevel + ".Commands"); - Toolkit.runCommands(p, commandsList, "%level%", newLevel); - } - - p.sendMessage(resources.getMessages().getString("Messages.Other.Level").replace("%level%", newLevel)); - p.playSound(p.getLocation(), XSound.ENTITY_PLAYER_LEVELUP.parseSound(), 1, 1); - - } else { - - arena.getStats().setExperience(p.getUniqueId().toString(), 0); - - } - - } - - public int getLevel(String uuid) { - return arena.getStats().getLevel(uuid); - } - - public int getExperience(String uuid) { - return arena.getStats().getExperience(uuid); - } - -} diff --git a/src/main/java/com/planetgallium/kitpvp/game/Stats.java b/src/main/java/com/planetgallium/kitpvp/game/Stats.java index 630dfa2..fb74aaa 100644 --- a/src/main/java/com/planetgallium/kitpvp/game/Stats.java +++ b/src/main/java/com/planetgallium/kitpvp/game/Stats.java @@ -1,90 +1,107 @@ package com.planetgallium.kitpvp.game; +import com.cryptomorin.xseries.XSound; import com.planetgallium.kitpvp.Game; -import com.planetgallium.kitpvp.util.Toolkit; +import com.planetgallium.kitpvp.api.PlayerLevelUpEvent; +import com.planetgallium.kitpvp.util.*; import com.zp4rker.localdb.DataType; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import java.util.List; + public class Stats { private final Infobase database; + private final Resources resources; + private final Resource levels; + private final Leaderboards leaderboards; - public Stats(Game plugin) { + public Stats(Game plugin, Arena arena) { this.database = plugin.getDatabase(); + this.resources = plugin.getResources(); + this.levels = plugin.getResources().getLevels(); + this.leaderboards = arena.getLeaderboards(); } public void createPlayer(Player p) { - if (!isPlayerRegistered(p.getUniqueId().toString())) { + CacheManager.getUUIDCache().put(p.getName(), p.getUniqueId().toString()); + if (!isPlayerRegistered(p.getName())) { database.createPlayerStats(p); } } - public boolean isPlayerRegistered(String uuid) { - return database.databaseTableContainsUUID("stats", uuid); + public boolean isPlayerRegistered(String username) { + return database.databaseTableContainsPlayer("stats", username); } - public double getKDRatio(String uuid) { - if (getDeaths(uuid) != 0) { - double divided = (double) getKills(uuid) / getDeaths(uuid); + public double getKDRatio(String username) { + if (getStat("deaths", username) != 0) { + double divided = (double) getStat("kills", username) / getStat("deaths", username); return Toolkit.round(divided, 2); } return 0.00; } - public void addKills(String uuid, int amount) { - setKills(uuid, getKills(uuid) + amount); + public void removeExperience(String username, int amount) { + if (levels.getBoolean("Levels.Levels.Enabled") && isPlayerRegistered(username)) { + int currentExperience = getStat("experience", username); + setStat("experience", username, currentExperience >= amount ? currentExperience - amount : 0); + } } - public void addDeaths(String uuid, int amount) { - setDeaths(uuid, getDeaths(uuid) + amount); - } - - public void addExperience(String uuid, int amount) { - setExperience(uuid, getExperience(uuid) + amount); - } - - public void removeExperience(String uuid, int amount) { - if (isPlayerRegistered(uuid)) { - if (getExperience(uuid) > amount) { - setExperience(uuid, getExperience(uuid) - amount); + public void addExperience(Player p, int experience) { + if (levels.getBoolean("Levels.Levels.Enabled")) { + setStat("experience", p.getName(), experience); + if (getStat("experience", p.getName()) >= levels.getInt("Levels.Options.Experience-To-Level-Up")) { + levelUp(p); + Bukkit.getPluginManager().callEvent(new PlayerLevelUpEvent(p, getStat("level", p.getName()))); } } } - public void setKills(String uuid, int kills) { - if (!database.databaseTableContainsUUID("stats", uuid)) return; - database.setData("stats", "kills", kills, DataType.INTEGER, uuid); + public void levelUp(Player p) { + + String username = p.getName(); + + if (getStat("level", username) < levels.getInt("Levels.Options.Maximum-Level")) { + + int newLevel = getStat("level", username) + 1; + setStat("level", username, newLevel); + setStat("experience", username, 0); + + List levelUpCommands = levels.getStringList("Levels.Commands-On-Level-Up"); + Toolkit.runCommands(p, levelUpCommands, "%level%", String.valueOf(newLevel)); + + if (levels.contains("Levels.Levels." + newLevel + ".Commands")) { + List commandsList = levels.getStringList("Levels.Levels." + newLevel + ".Commands"); + Toolkit.runCommands(p, commandsList, "%level%", String.valueOf(newLevel)); + } + + p.sendMessage(resources.getMessages().getString("Messages.Other.Level") + .replace("%level%", String.valueOf(newLevel))); + XSound.play(p, "ENTITY_PLAYER_LEVELUP, 1, 1"); + + } else { + setStat("experience", username, 0); + } + } - public void setDeaths(String uuid, int deaths) { - if (!database.databaseTableContainsUUID("stats", uuid)) return; - database.setData("stats", "deaths", deaths, DataType.INTEGER, uuid); + public void addToStat(String identifier, String username, int amount) { + int updatedAmount = (int) database.getData("stats", identifier, username) + amount; + setStat(identifier, username, updatedAmount); } - public void setExperience(String uuid, int experience) { - if (!database.databaseTableContainsUUID("stats", uuid)) return; - database.setData("stats", "experience", experience, DataType.INTEGER, uuid); + public void setStat(String identifier, String username, int data) { + // valid identifier: "kills", "deaths", "level", "experience" + if (!database.databaseTableContainsPlayer("stats", username)) return; + database.setData("stats", identifier, data, DataType.INTEGER, username); + leaderboards.updateCache(identifier, new PlayerEntry(username, data)); } - public void setLevel(String uuid, int level) { - if (!database.databaseTableContainsUUID("stats", uuid)) return; - database.setData("stats", "level", level, DataType.INTEGER, uuid); - } - - public int getKills(String uuid) { - return (int) database.getData("stats", "kills", uuid); - } - - public int getDeaths(String uuid) { - return (int) database.getData("stats", "deaths", uuid); - } - - public int getExperience(String uuid) { - return (int) database.getData("stats", "experience", uuid); - } - - public int getLevel(String uuid) { - return (int) database.getData("stats", "level", uuid); + public int getStat(String identifier, String username) { + return (int) database.getData("stats", identifier, username); } } diff --git a/src/main/java/com/planetgallium/kitpvp/listener/ChatListener.java b/src/main/java/com/planetgallium/kitpvp/listener/ChatListener.java index 58bcfbd..84f10ac 100644 --- a/src/main/java/com/planetgallium/kitpvp/listener/ChatListener.java +++ b/src/main/java/com/planetgallium/kitpvp/listener/ChatListener.java @@ -27,7 +27,7 @@ public class ChatListener implements Listener { Player p = e.getPlayer(); - String playerLevel = String.valueOf(arena.getLevels().getLevel(p.getUniqueId().toString())); + String playerLevel = String.valueOf(arena.getStats().getStat("level", p.getName())); String levelPrefix = resources.getLevels().getString("Levels.Levels." + playerLevel + ".Prefix") .replace("%level%", playerLevel); diff --git a/src/main/java/com/planetgallium/kitpvp/listener/DeathListener.java b/src/main/java/com/planetgallium/kitpvp/listener/DeathListener.java index 05c7b89..bc6f2c2 100644 --- a/src/main/java/com/planetgallium/kitpvp/listener/DeathListener.java +++ b/src/main/java/com/planetgallium/kitpvp/listener/DeathListener.java @@ -54,8 +54,8 @@ public class DeathListener implements Listener { setDeathMessage(victim); respawnPlayer(victim); - arena.getStats().addDeaths(victim.getUniqueId().toString(), 1); - arena.getLevels().removeExperience(victim, resources.getLevels().getInt("Levels.Options.Experience-Taken-On-Death")); + arena.getStats().addToStat("deaths", victim.getName(), 1); + arena.getStats().removeExperience(victim.getName(), resources.getLevels().getInt("Levels.Options.Experience-Taken-On-Death")); if (config.getBoolean("Arena.DeathParticle")) { victim.getWorld().playEffect(victim.getLocation().add(0.0D, 1.0D, 0.0D), Effect.STEP_SOUND, 152); @@ -267,8 +267,8 @@ public class DeathListener implements Listener { if (!victim.getName().equals(killer.getName())) { - arena.getStats().addKills(killer.getUniqueId().toString(), 1); - arena.getLevels().addExperience(killer, resources.getLevels().getInt("Levels.Options.Experience-Given-On-Kill")); + arena.getStats().addToStat("kills", killer.getName(), 1); + arena.getStats().addExperience(killer, resources.getLevels().getInt("Levels.Options.Experience-Given-On-Kill")); List killCommands = config.getStringList("Kill.Commands"); killCommands = Toolkit.replaceInList(killCommands, "%victim%", victim.getName()); diff --git a/src/main/java/com/planetgallium/kitpvp/util/CacheManager.java b/src/main/java/com/planetgallium/kitpvp/util/CacheManager.java index 40c15c0..af19f44 100644 --- a/src/main/java/com/planetgallium/kitpvp/util/CacheManager.java +++ b/src/main/java/com/planetgallium/kitpvp/util/CacheManager.java @@ -6,12 +6,15 @@ import java.util.*; public class CacheManager { + private static Map usernameToUUID = new HashMap<>(); private static Map kitCache = new HashMap<>(); private static Map previewMenuCache = new HashMap<>(); private static List compassUsers = new ArrayList<>(); private static Map> abilityCooldowns = new HashMap<>(); private static Set witchPotionUsers = new HashSet<>(); + public static Map getUUIDCache() { return usernameToUUID; } + public static Map getKitCache() { return kitCache; } public static Map getPreviewMenuCache() { return previewMenuCache; } diff --git a/src/main/java/com/planetgallium/kitpvp/util/Placeholders.java b/src/main/java/com/planetgallium/kitpvp/util/Placeholders.java index e29f4e1..1e576d1 100644 --- a/src/main/java/com/planetgallium/kitpvp/util/Placeholders.java +++ b/src/main/java/com/planetgallium/kitpvp/util/Placeholders.java @@ -1,6 +1,7 @@ package com.planetgallium.kitpvp.util; import com.planetgallium.kitpvp.Game; +import org.apache.commons.lang.StringUtils; import org.bukkit.entity.Player; import com.planetgallium.kitpvp.game.Arena; @@ -8,8 +9,8 @@ import me.clip.placeholderapi.expansion.PlaceholderExpansion; public class Placeholders extends PlaceholderExpansion { - private Arena arena; - private Resources resources; + private final Arena arena; + private final Resources resources; public Placeholders(Game plugin) { this.arena = plugin.getArena(); @@ -18,59 +19,62 @@ public class Placeholders extends PlaceholderExpansion { @Override public String onPlaceholderRequest(Player p, String identifier) { - - if (p != null) { - - switch (identifier) { - case "stats_kills": return String.valueOf(arena.getStats().getKills(p.getUniqueId())); - case "stats_deaths": return String.valueOf(arena.getStats().getDeaths(p.getUniqueId())); - case "stats_kdr": return String.valueOf(arena.getStats().getKDRatio(p.getUniqueId())); - case "stats_level": return String.valueOf(arena.getLevels().getLevel(p.getUniqueId())); - case "stats_experience": return String.valueOf(arena.getLevels().getExperience(p.getUniqueId())); - case "player_killstreak": return String.valueOf(arena.getKillStreaks().getStreak(p.getName())); + if (p == null) return null; + + if (identifier.contains("top")) { + + String[] queries = identifier.split("_"); + String topType = queries[1]; // ex: kills + String topIdentifier = queries[2]; // ex: amount, player + String possibleTopValue = queries[3]; // 1, 15 + int topValue = 1; + + if (StringUtils.isNumeric(possibleTopValue)) { + topValue = Integer.parseInt(possibleTopValue); + } else { + Toolkit.printToConsole("%prefix% &cFailed to properly parse placeholder, expected number but received: " + possibleTopValue); + } + + PlayerEntry entry = arena.getLeaderboards().getTopN(topType, topValue); + boolean isUsernamePlaceholder = topIdentifier.equals("player"); + + return isUsernamePlaceholder ? entry.getUsername() : String.valueOf(entry.getData()); + + } else { + String username = p.getName(); + + switch (identifier) { + case "stats_kills": return String.valueOf(arena.getStats().getStat("kills", username)); + case "stats_deaths": return String.valueOf(arena.getStats().getStat("deaths", username)); + case "stats_kdr": return String.valueOf(arena.getStats().getKDRatio(username)); + case "stats_level": return String.valueOf(arena.getStats().getStat("level", username)); + case "stats_experience": return String.valueOf(arena.getStats().getStat("experience", username)); + case "player_killstreak": return String.valueOf(arena.getKillStreaks().getStreak(username)); case "player_kit": - if (arena.getKits().hasKit(p.getName())) { - return arena.getKits().getKitOfPlayer(p.getName()).getName(); + if (arena.getKits().hasKit(username)) { + return arena.getKits().getKitOfPlayer(username).getName(); } return resources.getMessages().getString("Messages.Other.NoKit"); case "max_level": return String.valueOf(resources.getLevels().getInt("Levels.Options.Maximum-Level")); case "max_xp": return String.valueOf(resources.getLevels().getInt("Levels.Options.Experience-To-Level-Up")); - } - } - + return null; } @Override - public boolean canRegister() { - - return true; - - } + public boolean canRegister() { return true; } @Override - public String getAuthor() { - - return "Cervinakuy"; - - } + public String getAuthor() { return "Cervinakuy"; } @Override - public String getIdentifier() { - - return "kitpvp"; - - } + public String getIdentifier() { return "kitpvp"; } @Override - public String getVersion() { - - return "1.0.0"; - - } + public String getVersion() { return "1.0.0"; } } diff --git a/src/main/java/com/planetgallium/kitpvp/util/PlayerEntry.java b/src/main/java/com/planetgallium/kitpvp/util/PlayerEntry.java new file mode 100644 index 0000000..bde916e --- /dev/null +++ b/src/main/java/com/planetgallium/kitpvp/util/PlayerEntry.java @@ -0,0 +1,23 @@ +package com.planetgallium.kitpvp.util; + +public class PlayerEntry { + + private final String username; + private int data; + + public PlayerEntry(String username, int data) { + this.username = username; + this.data = data; + } + + @Override + public String toString() { + return String.format("Player(%s, %s)", username, data); + } + + public void setData(int newData) { this.data = newData; } + + public String getUsername() { return username; } + public int getData() { return data; } + +} diff --git a/src/main/java/com/zp4rker/localdb/Table.java b/src/main/java/com/zp4rker/localdb/Table.java index 851c196..d02c8b6 100644 --- a/src/main/java/com/zp4rker/localdb/Table.java +++ b/src/main/java/com/zp4rker/localdb/Table.java @@ -6,7 +6,9 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; +import com.planetgallium.kitpvp.util.PlayerEntry; import com.zp4rker.localdb.db.SQLite; public class Table { @@ -159,12 +161,30 @@ public class Table { return result; } - public List getTopN(Column column, int n) { - // will return an ordered list of usernames - // (0) Shredder72 - 700 - // (1) cervinakuy - 600 - // etc. - return null; + public List getTopN(Column sortColumn, Column returnColumn, int n) { + // Admittedly this method is more tailored towards KitPvP leaderboards, but can be repurposed for other uses + String query = "SELECT %return_column_name%, %sort_column_name% FROM %table_name% ORDER BY %sort_column_name% DESC LIMIT %n%" + .replace("%return_column_name%", returnColumn.getName()) + .replace("%table_name%", getName()) + .replace("%sort_column_name%", sortColumn.getName()) + .replace("%n%", String.valueOf(n)); + List topNResults = new ArrayList<>(); + + try { + PreparedStatement statement = sqLite.getSQLConnection().prepareStatement(query); + ResultSet resultSet = statement.executeQuery(); + + while (resultSet.next()) { + topNResults.add(new PlayerEntry(resultSet.getString(returnColumn.getName()), + resultSet.getInt(sortColumn.getName()))); + } + sqLite.close(statement, resultSet); + + } catch (SQLException e) { + e.printStackTrace(); + } + + return topNResults; } public List> search(Column column) {