From 86a15d29fdf30e491eb0b711c4132720ef9488ba Mon Sep 17 00:00:00 2001 From: Efnilite Date: Mon, 4 Jan 2021 17:38:41 +0100 Subject: [PATCH] Add leaderboard and fence jumps --- .../java/dev/efnilite/witp/ParkourPlayer.java | 132 ++++++++++++++++-- .../efnilite/witp/command/MainCommand.java | 10 +- .../witp/generator/ParkourGenerator.java | 22 ++- .../generator/subarea/SubareaDivider.java | 1 + .../efnilite/witp/hook/PlaceholderHook.java | 11 ++ .../java/dev/efnilite/witp/util/Util.java | 18 +++ src/main/resources/generation.yml | 3 +- src/main/resources/plugin.yml | 2 +- 8 files changed, 179 insertions(+), 20 deletions(-) diff --git a/src/main/java/dev/efnilite/witp/ParkourPlayer.java b/src/main/java/dev/efnilite/witp/ParkourPlayer.java index 0d778bec..d0f2a7e8 100644 --- a/src/main/java/dev/efnilite/witp/ParkourPlayer.java +++ b/src/main/java/dev/efnilite/witp/ParkourPlayer.java @@ -11,9 +11,11 @@ import dev.efnilite.witp.util.inventory.ItemBuilder; import dev.efnilite.witp.util.task.Tasks; import fr.mrmicky.fastboard.FastBoard; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.Material; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.*; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; @@ -59,7 +61,7 @@ public class ParkourPlayer { private final Player player; private final ParkourGenerator generator; private static final HashMap players = new HashMap<>(); - private static final HashMap highScores = new HashMap<>(); + private static HashMap highScores = new LinkedHashMap<>(); private static final Gson gson = new GsonBuilder().disableHtmlEscaping().excludeFieldsWithoutExposeAnnotation().create(); /** @@ -103,6 +105,15 @@ public ParkourPlayer(@NotNull Player player, int highScore, String time, String if (player.isOp() && WITP.isOutdated) { send("&4&l!!! &fThe WITP plugin version you are using is outdated. Please check the Spigot page for updates."); } + if (highScores.size() == 0) { + try { + fetchHighScores(); + } catch (IOException ex) { + ex.printStackTrace(); + Verbose.error("Error while trying to fetch the high scores!"); + } + highScores = Util.sortByValue(highScores); + } } @@ -185,7 +196,7 @@ public void setStyle(String style) { */ public void setHighScore(int score) { this.highScore = score; - highScores.put(score, player.getUniqueId()); + highScores.put(player.getUniqueId(), score); saveStats(); } @@ -327,6 +338,11 @@ public void menu() { saveStats(); player.closeInventory(); }); + builder.setItem(22, new ItemBuilder(Material.GOLD_BLOCK, "&6&lLeaderboard") + .setLore("&7Your rank: &f#" + getRank(player.getUniqueId()) + " &7(" + highScores.get(player.getUniqueId()) + ")").build(), (t2, e2) -> { + scoreboard(1); + player.closeInventory(); + }); builder.setItem(26, new ItemBuilder(Material.BARRIER, "&4&lQuit").build(), (t2, e2) -> { try { ParkourPlayer.unregister(this, true); @@ -405,6 +421,93 @@ public void send(@NotNull String... messages) { } } + /** + * Shows the scoreboard (as a chat message) + */ + public void scoreboard(int page) { + if (highScores.size() == 0) { + try { + fetchHighScores(); + } catch (IOException ex) { + ex.printStackTrace(); + Verbose.error("Error while trying to fetch the high scores!"); + } + } + + int lowest = page * 10; + int highest = (page - 1) * 10; + if (page < 1) { + return; + } + if (page > 1 && highest > highScores.size()) { + return; + } + + HashMap sorted = Util.sortByValue(highScores); + highScores = sorted; + List uuids = new ArrayList<>(sorted.keySet()); + + send("", "", "", "", "", "", "", ""); + send("&7----------------------------------------"); + for (int i = highest; i < lowest; i++) { + if (i == uuids.size()) { + break; + } + UUID uuid = uuids.get(i); + if (uuid == null) { + continue; + } + String name = Bukkit.getOfflinePlayer(uuid).getName(); + int rank = i + 1; + send("&c#" + rank + ". &7" + name + " &f- " + highScores.get(uuid)); + } + send("&7Your rank: &f#" + getRank(player.getUniqueId()) + " &7(" + highScores.get(player.getUniqueId()) + ")"); + send(""); + + int prevPage = page - 1; + int nextPage = page + 1; + BaseComponent[] previous = new ComponentBuilder() + .append("<< Previous page").color(net.md_5.bungee.api.ChatColor.RED) + .event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/witp leaderboard " + prevPage)) + .append(" | ").color(net.md_5.bungee.api.ChatColor.GRAY) + .event((ClickEvent) null) + .append("Next page >>").color(net.md_5.bungee.api.ChatColor.RED) + .event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/witp leaderboard " + nextPage)) + .create(); + + player.spigot().sendMessage(previous); + send("&7----------------------------------------"); + } + + /** + * Gets the high score of a player + * + * @param player + * The player + * + * @return the high score of the player + */ + public static int getHighScore(@NotNull UUID player) { + return highScores.get(player); + } + + /** + * Gets the player at a certain place + * Note: places are indicated in normal fashion (a.k.a. #1 is the first) + * + * @param place + * The place + * + * @return the player at that place + */ + public static UUID getAtPlace(int place) { + return new ArrayList<>(highScores.keySet()).get(place); + } + + private int getRank(UUID player) { + return new ArrayList<>(highScores.keySet()).indexOf(player) + 1; + } + /** * Registers a player * @@ -463,7 +566,8 @@ public static void fetchHighScores() throws IOException { for (File file : folder.listFiles()) { FileReader reader = new FileReader(file); ParkourPlayer from = gson.fromJson(reader, ParkourPlayer.class); - highScores.put(from.highScore, UUID.fromString(file.getName())); + String name = file.getName(); + highScores.put(UUID.fromString(name.substring(0, name.lastIndexOf('.'))), from.highScore); } } @@ -540,14 +644,6 @@ public static void unregister(@NotNull ParkourPlayer player, boolean sendBack) t } } - public HashMap getPreviousInventory() { - return previousInventory; - } - - public Location getPreviousLocation() { - return previousLocation; - } - /** * Gets the player's {@link ParkourGenerator} * @@ -565,4 +661,12 @@ public ParkourGenerator getGenerator() { public @NotNull Player getPlayer() { return player; } + + public HashMap getPreviousInventory() { + return previousInventory; + } + + public Location getPreviousLocation() { + return previousLocation; + } } diff --git a/src/main/java/dev/efnilite/witp/command/MainCommand.java b/src/main/java/dev/efnilite/witp/command/MainCommand.java index 10b17ef0..58847077 100644 --- a/src/main/java/dev/efnilite/witp/command/MainCommand.java +++ b/src/main/java/dev/efnilite/witp/command/MainCommand.java @@ -54,8 +54,16 @@ public boolean execute(Player player, String[] args) { pp.menu(); } } + } else if (args.length == 2) { + if (args[0].equalsIgnoreCase("leaderboard") && args[1] != null) { + int page = Integer.parseInt(args[1]); + ParkourPlayer pp = ParkourPlayer.getPlayer(player); + if (pp != null) { + pp.scoreboard(page); + } + } } - return false; + return true; } @Override diff --git a/src/main/java/dev/efnilite/witp/generator/ParkourGenerator.java b/src/main/java/dev/efnilite/witp/generator/ParkourGenerator.java index 0aeb420d..d39df8ee 100644 --- a/src/main/java/dev/efnilite/witp/generator/ParkourGenerator.java +++ b/src/main/java/dev/efnilite/witp/generator/ParkourGenerator.java @@ -18,6 +18,7 @@ import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.util.Vector; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.*; @@ -390,9 +391,13 @@ public void generateNext() { specialChances.put(index, 2); index++; } + for (int i = 0; i < Configurable.SPECIAL_FENCE; i++) { + specialChances.put(index, 3); + index++; + } } - int spec = specialChances.get(random.nextInt(specialChances.size() - 1)); + int spec = specialChances.get(random.nextInt(specialChances.size())); switch (spec) { case 0: // ice material = Material.PACKED_ICE.createBlockData(); @@ -400,20 +405,29 @@ public void generateNext() { break; case 1: // slab material = Material.SMOOTH_QUARTZ_SLAB.createBlockData(); - height = 0; // todo allow multiple heights + height = Math.min(height, 0); ((Slab) material).setType(Slab.Type.BOTTOM); break; case 2: // pane material = Material.GLASS_PANE.createBlockData(); gap -= 0.5; break; + case 3: + material = Material.OAK_FENCE.createBlockData(); + height = Math.min(height, 0); + gap -= 0.5; + break; } } Location local = lastSpawn.clone(); + if (local.getBlock().getType() == Material.SMOOTH_QUARTZ_SLAB) { + height = Math.min(height, 0); + } List possible = getPossible(gap - height, height); if (possible.size() == 0) { lastSpawn = local.clone(); + Verbose.error(lastSpawn.toString()); return; } @@ -451,7 +465,7 @@ public void generateNext() { Location local2 = lastSpawn.clone(); List possibleStructure = getPossible(gapStructure, 0); if (possibleStructure.size() == 0) { - lastSpawn = local2; + lastSpawn = local2.clone(); return; } Block chosenStructure = possibleStructure.get(random.nextInt(possibleStructure.size())); @@ -574,6 +588,7 @@ public static class Configurable { public static int SPECIAL_ICE; public static int SPECIAL_SLAB; public static int SPECIAL_PANE; + public static int SPECIAL_FENCE; public static int NORMAL_ONE_BLOCK; public static int NORMAL_TWO_BLOCK; @@ -622,6 +637,7 @@ public static void init() { SPECIAL_ICE = file.getInt("generation.normal-jump.special.ice"); SPECIAL_SLAB = file.getInt("generation.normal-jump.special.slab"); SPECIAL_PANE = file.getInt("generation.normal-jump.special.pane"); + SPECIAL_FENCE = file.getInt("generation.normal-jump.special.fence"); NORMAL_ONE_BLOCK = file.getInt("generation.normal-jump.1-block"); NORMAL_TWO_BLOCK = file.getInt("generation.normal-jump.2-block"); diff --git a/src/main/java/dev/efnilite/witp/generator/subarea/SubareaDivider.java b/src/main/java/dev/efnilite/witp/generator/subarea/SubareaDivider.java index 90308592..a25e9d79 100644 --- a/src/main/java/dev/efnilite/witp/generator/subarea/SubareaDivider.java +++ b/src/main/java/dev/efnilite/witp/generator/subarea/SubareaDivider.java @@ -203,6 +203,7 @@ private void fetchPossibleInLayer() { world.setGameRule(GameRule.DO_TILE_DROPS, false); world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false); world.setGameRule(GameRule.DO_WEATHER_CYCLE, false); + world.setGameRule(GameRule.LOG_ADMIN_COMMANDS, false); world.setWeatherDuration(1000); world.setDifficulty(Difficulty.PEACEFUL); world.setAutoSave(false); diff --git a/src/main/java/dev/efnilite/witp/hook/PlaceholderHook.java b/src/main/java/dev/efnilite/witp/hook/PlaceholderHook.java index 6955499b..0d938a97 100644 --- a/src/main/java/dev/efnilite/witp/hook/PlaceholderHook.java +++ b/src/main/java/dev/efnilite/witp/hook/PlaceholderHook.java @@ -3,6 +3,8 @@ import dev.efnilite.witp.ParkourPlayer; import dev.efnilite.witp.WITP; import me.clip.placeholderapi.expansion.PlaceholderExpansion; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -65,6 +67,15 @@ public String onPlaceholderRequest(Player player, @NotNull String params) { case "time_pref": case "time_preference": return pp.time; + case "leader": + case "rank_one": + case "record_player": + return Bukkit.getOfflinePlayer(ParkourPlayer.getAtPlace(1)).getName(); + case "leader_score": + case "rank_one_score": + case "record_score": + case "record": + return Integer.toString(ParkourPlayer.getHighScore(ParkourPlayer.getAtPlace(1))); } return null; diff --git a/src/main/java/dev/efnilite/witp/util/Util.java b/src/main/java/dev/efnilite/witp/util/Util.java index 0a96510e..93571adc 100644 --- a/src/main/java/dev/efnilite/witp/util/Util.java +++ b/src/main/java/dev/efnilite/witp/util/Util.java @@ -30,6 +30,24 @@ public class Util { private static Economy economy; + /** + * Sorts a HashMap by value + * Source: https://stackoverflow.com/questions/109383/sort-a-mapkey-value-by-values + * + * @return a sorted HashMap + */ + public static > HashMap sortByValue(Map map) { + List> list = new ArrayList<>(map.entrySet()); + list.sort(Map.Entry.comparingByValue(Comparator.reverseOrder())); + + HashMap result = new LinkedHashMap<>(); + for (Map.Entry entry : list) { + result.put(entry.getKey(), entry.getValue()); + } + + return result; + } + /** * Deposits money to a player using Vault * diff --git a/src/main/resources/generation.yml b/src/main/resources/generation.yml index 7dc96d7d..15ec6546 100644 --- a/src/main/resources/generation.yml +++ b/src/main/resources/generation.yml @@ -30,9 +30,10 @@ generation: chance: 10 # The type of block - ice: 60 + ice: 50 slab: 30 # for bottom-side half slabs pane: 10 # for glass panes + fence: 10 # The settings for structures structures: diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 4b6248a0..f83cf07a 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: 'WITP' description: 'Automatically generating, infinitely long parkour plugin. The sky, and your time, is the limit. The further you go, the harder it gets. Should be a walk in the park, right?' author: Efnilite, Ice_Pancake -version: 1.5a +version: 1.6 api-version: 1.16 main: dev.efnilite.witp.WITP softdepend: [Vault, PlaceholderAPI]