diff --git a/pom.xml b/pom.xml index 8b1d5158..7ef8484e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ dev.efnilite witp - 1.0 + 1.8 diff --git a/src/main/java/dev/efnilite/witp/WITP.java b/src/main/java/dev/efnilite/witp/WITP.java index 4660db08..a2753ece 100644 --- a/src/main/java/dev/efnilite/witp/WITP.java +++ b/src/main/java/dev/efnilite/witp/WITP.java @@ -5,6 +5,7 @@ import dev.efnilite.witp.generator.subarea.SubareaDivider; import dev.efnilite.witp.hook.PlaceholderHook; import dev.efnilite.witp.player.ParkourPlayer; +import dev.efnilite.witp.player.ParkourUser; import dev.efnilite.witp.util.Configuration; import dev.efnilite.witp.util.Util; import dev.efnilite.witp.util.Verbose; @@ -61,7 +62,7 @@ public void onEnable() { break; default: Verbose.error("You are trying to start this plugin using an invalid server version"); - Verbose.error("This plugin only works in version 1.16.4"); + Verbose.error("This plugin only works in version 1.16.4, 1.16.3 or 1.16.2"); this.getServer().getPluginManager().disablePlugin(this); return; } @@ -118,16 +119,18 @@ public void join(PlayerJoinEvent event) { Player player = event.getPlayer(); World world = WITP.getDivider().getWorld(); if (configuration.getFile("config").getBoolean("bungeecord.enabled")) { - if (configuration.getFile("config").getBoolean("messages.join-leave-enabled")) { - event.setJoinMessage(configuration.getString("config", "messages.join").replaceAll("%[a-z]", - player.getName())); - } try { ParkourPlayer.register(player); } catch (IOException ex) { ex.printStackTrace(); Verbose.error("Something went wrong while trying to fetch a player's (" + player.getName() + ") data"); } + if (configuration.getFile("lang").getBoolean("messages.join-leave-enabled")) { + event.setJoinMessage(null); + for (ParkourUser user : ParkourUser.getUsers()) { + user.sendTranslated("join", player.getName()); + } + } } else if (player.getWorld() == WITP.getDivider().getWorld()) { World fallback = Bukkit.getWorld(configuration.getString("config", "world.fall-back")); if (fallback != null) { @@ -149,29 +152,40 @@ public void join(PlayerJoinEvent event) { @EventHandler public void damage(EntityDamageEvent event) { if (event.getEntity() instanceof Player) { - if (ParkourPlayer.getPlayer((Player) event.getEntity()) != null) { + if (ParkourUser.getUser((Player) event.getEntity()) != null) { + event.setCancelled(true); + } + } + } + + @EventHandler + public void command(PlayerCommandPreprocessEvent event) { + if (ParkourGenerator.Configurable.FOCUS_MODE) { + ParkourUser user = ParkourUser.getUser(event.getPlayer()); + if (user != null && !(event.getMessage().toLowerCase().contains("witp"))) { event.setCancelled(true); + user.sendTranslated("cant-do"); } } } @EventHandler public void onDrop(PlayerDropItemEvent event) { - if (ParkourPlayer.getPlayer(event.getPlayer()) != null) { + if (ParkourUser.getUser(event.getPlayer()) != null) { event.setCancelled(true); } } @EventHandler public void onPlace(BlockPlaceEvent event) { - if (ParkourPlayer.getPlayer(event.getPlayer()) != null) { + if (ParkourUser.getUser(event.getPlayer()) != null) { event.setCancelled(true); } } @EventHandler public void onBreak(BlockBreakEvent event) { - if (ParkourPlayer.getPlayer(event.getPlayer()) != null) { + if (ParkourUser.getUser(event.getPlayer()) != null) { event.setCancelled(true); } } @@ -196,7 +210,7 @@ public void interact(PlayerInteractEvent event) { @EventHandler public void onSwitch(PlayerChangedWorldEvent event) { ParkourPlayer player = ParkourPlayer.getPlayer(event.getPlayer()); - if (player != null && player.getPlayer().getWorld().getName().equals(WITP.getDivider().getWorld().getName())) { + if (player != null && player.getPlayer().getWorld().getUID() != WITP.getDivider().getWorld().getUID()) { try { ParkourPlayer.unregister(player, true); } catch (IOException ex) { @@ -210,9 +224,11 @@ public void onSwitch(PlayerChangedWorldEvent event) { public void leave(PlayerQuitEvent event) { ParkourPlayer player = ParkourPlayer.getPlayer(event.getPlayer()); if (player != null) { - if (configuration.getFile("config").getBoolean("messages.join-leave-enabled")) { - event.setQuitMessage(configuration.getString("config", "messages.leave").replaceAll("%p", - event.getPlayer().getName())); + if (configuration.getFile("lang").getBoolean("messages.join-leave-enabled")) { + event.setQuitMessage(null); + for (ParkourUser user : ParkourUser.getUsers()) { + user.sendTranslated("leave", player.getPlayer().getName()); + } } try { ParkourPlayer.unregister(player, false); diff --git a/src/main/java/dev/efnilite/witp/command/MainCommand.java b/src/main/java/dev/efnilite/witp/command/MainCommand.java index 8d48bcd3..3102ce6f 100644 --- a/src/main/java/dev/efnilite/witp/command/MainCommand.java +++ b/src/main/java/dev/efnilite/witp/command/MainCommand.java @@ -1,6 +1,8 @@ package dev.efnilite.witp.command; import dev.efnilite.witp.player.ParkourPlayer; +import dev.efnilite.witp.player.ParkourSpectator; +import dev.efnilite.witp.player.ParkourUser; import dev.efnilite.witp.util.Util; import dev.efnilite.witp.util.Verbose; import dev.efnilite.witp.util.wrapper.BukkitCommand; @@ -9,6 +11,7 @@ import org.bukkit.entity.Player; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -26,6 +29,7 @@ public boolean execute(CommandSender sender, String[] args) { sender.sendMessage(Util.color("&a/witp join [player] &f- &7Join the game on this server or make another player join")); sender.sendMessage(Util.color("&a/witp leave &f- &7Leave the game on this server")); sender.sendMessage(Util.color("&a/witp menu &f- &7Open the customization menu")); + sender.sendMessage(Util.color("&a/witp gamemode &f- &7Open the gamemode menu")); sender.sendMessage(Util.color("&a/witp leaderboard &f- &7Open the leaderboard")); return true; } else if (args.length == 1) { @@ -37,7 +41,7 @@ public boolean execute(CommandSender sender, String[] args) { ParkourPlayer.register(player); ParkourPlayer pp = ParkourPlayer.getPlayer(player); if (pp != null) { - pp.send("&aYou joined the parkour"); + pp.sendTranslated("joined"); } } catch (IOException ex) { ex.printStackTrace(); @@ -47,7 +51,7 @@ public boolean execute(CommandSender sender, String[] args) { ParkourPlayer pp = ParkourPlayer.getPlayer(player); if (pp != null) { try { - pp.send("&cYou left the parkour"); + pp.sendTranslated("left"); ParkourPlayer.unregister(pp, true); } catch (IOException ex) { ex.printStackTrace(); @@ -59,6 +63,16 @@ public boolean execute(CommandSender sender, String[] args) { if (pp != null) { pp.menu(); } + } else if (args[0].equalsIgnoreCase("gamemode") || args[0].equalsIgnoreCase("gm")) { + ParkourUser user = ParkourUser.getUser(player); + if (user != null) { + user.gamemode(); + } + } else if (args[0].equalsIgnoreCase("leaderboard")) { + ParkourUser user = ParkourUser.getUser(player); + if (user != null) { + user.scoreboard(1); + } } } else if (args.length == 2) { if (args[0].equalsIgnoreCase("leaderboard") && args[1] != null && player != null) { @@ -78,13 +92,31 @@ public boolean execute(CommandSender sender, String[] args) { ParkourPlayer.register(join); ParkourPlayer pp = ParkourPlayer.getPlayer(join); if (pp != null) { - pp.send("&aYou joined the parkour"); + pp.sendTranslated("joined"); } } catch (IOException ex) { ex.printStackTrace(); Verbose.error("Error while joining"); } } + } else if (args[0].equalsIgnoreCase("search") && player != null) { + ParkourUser user = ParkourUser.getUser(player); + if (user != null) { + if (args[1] == null || player.getName().equalsIgnoreCase(args[1])) { + user.sendTranslated("not-there-search"); + } else { + Player search = Bukkit.getPlayer(args[1]); + if (search != null) { + ParkourUser searchUser = ParkourUser.getUser(search); + if (searchUser instanceof ParkourPlayer) { + ParkourPlayer searchPp = (ParkourPlayer) searchUser; + if (searchPp.getGenerator() != null) { + new ParkourSpectator(user, searchPp); + } + } + } + } + } } } return true; @@ -92,6 +124,19 @@ public boolean execute(CommandSender sender, String[] args) { @Override public List tabComplete(Player player, String[] args) { - return Arrays.asList("join", "generate", "customize", "leave"); + if (args.length == 2) { + if (args[0].equalsIgnoreCase("search")) { + List names = new ArrayList<>(); + for (ParkourPlayer pp : ParkourUser.getActivePlayers()) { + String name = pp.getPlayer().getName(); + if (player.getName().equals(name)) { + continue; + } + names.add(name); + } + return names; + } + } + return Arrays.asList("join", "leave", "menu", "leaderboard", "gamemode"); } } diff --git a/src/main/java/dev/efnilite/witp/events/BlockGenerateEvent.java b/src/main/java/dev/efnilite/witp/events/BlockGenerateEvent.java index 9c758637..eee43f62 100644 --- a/src/main/java/dev/efnilite/witp/events/BlockGenerateEvent.java +++ b/src/main/java/dev/efnilite/witp/events/BlockGenerateEvent.java @@ -1,7 +1,7 @@ package dev.efnilite.witp.events; -import dev.efnilite.witp.player.ParkourPlayer; import dev.efnilite.witp.generator.ParkourGenerator; +import dev.efnilite.witp.player.ParkourPlayer; import dev.efnilite.witp.util.wrapper.EventWrapper; import org.bukkit.block.Block; diff --git a/src/main/java/dev/efnilite/witp/generator/ParkourGenerator.java b/src/main/java/dev/efnilite/witp/generator/ParkourGenerator.java index 2206988e..dbd6e00a 100644 --- a/src/main/java/dev/efnilite/witp/generator/ParkourGenerator.java +++ b/src/main/java/dev/efnilite/witp/generator/ParkourGenerator.java @@ -1,11 +1,11 @@ package dev.efnilite.witp.generator; -import dev.efnilite.witp.player.ParkourPlayer; import dev.efnilite.witp.WITP; import dev.efnilite.witp.events.BlockGenerateEvent; import dev.efnilite.witp.events.PlayerFallEvent; import dev.efnilite.witp.events.PlayerScoreEvent; import dev.efnilite.witp.generator.subarea.SubareaPoint; +import dev.efnilite.witp.player.ParkourPlayer; import dev.efnilite.witp.util.Util; import dev.efnilite.witp.util.Verbose; import dev.efnilite.witp.util.particle.ParticleData; @@ -113,10 +113,14 @@ public void run() { if (stopped) { this.cancel(); return; - } + } // todo check if first location isn't current Location playerLoc = player.getPlayer().getLocation(); - if (playerLoc.getWorld() != lastPlayer.getWorld()) { - lastPlayer = playerLoc.clone(); + if (playerLoc.getWorld().getUID() != lastPlayer.getWorld().getUID()) { + Verbose.error("Worlds are not the same (1)"); + return; + } + if (playerLoc.getWorld().getUID() != playerSpawn.getWorld().getUID()) { + Verbose.error("Worlds are not the same (2)"); return; } // Fall check @@ -136,9 +140,6 @@ public void run() { // Structure deletion check if (structureBlocks.contains(current) && current.getType() == Material.RED_WOOL && !deleteStructure) { score += 10; - if (player.showScoreboard && Configurable.SCOREBOARD) { - player.updateScoreboard(); - } structureCooldown = 20; generateNext(player.blockLead); deleteStructure = true; @@ -166,9 +167,6 @@ public void run() { } new PlayerScoreEvent(player).call(); - if (player.showScoreboard && Configurable.SCOREBOARD) { - player.updateScoreboard(); - } List locations = new ArrayList<>(buildLog.keySet()); int lastIndex = locations.indexOf(last) + 1; int size = locations.size(); @@ -195,6 +193,7 @@ public void run() { if (player.showScoreboard && Configurable.SCOREBOARD) { player.updateScoreboard(); } + player.updateSpectators(); } }, Configurable.GENERATOR_CHECK); } @@ -212,14 +211,14 @@ public void reset(boolean regenerate) { for (Block block : structureBlocks) { block.setType(Material.AIR); } - structureBlocks.clear(); for (String s : buildLog.keySet()) { Util.parseLocation(s).getBlock().setType(Material.AIR); } + structureBlocks.clear(); structureCooldown = 20; buildLog.clear(); player.getPlayer().teleport(playerSpawn); - if (player.showDeathMsg) { + if (player.showDeathMsg && regenerate) { String message; int number = 0; if (score == player.highScore) { @@ -237,7 +236,7 @@ public void reset(boolean regenerate) { player.sendTranslated("divider"); player.sendTranslated("score", Integer.toString(score)); player.sendTranslated("time", time); - player.sendTranslated("highscore", Integer.toString(score)); + player.sendTranslated("highscore", Integer.toString(player.highScore)); player.sendTranslated(message, Integer.toString(number)); player.sendTranslated("divider"); } else { @@ -495,7 +494,7 @@ public void generateNext() { break; } - int listSize = player.blockLead + 7; // the size of the queue of parkour blocks + int listSize = player.blockLead + 10; // the size of the queue of parkour blocks listSize--; List locations = new ArrayList<>(buildLog.keySet()); if (locations.size() > listSize) { @@ -522,6 +521,7 @@ public void generateNext() { */ public void generateFirst(Location spawn, Location block) { playerSpawn = spawn.clone(); + lastPlayer = spawn.clone(); blockSpawn = block.clone(); lastSpawn = block.clone(); generateNext(player.blockLead); @@ -625,6 +625,10 @@ public static class Configurable { public static boolean SCOREBOARD; public static boolean INVENTORY_HANDLING; + public static String SCOREBOARD_TITLE; + public static List SCOREBOARD_LINES; + public static boolean PERMISSIONS; + public static boolean FOCUS_MODE; // Advanced settings public static double BORDER_SIZE; @@ -676,7 +680,11 @@ public static void init() { } SCOREBOARD = config.getBoolean("scoreboard.enabled"); + SCOREBOARD_TITLE = Util.color(config.getString("scoreboard.title")); + SCOREBOARD_LINES = Util.color(config.getStringList("scoreboard.lines")); INVENTORY_HANDLING = config.getBoolean("options.inventory-handling"); + PERMISSIONS = config.getBoolean("permissions.enabled"); + FOCUS_MODE = config.getBoolean("focus-mode.enabled"); SOUND_TYPE = Sound.valueOf(config.getString("particles.sound-type").toUpperCase()); SOUND_PITCH = config.getInt("particles.sound-pitch"); 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 77690ad8..60a76172 100644 --- a/src/main/java/dev/efnilite/witp/generator/subarea/SubareaDivider.java +++ b/src/main/java/dev/efnilite/witp/generator/subarea/SubareaDivider.java @@ -1,8 +1,8 @@ package dev.efnilite.witp.generator.subarea; -import dev.efnilite.witp.player.ParkourPlayer; import dev.efnilite.witp.WITP; import dev.efnilite.witp.generator.ParkourGenerator; +import dev.efnilite.witp.player.ParkourPlayer; import dev.efnilite.witp.util.Util; import dev.efnilite.witp.util.Verbose; import dev.efnilite.witp.util.VoidGenerator; @@ -11,13 +11,16 @@ import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.craftbukkit.libs.org.apache.commons.io.FileUtils; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.FileUtil; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -70,7 +73,12 @@ public SubareaDivider() { } File folder = new File(worldName); if (folder.exists() && folder.isDirectory()) { - folder.delete(); + try { + FileUtils.deleteDirectory(folder); + } catch (IOException ex) { + ex.printStackTrace(); + Verbose.error("Error while deleting the playing world"); + } } this.world = createWorld(worldName); FileConfiguration gen = WITP.getConfiguration().getFile("generation"); @@ -101,7 +109,7 @@ public World getWorld() { */ public @Nullable SubareaPoint getPoint(@NotNull ParkourPlayer player) { for (SubareaPoint point : collection.keySet()) { - if (collection.get(point) == player) { + if (collection.get(point).getPlayer().getUniqueId() == player.getPlayer().getUniqueId()) { return point; } } @@ -123,10 +131,10 @@ public synchronized void generate(@NotNull ParkourPlayer player) { SubareaPoint last = openSpaces.get(openSpaces.size() - 1); createIsland(player, last); openSpaces.remove(last); + Verbose.verbose("Used Subarea divided to " + player.getPlayer().getName()); return; } if (copy % 8 == 0) { // every new layer has +8 area points - createIsland(player, current); current = current.zero(); layer++; @@ -206,6 +214,7 @@ private void fetchPossibleInLayer() { world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false); world.setGameRule(GameRule.DO_WEATHER_CYCLE, false); world.setGameRule(GameRule.LOG_ADMIN_COMMANDS, false); + world.setGameRule(GameRule.ANNOUNCE_ADVANCEMENTS, false); world.setWeatherDuration(1000); world.setDifficulty(Difficulty.PEACEFUL); world.setAutoSave(false); @@ -213,7 +222,7 @@ private void fetchPossibleInLayer() { return world; } - private void setBorder(@NotNull ParkourPlayer player, @NotNull SubareaPoint point) { + public void setBorder(@NotNull ParkourPlayer player, @NotNull SubareaPoint point) { int size = (int) player.getGenerator().borderOffset * 2; Vector estimated = point.getEstimatedCenter(size); WITP.getVersionManager().setWorldBorder(player.getPlayer(), estimated, size); @@ -281,6 +290,6 @@ public void run() { setBorder(pp, point); } }; - Tasks.syncDelay(delay, 10 * 20); + Tasks.syncDelay(delay, 5 * 20); } } diff --git a/src/main/java/dev/efnilite/witp/hook/PlaceholderHook.java b/src/main/java/dev/efnilite/witp/hook/PlaceholderHook.java index 7c07da40..24b8770e 100644 --- a/src/main/java/dev/efnilite/witp/hook/PlaceholderHook.java +++ b/src/main/java/dev/efnilite/witp/hook/PlaceholderHook.java @@ -1,7 +1,7 @@ package dev.efnilite.witp.hook; -import dev.efnilite.witp.player.ParkourPlayer; import dev.efnilite.witp.WITP; +import dev.efnilite.witp.player.ParkourPlayer; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import org.bukkit.Bukkit; import org.bukkit.entity.Player; diff --git a/src/main/java/dev/efnilite/witp/player/ParkourPlayer.java b/src/main/java/dev/efnilite/witp/player/ParkourPlayer.java index ecadd858..e2a5b48f 100644 --- a/src/main/java/dev/efnilite/witp/player/ParkourPlayer.java +++ b/src/main/java/dev/efnilite/witp/player/ParkourPlayer.java @@ -1,7 +1,5 @@ package dev.efnilite.witp.player; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.annotations.Expose; import dev.efnilite.witp.WITP; import dev.efnilite.witp.WITPAPI; @@ -13,19 +11,19 @@ import dev.efnilite.witp.util.inventory.ItemBuilder; import dev.efnilite.witp.util.task.Tasks; import fr.mrmicky.fastboard.FastBoard; -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 org.bukkit.*; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; import org.bukkit.entity.Player; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; -import java.io.*; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; import java.util.*; import java.util.concurrent.ThreadLocalRandom; @@ -51,14 +49,10 @@ public class ParkourPlayer extends ParkourUser { public @Expose String style; public @Expose String lang; - public UUID openInventory; - private FastBoard board; + private ParkourGenerator generator; private List possibleStyle; private final File file; - private final ParkourGenerator generator; - private static final HashMap players = new HashMap<>(); - private static HashMap highScores = new LinkedHashMap<>(); - private static final Gson gson = new GsonBuilder().disableHtmlEscaping().excludeFieldsWithoutExposeAnnotation().create(); + private final HashMap spectators; /** * Creates a new instance of a ParkourPlayer
@@ -68,19 +62,6 @@ public ParkourPlayer(@NotNull Player player, int highScore, String time, String boolean useDifficulty, boolean useStructure, boolean useSpecial, boolean showDeathMsg, boolean showScoreboard) { super(player); Verbose.verbose("Init of Player " + player.getName()); - this.previousLocation = player.getLocation().clone(); - this.previousGamemode = player.getGameMode(); - this.previousInventory = new HashMap<>(); - if (ParkourGenerator.Configurable.INVENTORY_HANDLING) { - int index = 0; - Inventory inventory = player.getInventory(); - for (ItemStack item : inventory.getContents()) { - if (item != null) { - previousInventory.put(index, item); - } - index++; - } - } this.useSpecial = useSpecial; this.showDeathMsg = showDeathMsg; this.highScore = highScore; @@ -91,10 +72,10 @@ public ParkourPlayer(@NotNull Player player, int highScore, String time, String this.useDifficulty = useDifficulty; this.useStructure = useStructure; this.showScoreboard = showScoreboard; + this.spectators = new HashMap<>(); this.file = new File(WITP.getInstance().getDataFolder() + "/players/" + player.getUniqueId().toString() + ".json"); this.possibleStyle = new ArrayList<>(); - this.board = new FastBoard(player); setStyle(style); this.generator = new ParkourGenerator(this); @@ -117,46 +98,38 @@ public ParkourPlayer(@NotNull Player player, int highScore, String time, String } } - - /** - * Gets a message from lang.yml - * - * @param path - * The path name in lang.yml (for example: 'time-preference') - * - * @param replaceable - * What can be replaced (for example: %s to yes) - */ - public void sendTranslated(String path, String... replaceable) { // todo add lang.yml - path = "messages." + path; - String string = WITP.getConfiguration().getString("config", path); - if (string == null) { - Verbose.error("Unknown path: " + path); - return; + public void removeSpectators(ParkourSpectator... spectators) { + for (ParkourSpectator spectator : spectators) { + this.spectators.remove(spectator.getPlayer().getName()); } - for (String s : replaceable) { - string = string.replaceAll("%[a-z]", s); + } + + public void addSpectator(ParkourSpectator... spectators) { + for (ParkourSpectator spectator : spectators) { + this.spectators.put(spectator.getPlayer().getName(), spectator); } - send(string); } /** - * Gets the scoreboard of the player - * - * @return the {@link FastBoard} of the player + * Updates the stats for spectators */ - public FastBoard getBoard() { - return board; + public void updateSpectators() { + for (ParkourSpectator spectator : spectators.values()) { + spectator.checkDistance(); + spectator.updateScoreboard(); + } } /** * Updates the scoreboard */ + @Override public void updateScoreboard() { - board.updateTitle(WITP.getConfiguration().getString("config", "scoreboard.title")); + board.updateTitle(ParkourGenerator.Configurable.SCOREBOARD_TITLE); List list = new ArrayList<>(); - List lines = WITP.getConfiguration().getStringList("config", "scoreboard.lines"); + List lines = ParkourGenerator.Configurable.SCOREBOARD_LINES; if (lines == null) { + Verbose.error("Scoreboard lines are null! Check your config!"); return; } for (String s : lines) { @@ -206,72 +179,78 @@ public void setHighScore(int score) { */ public void menu() { InventoryBuilder builder = new InventoryBuilder(this, 3, "Customize").open(); - InventoryBuilder builder1 = new InventoryBuilder(this, 3, "Lead").open(); - InventoryBuilder builder2 = new InventoryBuilder(this, 3, "Parkour style").open(); - InventoryBuilder builder3 = new InventoryBuilder(this, 3, "Time").open(); + InventoryBuilder lead = new InventoryBuilder(this, 3, "Lead").open(); + InventoryBuilder styling = new InventoryBuilder(this, 3, "Parkour style").open(); + InventoryBuilder timeofday = new InventoryBuilder(this, 3, "Time").open(); + String close = getTranslated("item-close"); if (WITP.getConfiguration().getFile("config").getBoolean("styles.enabled")) { builder.setItem(9, new ItemBuilder(Material.END_STONE, "&a&lParkour style") .setLore("&7The style of your parkour.", "&7(which blocks will be used)", "", "&7Currently: &a" + style).build(), (t, e) -> { - List styles = Util.getNode(WITP.getConfiguration().getFile("config"), "styles.list"); - if (styles == null) { - Verbose.error("Error while trying to fetch possible styles from config.yml"); - return; - } - int i = 0; - for (String style : styles) { - if (i == 26) { - Verbose.error("There are too many styles to display!"); - return; - } - List possible = this.getPossibleMaterials(style); - if (possible == null) { - continue; - } - Material material = possible.get(possible.size() - 1); - builder2.setItem(i, new ItemBuilder(material, "&b&l" + Util.capitalizeFirst(style)).build(), (t2, e2) -> { - String selected = ChatColor.stripColor(e2.getItemMeta().getDisplayName()).toLowerCase(); - this.setStyle(selected); - this.send("&7You selected style &c" + selected + "&7!"); - this.saveStats(); - }); - i++; - builder2.setItem(26, new ItemBuilder(Material.ARROW, "&c&lClose").build(), (t2, e2) -> player.closeInventory()); - } - builder2.build(); + if (checkPermission("witp.style")) { + List styles = Util.getNode(WITP.getConfiguration().getFile("config"), "styles.list"); + if (styles == null) { + Verbose.error("Error while trying to fetch possible styles from config.yml"); + return; + } + int i = 0; + for (String style : styles) { + if (i == 26) { + Verbose.error("There are too many styles to display!"); + return; + } + List possible = this.getPossibleMaterials(style); + if (possible == null) { + continue; + } + Material material = possible.get(possible.size() - 1); + styling.setItem(i, new ItemBuilder(material, "&b&l" + Util.capitalizeFirst(style)).build(), (t2, e2) -> { + String selected = ChatColor.stripColor(e2.getItemMeta().getDisplayName()).toLowerCase(); + setStyle(selected); + sendTranslated("selected-style", selected); + saveStats(); + }); + i++; + styling.setItem(26, new ItemBuilder(Material.ARROW, close).build(), (t2, e2) -> player.closeInventory()); + } + styling.build(); + } }); } builder.setItem(10, new ItemBuilder(Material.GLASS, "&a&lLead") .setLore("&7How many blocks will", "&7be generated ahead of you.", "", "&7Currently: &a" + blockLead + " blocks").build(), (t, e) -> { - for (int i = 10; i < 17; i++) { - builder1.setItem(i, new ItemBuilder(Material.PAPER, "&b&l" + (i - 9) + " block(s)").build(), (t2, e2) -> { - int amount = t2.getSlot() - 9; - blockLead = amount; - send("&7You selected a " + amount + " block lead."); - saveStats(); - }); + if (checkPermission("witp.lead")) { + for (int i = 10; i < 17; i++) { + lead.setItem(i, new ItemBuilder(Material.PAPER, "&b&l" + (i - 9) + " block(s)").build(), (t2, e2) -> { + blockLead = t2.getSlot() - 9; + sendTranslated("selected-block-lead", Integer.toString(blockLead)); + saveStats(); + }); + } + lead.setItem(26, new ItemBuilder(Material.ARROW, close).build(), (t2, e2) -> player.closeInventory()); + lead.build(); } - builder1.setItem(26, new ItemBuilder(Material.ARROW, "&c&lClose").build(), (t2, e2) -> player.closeInventory()); - builder1.build(); }); builder.setItem(11, new ItemBuilder(Material.CLOCK, "&a&lTime") .setLore("&7The time of day.", "", "&7Currently: &a" + time.toLowerCase()).build(), (t, e) -> { - List times = Arrays.asList("Day", "Noon", "Dawn", "Night", "Midnight"); - int i = 11; - for (String time : times) { - builder3.setItem(i, new ItemBuilder(Material.PAPER, "&b&l" + time).build(), (t2, e2) -> { - if (e2.getItemMeta() != null) { - String name = ChatColor.stripColor(e2.getItemMeta().getDisplayName()); - this.time = name; - send("&7You changed your time preference to &a" + time.toLowerCase()); - player.setPlayerTime(getTime(name), false); - saveStats(); - } - }); - i++; + if (checkPermission("witp.time")) { + List times = Arrays.asList("Day", "Noon", "Dawn", "Night", "Midnight"); + int i = 11; + for (String time : times) { + timeofday.setItem(i, new ItemBuilder(Material.PAPER, "&b&l" + time).build(), (t2, e2) -> { + if (e2.getItemMeta() != null) { + String name = ChatColor.stripColor(e2.getItemMeta().getDisplayName()); + this.time = name; + sendTranslated("selected-time", time.toLowerCase()); + player.setPlayerTime(getTime(name), false); + saveStats(); + } + }); + i++; + } + timeofday.setItem(26, new ItemBuilder(Material.ARROW, close).build(), (t2, e2) -> player.closeInventory()); + timeofday.build(); } - builder3.setItem(26, new ItemBuilder(Material.ARROW, "&c&lClose").build(), (t2, e2) -> player.closeInventory()); - builder3.build(); }); Material difficulty = useDifficulty ? Material.GREEN_WOOL : Material.RED_WOOL; String difficultyString = Boolean.toString(useDifficulty); @@ -279,11 +258,12 @@ public void menu() { builder.setItem(12, new ItemBuilder(difficulty, "&a&lUse difficulty") .setLore("&7If enabled having a higher score will mean", "&7the parkour becomes more difficult.", "", "&7Currently: " + difficultyValue).build(), (t2, e2) -> { - useDifficulty = !useDifficulty; - send("&7You changed your usage of difficulty to " + - Util.normalizeBoolean(Util.colorBoolean(Util.reverseBoolean(difficultyString)))); - saveStats(); - player.closeInventory(); + if (checkPermission("witp.difficulty")) { + useDifficulty = !useDifficulty; + sendTranslated("selected-difficulty", Util.normalizeBoolean(Util.colorBoolean(Util.reverseBoolean(difficultyString)))); + saveStats(); + player.closeInventory(); + } }); Material particles = useParticles ? Material.GREEN_WOOL : Material.RED_WOOL; String particlesString = Boolean.toString(useParticles); @@ -291,11 +271,12 @@ public void menu() { builder.setItem(13, new ItemBuilder(particles, "&a&lUse particles and sounds") .setLore("&7If enabled every generated block", "&7will show particles and play a sound.", "", "&7Currently: " + particlesValue).build(), (t2, e2) -> { - useParticles = !useParticles; - send("&7You changed your usage of particles to " + - Util.normalizeBoolean(Util.colorBoolean(Util.reverseBoolean(particlesString)))); - saveStats(); - player.closeInventory(); + if (checkPermission("witp.particles")) { + useParticles = !useParticles; + sendTranslated("selected-particles", Util.normalizeBoolean(Util.colorBoolean(Util.reverseBoolean(particlesString)))); + saveStats(); + player.closeInventory(); + } }); Material scoreboard = showScoreboard ? Material.GREEN_WOOL : Material.RED_WOOL; String scoreboardString = Boolean.toString(showScoreboard); @@ -303,17 +284,22 @@ public void menu() { builder.setItem(14, new ItemBuilder(scoreboard, "&a&lShow scoreboard") .setLore("&7If enabled shows the scoreboard", "", "&7Currently: " + scoreboardValue).build(), (t2, e2) -> { - showScoreboard = !showScoreboard; - if (showScoreboard) { - board = new FastBoard(player); - updateScoreboard(); - } else { - board.delete(); + if (checkPermission("witp.scoreboard")) { + if (ParkourGenerator.Configurable.SCOREBOARD) { + showScoreboard = !showScoreboard; + if (showScoreboard) { + board = new FastBoard(player); + updateScoreboard(); + } else { + board.delete(); + } + sendTranslated("selected-scoreboard", Util.normalizeBoolean(Util.colorBoolean(Util.reverseBoolean(scoreboardString)))); + saveStats(); + player.closeInventory(); + } else { + sendTranslated("cant-do"); + } } - send("&7You changed your usage of the scoreboard to " + - Util.normalizeBoolean(Util.colorBoolean(Util.reverseBoolean(scoreboardString)))); - saveStats(); - player.closeInventory(); }); Material deathMsg = showDeathMsg ? Material.GREEN_WOOL : Material.RED_WOOL; String deathString = Boolean.toString(showDeathMsg); @@ -321,11 +307,12 @@ public void menu() { builder.setItem(15, new ItemBuilder(deathMsg, "&a&lShow fall message") .setLore("&7If enabled shows a message when you fall", "&7with extra info", "", "&7Currently: " + deathValue).build(), (t2, e2) -> { - showDeathMsg = !showDeathMsg; - send("&7You changed your showing of the fall message to " + - Util.normalizeBoolean(Util.colorBoolean(Util.reverseBoolean(deathString)))); - saveStats(); - player.closeInventory(); + if (checkPermission("witp.fall")) { + showDeathMsg = !showDeathMsg; + sendTranslated("selected-fall-message", Util.normalizeBoolean(Util.colorBoolean(Util.reverseBoolean(deathString)))); + saveStats(); + player.closeInventory(); + } }); Material special = useSpecial ? Material.GREEN_WOOL : Material.RED_WOOL; String specialString = Boolean.toString(useSpecial); @@ -333,31 +320,41 @@ public void menu() { builder.setItem(16, new ItemBuilder(special, "&a&lUse special blocks") .setLore("&7If enabled uses special blocks like ice and slabs.", "", "&7Currently: " + specialValue).build(), (t2, e2) -> { - useSpecial = !useSpecial; - send("&7You changed your usage of special blocks to " + - Util.normalizeBoolean(Util.colorBoolean(Util.reverseBoolean(specialString)))); - saveStats(); - player.closeInventory(); + if (checkPermission("witp.special")) { + useSpecial = !useSpecial; + sendTranslated("selected-special-blocks", Util.normalizeBoolean(Util.colorBoolean(Util.reverseBoolean(specialString)))); + saveStats(); + player.closeInventory(); + } }); Material structures = useStructure ? Material.GREEN_WOOL : Material.RED_WOOL; String structuresString = Boolean.toString(useStructure); String structuresValue = Util.normalizeBoolean(Util.colorBoolean(structuresString)); builder.setItem(17, new ItemBuilder(structures, "&a&lUse structures") - .setLore("&7If enabled static structures", "&7will appear throughout the parkour.", "", - "&7Currently: " + structuresValue).build(), (t2, e2) -> { - useStructure = !useStructure; - send("&7You changed your usage of structures to " + - Util.normalizeBoolean(Util.colorBoolean(Util.reverseBoolean(structuresString)))); - saveStats(); - player.closeInventory(); + .setLore("&7If enabled static structures", "&7will appear throughout the parkour.", "", "&7Currently: " + structuresValue).build(), (t2, e2) -> { + if (checkPermission("witp.structures")) { + useStructure = !useStructure; + sendTranslated("selected-structures", Util.normalizeBoolean(Util.colorBoolean(Util.reverseBoolean(structuresString)))); + saveStats(); + player.closeInventory(); + } + }); + builder.setItem(18, new ItemBuilder(Material.PAPER, "&c&lGamemode").build(), (t2, e2) -> { + if (checkPermission("witp.gamemode")) { + player.closeInventory(); + gamemode(); + } }); Integer score = highScores.get(player.getUniqueId()); - builder.setItem(22, new ItemBuilder(Material.GOLD_BLOCK, "&6&lLeaderboard") - .setLore("&7Your rank: &f#" + getRank(player.getUniqueId()) + " &7(" + (score == null ? 0 : score) + ")").build(), (t2, e2) -> { - scoreboard(1); - player.closeInventory(); + builder.setItem(19, new ItemBuilder(Material.GOLD_BLOCK, "&6&lLeaderboard") + .setLore(getTranslated("your-rank", Integer.toString(getRank(player.getUniqueId())), Integer.toString(score == null ? 0 : score))) + .build(), (t2, e2) -> { + if (checkPermission("witp.leaderboard")) { + scoreboard(1); + player.closeInventory(); + } }); - builder.setItem(26, new ItemBuilder(Material.BARRIER, "&4&lQuit").build(), (t2, e2) -> { + builder.setItem(26, new ItemBuilder(Material.BARRIER, getTranslated("item-quit")).build(), (t2, e2) -> { try { ParkourPlayer.unregister(this, true); } catch (IOException ex) { @@ -365,10 +362,21 @@ public void menu() { Verbose.error("Error while trying to quit player " + player.getName()); } }); - builder.setItem(25, new ItemBuilder(Material.ARROW, "&c&lClose").build(), (t2, e2) -> player.closeInventory()); + builder.setItem(25, new ItemBuilder(Material.ARROW, close).build(), (t2, e2) -> player.closeInventory()); builder.build(); } + private boolean checkPermission(String perm) { + if (ParkourGenerator.Configurable.PERMISSIONS) { + boolean check = player.hasPermission(perm); + if (!check) { + sendTranslated("cant-do"); + } + return check; + } + return true; + } + private void saveStats() { BukkitRunnable runnable = new BukkitRunnable() { @Override @@ -423,76 +431,6 @@ public void save() throws IOException { writer.close(); } - /** - * Sends a message or array of it - coloured allowed, using '&' - * - * @param messages - * The message - */ - public void send(String... messages) { - for (String msg : messages) { - player.sendMessage(Util.color(msg)); - } - } - - /** - * 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(WITP.getConfiguration().getString("config", "messages.divider")); - } - /** * Gets the high score of a player * @@ -518,10 +456,6 @@ 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 * @@ -572,27 +506,6 @@ private int getRank(UUID player) { return players.get(player); } - // todo scoreboard - /** - * Gets the highscores of all player - * - * @throws IOException - * When creating the file reader goes wrong - */ - public static void fetchHighScores() throws IOException { - File folder = new File(WITP.getInstance().getDataFolder() + "/players/"); - if (!(folder.exists())) { - folder.mkdirs(); - return; - } - for (File file : folder.listFiles()) { - FileReader reader = new FileReader(file); - ParkourPlayer from = gson.fromJson(reader, ParkourPlayer.class); - String name = file.getName(); - highScores.put(UUID.fromString(name.substring(0, name.lastIndexOf('.'))), from.highScore); - } - } - /** * Gets a ParkourPlayer from a regular Player * @@ -651,6 +564,17 @@ public static void unregister(@NotNull ParkourPlayer player, boolean sendBack) t player.save(); WITP.getDivider().leave(player); players.remove(player.getPlayer()); + users.remove(player); + for (ParkourSpectator spectator : player.spectators.values()) { + try { + ParkourPlayer.register(spectator.getPlayer()); + } catch (IOException ex) { + ex.printStackTrace(); + Verbose.error("Error while trying to register player" + player.getPlayer().getName()); + } + } + player.spectators.clear(); + if (sendBack) { if (WITP.getConfiguration().getFile("config").getBoolean("bungeecord.enabled")) { Util.sendPlayer(player.getPlayer(), WITP.getConfiguration().getString("config", "bungeecord.return_server")); @@ -668,6 +592,7 @@ public static void unregister(@NotNull ParkourPlayer player, boolean sendBack) t pl.resetPlayerTime(); } } + player.generator = null; } /** @@ -678,13 +603,4 @@ public static void unregister(@NotNull ParkourPlayer player, boolean sendBack) t public ParkourGenerator getGenerator() { return generator; } - - /** - * Gets the Bukkit version of the player - * - * @return the player - */ - public @NotNull Player getPlayer() { - return player; - } } diff --git a/src/main/java/dev/efnilite/witp/player/ParkourSpectator.java b/src/main/java/dev/efnilite/witp/player/ParkourSpectator.java index a9ba8852..f06ed292 100644 --- a/src/main/java/dev/efnilite/witp/player/ParkourSpectator.java +++ b/src/main/java/dev/efnilite/witp/player/ParkourSpectator.java @@ -1,11 +1,68 @@ package dev.efnilite.witp.player; -import org.bukkit.entity.Player; +import dev.efnilite.witp.WITP; +import dev.efnilite.witp.generator.ParkourGenerator; +import dev.efnilite.witp.util.Verbose; +import org.bukkit.GameMode; import org.jetbrains.annotations.NotNull; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + public class ParkourSpectator extends ParkourUser { - public ParkourSpectator(@NotNull Player player) { - super(player); + protected final ParkourPlayer watching; + protected final ParkourGenerator watchingGenerator; + + public ParkourSpectator(@NotNull ParkourUser player, @NotNull ParkourPlayer watching) { + super(player.getPlayer()); + Verbose.verbose("New ParkourSpectator init " + this.player.getName()); + + if (player instanceof ParkourPlayer) { + try { + ParkourPlayer.unregister((ParkourPlayer) player, false); + } catch (IOException ex) { + ex.printStackTrace(); + Verbose.error("Error while trying to unregister"); + } + } else if (player instanceof ParkourSpectator) { + ParkourSpectator spectator = (ParkourSpectator) player; + spectator.watching.removeSpectators(spectator); + } + users.put(this.player.getName(), this); + + this.watching = watching; + this.watchingGenerator = watching.getGenerator(); + this.player.setGameMode(GameMode.SPECTATOR); + double offset = watching.getGenerator().borderOffset * 2; + WITP.getVersionManager().setWorldBorder(this.player, WITP.getDivider().getPoint(watching).getEstimatedCenter(offset), offset); + watching.addSpectator(this); + this.player.teleport(watching.getPlayer().getLocation()); + sendTranslated("spectator"); + } + + public void checkDistance() { + if (watching.getPlayer().getLocation().distance(player.getLocation()) > 30) { + player.teleport(watching.getPlayer().getLocation()); + } + } + + @Override + protected void updateScoreboard() { + board.updateTitle(ParkourGenerator.Configurable.SCOREBOARD_TITLE); + List list = new ArrayList<>(); + List lines = ParkourGenerator.Configurable.SCOREBOARD_LINES; + if (lines == null) { + Verbose.error("Scoreboard lines are null! Check your config!"); + return; + } + for (String s : lines) { + list.add(s + .replaceAll("%score%", Integer.toString(watchingGenerator.score)) + .replaceAll("%time%", watchingGenerator.time)); + } + + board.updateLines(list); } -} +} \ No newline at end of file diff --git a/src/main/java/dev/efnilite/witp/player/ParkourUser.java b/src/main/java/dev/efnilite/witp/player/ParkourUser.java index fc8777f5..bc3946f7 100644 --- a/src/main/java/dev/efnilite/witp/player/ParkourUser.java +++ b/src/main/java/dev/efnilite/witp/player/ParkourUser.java @@ -1,21 +1,302 @@ package dev.efnilite.witp.player; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import dev.efnilite.witp.WITP; +import dev.efnilite.witp.generator.ParkourGenerator; +import dev.efnilite.witp.util.Util; +import dev.efnilite.witp.util.Verbose; +import dev.efnilite.witp.util.inventory.InventoryBuilder; +import dev.efnilite.witp.util.inventory.ItemBuilder; +import fr.mrmicky.fastboard.FastBoard; +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 org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.HashMap; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.*; -abstract class ParkourUser { +public abstract class ParkourUser { + public UUID openInventory; protected final Player player; + protected FastBoard board; protected GameMode previousGamemode; protected Location previousLocation; protected HashMap previousInventory; + protected static final HashMap users = new HashMap<>(); + protected static final HashMap players = new HashMap<>(); + protected static HashMap highScores = new LinkedHashMap<>(); + protected static final Gson gson = new GsonBuilder().disableHtmlEscaping().excludeFieldsWithoutExposeAnnotation().create(); + public ParkourUser(@NotNull Player player) { this.player = player; + saveInventory(); + this.previousLocation = player.getLocation().clone(); + this.previousGamemode = player.getGameMode(); + this.board = new FastBoard(player); + // remove duplicates + users.put(player.getName(), this); + } + + protected void saveInventory() { + this.previousInventory = new HashMap<>(); + if (ParkourGenerator.Configurable.INVENTORY_HANDLING) { + int index = 0; + Inventory inventory = player.getInventory(); + for (ItemStack item : inventory.getContents()) { + if (item != null) { + previousInventory.put(index, item); + } + index++; + } + } + } + + public static @Nullable ParkourUser getUser(@NotNull Player player) { + for (ParkourUser user : users.values()) { + if (user.player.getUniqueId() == player.getUniqueId()) { + return user; + } + } + return null; + } + + /** + * Updates the scoreboard + */ + protected abstract void updateScoreboard(); + + /** + * Gets the highscores of all player + * + * @throws IOException + * When creating the file reader goes wrong + */ + public static void fetchHighScores() throws IOException { + File folder = new File(WITP.getInstance().getDataFolder() + "/players/"); + if (!(folder.exists())) { + folder.mkdirs(); + return; + } + for (File file : folder.listFiles()) { + FileReader reader = new FileReader(file); + ParkourPlayer from = gson.fromJson(reader, ParkourPlayer.class); + String name = file.getName(); + highScores.put(UUID.fromString(name.substring(0, name.lastIndexOf('.'))), from.highScore); + } + } + + /** + * Sends a message or array of it - coloured allowed, using '&' + * + * @param messages + * The message + */ + public void send(String... messages) { + for (String msg : messages) { + player.sendMessage(Util.color(msg)); + } + } + + /** + * Opens the gamemode menu + */ + public void gamemode() { + InventoryBuilder gamemode = new InventoryBuilder(this, 3, "Gamemode").open(); + InventoryBuilder spectatable = new InventoryBuilder(this, 3, "Select a player").open(); + gamemode.setItem(12, new ItemBuilder(Material.BARREL, "&c&lNormal").setLore("&7Play the game like normal").build(), (t, e) -> { + try { + player.closeInventory(); + if (this instanceof ParkourSpectator) { + ParkourSpectator spectator = (ParkourSpectator) this; + spectator.watching.removeSpectators(spectator); + } + ParkourPlayer.register(player); + } catch (IOException ex) { + ex.printStackTrace(); + Verbose.error("Error while trying to register player" + player.getName()); + } + }); + gamemode.setItem(14, new ItemBuilder(Material.GLASS, "&c&lSpectate").setLore("&7Spectate another player").build(), (t, e) -> { + int index = 0; + player.closeInventory(); + for (ParkourPlayer pp : getActivePlayers()) { + if (pp == null || pp.getGenerator() == null) { + continue; + } + Player player = pp.getPlayer(); + if (player.getUniqueId() != this.player.getUniqueId()) { + ItemStack item = new ItemBuilder(Material.PLAYER_HEAD, 1, "&c&l" + player.getName()) + .setLore("&7Click to spectate " + player.getName()).build(); + SkullMeta meta = (SkullMeta) item.getItemMeta(); + if (meta == null) { + continue; + } + meta.setOwningPlayer(player); + item.setItemMeta(meta); + spectatable.setItem(index, item, (t2, e2) -> new ParkourSpectator(this, pp)); + index++; + if (index == 25) { + break; + } + } + } + spectatable.setItem(25, new ItemBuilder(Material.PAPER, getTranslated("item-search")).setLore(getTranslated("item-search-lore")).build(), + (t2, e2) -> { + player.closeInventory(); + BaseComponent[] send = new ComponentBuilder().append(getTranslated("click-search")) + .event(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/witp search ")).create(); + player.spigot().sendMessage(send); + }); + spectatable.setItem(26, new ItemBuilder(Material.ARROW, getTranslated("item-close")).build(), (t2, e2) -> player.closeInventory()); + spectatable.build(); + }); + gamemode.setItem(26, new ItemBuilder(Material.ARROW, getTranslated("item-close")).build(), (t2, e2) -> player.closeInventory()); + gamemode.build(); + } + + /** + * 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("", "", "", "", "", "", "", ""); + sendTranslated("divider"); + 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("&a#" + rank + ". &7" + name + " &f- " + highScores.get(uuid)); + } + sendTranslated("your-rank", Integer.toString(getRank(player.getUniqueId())), Integer.toString(highScores.get(player.getUniqueId()))); + send(""); + + int prevPage = page - 1; + int nextPage = page + 1; + BaseComponent[] previous = new ComponentBuilder() + .append(getTranslated("previous-page")) + .event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/witp leaderboard " + prevPage)) + .append(" | ").color(net.md_5.bungee.api.ChatColor.GRAY) + .event((ClickEvent) null) + .append(getTranslated("next-page")) + .event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/witp leaderboard " + nextPage)) + .create(); + + player.spigot().sendMessage(previous); + sendTranslated("divider"); + } + + /** + * Gets the rank of a certain player + * + * @param player + * The player + * + * @return the rank (starts at 1.) + */ + protected int getRank(UUID player) { + return new ArrayList<>(highScores.keySet()).indexOf(player) + 1; + } + + /** + * Gets a message from lang.yml + * + * @param path + * The path name in lang.yml (for example: 'time-preference') + * + * @param replaceable + * What can be replaced (for example: %s to yes) + */ + public void sendTranslated(String path, String... replaceable) { + path = "messages.en." + path; + String string = WITP.getConfiguration().getString("lang", path); + if (string == null) { + Verbose.error("Unknown path: " + path + " - try deleting the config"); + return; + } + for (String s : replaceable) { + string = string.replaceAll("%[a-z]", s); + } + send(string); + } + + public String getTranslated(String path, String... replaceable) { + path = "messages.en." + path; + String string = WITP.getConfiguration().getString("lang", path); + if (string == null) { + Verbose.error("Unknown path: " + path + " - try deleting the config"); + return ""; + } + for (String s : replaceable) { + string = string.replaceAll("%[a-z]", s); + } + return string; + } + + public static List getUsers() { + return new ArrayList<>(users.values()); + } + + public static List getActivePlayers() { + return new ArrayList<>(players.values()); + } + + /** + * Gets the scoreboard of the player + * + * @return the {@link FastBoard} of the player + */ + public FastBoard getBoard() { + return board; + } + + /** + * Gets the Bukkit version of the player + * + * @return the player + */ + public @NotNull Player getPlayer() { + return player; } } \ No newline at end of file diff --git a/src/main/java/dev/efnilite/witp/util/Configuration.java b/src/main/java/dev/efnilite/witp/util/Configuration.java index 4604dfad..37152f69 100644 --- a/src/main/java/dev/efnilite/witp/util/Configuration.java +++ b/src/main/java/dev/efnilite/witp/util/Configuration.java @@ -32,9 +32,9 @@ public Configuration(Plugin plugin) { this.plugin = plugin; files = new HashMap<>(); - defaultFiles = new String[] {"config.yml", "generation.yml"}; + defaultFiles = new String[] {"config.yml", "generation.yml", "lang.yml"}; - if (!new File(plugin.getDataFolder() + "/config.yml").exists()) { + if (!new File(plugin.getDataFolder() + "/lang.yml").exists()) { plugin.getDataFolder().mkdirs(); for (String file : defaultFiles) { diff --git a/src/main/java/dev/efnilite/witp/util/Util.java b/src/main/java/dev/efnilite/witp/util/Util.java index 93571adc..f8914a84 100644 --- a/src/main/java/dev/efnilite/witp/util/Util.java +++ b/src/main/java/dev/efnilite/witp/util/Util.java @@ -3,6 +3,7 @@ import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; import dev.efnilite.witp.WITP; +import dev.efnilite.witp.player.ParkourUser; import dev.efnilite.witp.util.wrapper.EventWrapper; import net.milkbowl.vault.economy.Economy; import org.bukkit.*; diff --git a/src/main/java/dev/efnilite/witp/util/inventory/InventoryBuilder.java b/src/main/java/dev/efnilite/witp/util/inventory/InventoryBuilder.java index 58216cfa..04b0ff06 100644 --- a/src/main/java/dev/efnilite/witp/util/inventory/InventoryBuilder.java +++ b/src/main/java/dev/efnilite/witp/util/inventory/InventoryBuilder.java @@ -1,7 +1,7 @@ package dev.efnilite.witp.util.inventory; -import dev.efnilite.witp.player.ParkourPlayer; import dev.efnilite.witp.WITP; +import dev.efnilite.witp.player.ParkourUser; import dev.efnilite.witp.util.Util; import dev.efnilite.witp.util.Verbose; import org.bukkit.Bukkit; @@ -13,7 +13,6 @@ import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import javax.annotation.Nullable; @@ -27,13 +26,11 @@ */ public class InventoryBuilder implements Listener { - private final ParkourPlayer pp; - private int rows; private boolean open; private String name; - private Player holder; private UUID uuid; + private final ParkourUser player; private final HandlerList handlerList; private final HashMap items; private final HashMap onClick; @@ -53,15 +50,12 @@ public InventoryBuilder(int rows, String name) { /** * {@link #InventoryBuilder(int, String)} but with the holder */ - public InventoryBuilder(@Nullable ParkourPlayer pp, int rows, String name) { + public InventoryBuilder(@Nullable ParkourUser player, int rows, String name) { this.open = false; this.uuid = null; this.rows = rows; this.name = name; - this.pp = pp; - if (pp != null) { - this.holder = pp.getPlayer(); - } + this.player = player; this.handlerList = new HandlerList(); this.items = new HashMap<>(); this.onClick = new HashMap<>(); @@ -77,11 +71,11 @@ public Inventory build() { } uuid = UUID.randomUUID(); if (open) { - if (pp == null) { + if (player == null) { Verbose.error("Tried opening inventory " + uuid.toString() + " but player is null"); } else { - holder.openInventory(inventory); - pp.openInventory = uuid; + player.getPlayer().openInventory(inventory); + player.openInventory = uuid; } } unregister(); @@ -97,14 +91,6 @@ public InventoryBuilder open() { return this; } - /** - * Set the holder - */ - public InventoryBuilder setHolder(Player holder) { - this.holder = holder; - return this; - } - /** * Set an item in a slot */ @@ -117,8 +103,8 @@ public InventoryBuilder setItem(int slot, ItemStack item, @Nullable InventoryCon @EventHandler public void onClose(InventoryCloseEvent event) { Player player = (Player) event.getPlayer(); - if (player.getOpenInventory().getTitle().equals(name) && ParkourPlayer.getPlayer(player) != null) { - pp.openInventory = null; + if (player.getOpenInventory().getTitle().equals(name) && ParkourUser.getUser(player) != null) { + this.player.openInventory = null; unregister(); } } @@ -127,7 +113,7 @@ public void onClose(InventoryCloseEvent event) { public void onClick(InventoryClickEvent event) { Player player = (Player) event.getWhoClicked(); ItemStack current = event.getCurrentItem(); - if (player.getOpenInventory().getTitle().equals(name) && ParkourPlayer.getPlayer(player) != null && current != null && uuid == pp.openInventory) { + if (player.getOpenInventory().getTitle().equals(name) && ParkourUser.getUser(player) != null && current != null && uuid == this.player.openInventory) { event.setCancelled(true); InventoryConsumer consumer = onClick.get(event.getSlot()); if (consumer != null) { @@ -180,13 +166,6 @@ public int getRows() { return rows; } - /** - * Gets the holder - */ - public InventoryHolder getHolder() { - return holder; - } - /** * Gets the name */ diff --git a/src/main/java/dev/efnilite/witp/util/inventory/ItemBuilder.java b/src/main/java/dev/efnilite/witp/util/inventory/ItemBuilder.java index da541515..973dd045 100644 --- a/src/main/java/dev/efnilite/witp/util/inventory/ItemBuilder.java +++ b/src/main/java/dev/efnilite/witp/util/inventory/ItemBuilder.java @@ -5,7 +5,6 @@ import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 35cfb8dd..6e16824b 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -39,6 +39,20 @@ world: # The world players will be teleported to if they accidentally join the WITP world without being a player fall-back: world +# Options for permissions +# These permissions are used to determine which things the player can change. +# List: https://github.com/Efnilite/Walk-in-the-Park/wiki/Permissions +permissions: + + # If permissions are enabled + enabled: false + +# Options for focus mode +focus-mode: + + # If focus mode is enabled players can't use commands while in parkour + enabled: false + # Options for the option menu options: @@ -85,7 +99,7 @@ styles: scoreboard: enabled: true - title: '&c&lInfinite Parkour' + title: '&a&lWITP' lines: - '&a' - '&7Score: &f%score%' @@ -93,24 +107,6 @@ scoreboard: - '&b' - '&6&lserver.ip' -# Options for the messages -# %p is the player. -messages: - - # If join/leave messages should be shown - join-leave-enabled: true - join: '&7%p has joined the server.' - leave: '&7%p has left the server.' - - divider: '&7----------------------------------------' - score: '&aYour score: &f%s' - time: '&aYour time: &f%s' - highscore: '&aYour highscore: &f%s' - message: - miss: '&7You missed your high score by %s points!' - beat: '&7You beat your high score by %s points!' - tied: '&7You tied your high score!' - # Options for custom rewards rewards: diff --git a/src/main/resources/lang.yml b/src/main/resources/lang.yml new file mode 100644 index 00000000..2ace0c6c --- /dev/null +++ b/src/main/resources/lang.yml @@ -0,0 +1,50 @@ +# Options for the messages +# %p is the player. +# %[a-z] is the value that can get replaced +messages: + + # If the scoreboard is enabled + scoreboard-enabled: true + # If join/leave messages should be shown + join-leave-enabled: true + + # English + # Currently (v1.8) you can't add any other language, this will be added later + en: + join: '&7%p has joined the server' + leave: '&7%p has left the server' + joined: '&aYou joined the parkour' + left: '&cYou left the parkour' + + next-page: '&aNext page >>' + previous-page: '&a<< Previous page' + your-rank: '&7Your rank: &f#%n &7(%h)' + + selected-style: '&7You selected style &c%s&7!' + selected-block-lead: '&7You selected a &a%a &7block lead!' + selected-time: '&7You changed your time preference to &a%t' + selected-difficulty: '&7You changed your usage of difficulty to %v' + selected-particles: '&7You changed the showing of particles to %v' + selected-scoreboard: '&7You changed the showing of the scoreboard to %v' + selected-fall-message: '&7You changed the showing of the fall messages to %v' + selected-special-blocks: '&7You changed the usage of special blocks to %v' + selected-structures: '&7You changed the usage of structures to %v' + cant-do: '&cYou can''t do this right now.' + + item-close: '&c&lClose' + item-quit: '&4&lQuit' + + item-search: '&a&lSearch' + item-search-lore: '&7Search for a player to spectate' + not-there-search: '&7Type the player you want to spectate!' + click-search: '&c&l&nClick here&r&c&l to enter the player you want to search.' + + spectator: '&cYou are now a spectator. You can use "/witp gm" to leave/change your gamemode.' + divider: '&7----------------------------------------' + score: '&aYour score: &f%s' + time: '&aYour time: &f%s' + highscore: '&aYour highscore: &f%s' + message: + miss: '&7You missed your high score by %s points!' + beat: '&7You beat your high score by %s points!' + tied: '&7You tied your high score!' \ No newline at end of file