From 87788e60a396a752f9bb3704a754e91475ec1672 Mon Sep 17 00:00:00 2001 From: EpicKnarvik97 Date: Sun, 28 Apr 2024 16:21:54 +0200 Subject: [PATCH] Implements #35 --- README.md | 42 ++- .../net/knarcraft/minigames/MiniGames.java | 20 +- .../minigames/arena/ArenaSession.java | 7 + .../parkour/ParkourArenaPlayerRegistry.java | 2 +- .../arena/parkour/ParkourArenaSession.java | 4 + .../placeholder/DropperExpansion.java | 73 +++++ .../placeholder/DropperRecordExpansion.java | 32 --- .../placeholder/ParkourExpansion.java | 73 +++++ .../placeholder/ParkourRecordExpansion.java | 32 --- .../placeholder/parsing/PlayerInfoType.java | 37 +++ .../parsing/PlayerPlaceholderParser.java | 271 ++++++++++++++++++ .../RecordPlaceholderParser.java} | 122 ++++---- src/main/resources/plugin.yml | 2 + 13 files changed, 566 insertions(+), 151 deletions(-) create mode 100644 src/main/java/net/knarcraft/minigames/placeholder/DropperExpansion.java delete mode 100644 src/main/java/net/knarcraft/minigames/placeholder/DropperRecordExpansion.java create mode 100644 src/main/java/net/knarcraft/minigames/placeholder/ParkourExpansion.java delete mode 100644 src/main/java/net/knarcraft/minigames/placeholder/ParkourRecordExpansion.java create mode 100644 src/main/java/net/knarcraft/minigames/placeholder/parsing/PlayerInfoType.java create mode 100644 src/main/java/net/knarcraft/minigames/placeholder/parsing/PlayerPlaceholderParser.java rename src/main/java/net/knarcraft/minigames/placeholder/{RecordExpansion.java => parsing/RecordPlaceholderParser.java} (75%) diff --git a/README.md b/README.md index 4a74cbe..b2e76be 100644 --- a/README.md +++ b/README.md @@ -282,7 +282,9 @@ These are all the options that can be changed for an arena. - LIGHTNING_ROD - CHAIN -## Record placeholders +## Placeholders + +### Record Placeholders Player records can be displayed on a leaderboard by using PlaceholderAPI. If you want to display a sign-based leaderboard, you can use the [Placeholder Signs](https://git.knarcraft.net/EpicKnarvik97/PlaceholderSigns) plugin. The @@ -290,16 +292,34 @@ format for the built-in placeholders is as follows: `%gameMode_record_recordType_gameModeType_identifierType_identifier_recordPosition_infoType%` -| Variable | Values | Description | -|----------------|-----------------------------|------------------------------------------------------------------------------------------------------------------------------------| -| gameMode | dropper / parkour | A selection of which game-mode you are getting a record for | -| record | | This must be as-is. It's a selector in case placeholders are added for more than records. | -| recordType | deaths / time | Selects the type of record to get (deaths or time). | -| gameModeType | default / inverted / random | Selects the game-mode to get the record for. | -| identifierType | arena / group | The type of thing the following identifier points to (an arena or an arena group). | -| identifier | ? | An identifier (the name or UUID) for an arena or a group (whichever was chosen as identifierType). | -| recordPosition | 1 / 2 / 3 / ... | The position of the record to get (1 = first place, 2 = second place, etc.). | -| infoType | player / value / combined | The type of info to get. Player gets the player name, Value gets the value of the achieved record. Combined gets "Player: Record". | +| Variable | Values | Description | +|----------------|----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------| +| gameMode | dropper / parkour | A selection of which game-mode you are getting a record for | +| record | | This must be as-is. It's a selector for the type of placeholder to get. | +| recordType | deaths / time | Selects the type of record to get (deaths or time). | +| gameModeType | default / inverted / random / hardcore | Selects the game-mode to get the record for. | +| identifierType | arena / group | The type of thing the following identifier points to (an arena or an arena group). | +| identifier | ? | An identifier (the name or UUID) for an arena or a group (whichever was chosen as identifierType). | +| recordPosition | 1 / 2 / 3 / ... | The position of the record to get (1 = first place, 2 = second place, etc.). | +| infoType | player / value / combined | The type of info to get. Player gets the player name, Value gets the value of the achieved record. Combined gets "Player: Record". | + +### Player Placeholders + +The number of currently playing players can be displayed using PlaceholderAPI. If you want to display a sign-based +leaderboard, you can use the [Placeholder Signs](https://git.knarcraft.net/EpicKnarvik97/PlaceholderSigns) plugin. The +format for the built-in placeholders is as follows: + +`%gameMode_players_playing_gameModeType_identifierType_identifier_infoType_additionalSpecifier%` + +| Variable | Values | Description | +|-----------------|----------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------| +| gameMode | dropper / parkour | A selection of which game-mode you are getting a record for | +| players_playing | | This must be as-is. It's a selector in case placeholders are added for more than playing players. | +| gameModeType | default / inverted / random / hardcore / all | Selects the game-mode to get the players for. Note that "all" combines players for all game-modes. | +| identifierType | arena / group | The type of thing the following identifier points to (an arena or an arena group). | +| identifier | ? | An identifier (the name or UUID) for an arena or a group (whichever was chosen as identifierType). | +| playerInfoType | player / count | The type of info to get. Player gets the player name, and count gets the total number of players. | +| playerNumber | 1 / 2 / 3 / ... | The player number to get the name of. Players are numbered after their sorted names. This argument is not used when getting the player count. | ## Notes about material tags diff --git a/src/main/java/net/knarcraft/minigames/MiniGames.java b/src/main/java/net/knarcraft/minigames/MiniGames.java index 7521db5..bfbd04a 100644 --- a/src/main/java/net/knarcraft/minigames/MiniGames.java +++ b/src/main/java/net/knarcraft/minigames/MiniGames.java @@ -70,8 +70,8 @@ import net.knarcraft.minigames.listener.MoveListener; import net.knarcraft.minigames.listener.PlayerStateChangeListener; import net.knarcraft.minigames.manager.EconomyManager; import net.knarcraft.minigames.manager.PermissionManager; -import net.knarcraft.minigames.placeholder.DropperRecordExpansion; -import net.knarcraft.minigames.placeholder.ParkourRecordExpansion; +import net.knarcraft.minigames.placeholder.DropperExpansion; +import net.knarcraft.minigames.placeholder.ParkourExpansion; import net.md_5.bungee.api.ChatColor; import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.permission.Permission; @@ -102,8 +102,8 @@ public final class MiniGames extends JavaPlugin { private ParkourConfiguration parkourConfiguration; private DropperArenaHandler dropperArenaHandler; private ArenaPlayerRegistry dropperArenaPlayerRegistry; - private DropperRecordExpansion dropperRecordExpansion; - private ParkourRecordExpansion parkourRecordExpansion; + private DropperExpansion dropperExpansion; + private ParkourExpansion parkourExpansion; private ParkourArenaHandler parkourArenaHandler; private ArenaPlayerRegistry parkourArenaPlayerRegistry; private PlayerVisibilityManager playerVisibilityManager; @@ -253,8 +253,8 @@ public final class MiniGames extends JavaPlugin { this.parkourConfiguration.load(this.getConfig()); // Clear record caches - this.dropperRecordExpansion.clearCaches(); - this.parkourRecordExpansion.clearCaches(); + this.dropperExpansion.clearCaches(); + this.parkourExpansion.clearCaches(); } @Override @@ -316,12 +316,12 @@ public final class MiniGames extends JavaPlugin { */ private void doPluginIntegration() { if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { - this.dropperRecordExpansion = new DropperRecordExpansion(this); - if (!this.dropperRecordExpansion.register()) { + this.dropperExpansion = new DropperExpansion(this); + if (!this.dropperExpansion.register()) { log(Level.WARNING, "Unable to register PlaceholderAPI dropper expansion!"); } - this.parkourRecordExpansion = new ParkourRecordExpansion(this); - if (!this.parkourRecordExpansion.register()) { + this.parkourExpansion = new ParkourExpansion(this); + if (!this.parkourExpansion.register()) { log(Level.WARNING, "Unable to register PlaceholderAPI parkour expansion!"); } } diff --git a/src/main/java/net/knarcraft/minigames/arena/ArenaSession.java b/src/main/java/net/knarcraft/minigames/arena/ArenaSession.java index 8003b62..eb1564e 100644 --- a/src/main/java/net/knarcraft/minigames/arena/ArenaSession.java +++ b/src/main/java/net/knarcraft/minigames/arena/ArenaSession.java @@ -52,4 +52,11 @@ public interface ArenaSession { */ void reset(); + /** + * Gets the game-mode the player is playing + * + * @return

The game-mode the player is playing

+ */ + @NotNull ArenaGameMode getGameMode(); + } diff --git a/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArenaPlayerRegistry.java b/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArenaPlayerRegistry.java index 3cc6cf9..f863e18 100644 --- a/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArenaPlayerRegistry.java +++ b/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArenaPlayerRegistry.java @@ -11,5 +11,5 @@ public class ParkourArenaPlayerRegistry extends AbstractArenaPlayerRegistry playerPlaceholderParser; + + /** + * Instantiates a new dropper expansion + * + * @param plugin

A reference to the mini-games plugin

+ */ + public DropperExpansion(@NotNull MiniGames plugin) { + DropperArenaHandler arenaHandler = plugin.getDropperArenaHandler(); + this.recordPlaceholderParser = new RecordPlaceholderParser(arenaHandler, DropperArenaGameMode::matchGameMode); + this.playerPlaceholderParser = new PlayerPlaceholderParser<>(arenaHandler, DropperArenaGameMode::matchGameMode, + plugin.getDropperArenaPlayerRegistry()); + } + + /** + * Clears record caches + */ + public void clearCaches() { + this.recordPlaceholderParser.clearCaches(); + } + + @Override + public String getIdentifier() { + return "dropper"; + } + + @Override + public String getAuthor() { + return "EpicKnarvik97"; + } + + @Override + public String getVersion() { + return "1.0.0"; + } + + @Override + public boolean persist() { + return true; + } + + @Override + public String onRequest(OfflinePlayer player, String parameters) { + String[] parts = parameters.split("_"); + // Record is used as the prefix for all record placeholders in case more placeholder types are added + if (parts[0].equalsIgnoreCase("record") && parts.length >= 7) { + return recordPlaceholderParser.onRequest(parameters, parts); + } else if (parts[0].equalsIgnoreCase("players")) { + return this.playerPlaceholderParser.onRequest(parameters, parts); + } else { + return parameters; + } + } + +} diff --git a/src/main/java/net/knarcraft/minigames/placeholder/DropperRecordExpansion.java b/src/main/java/net/knarcraft/minigames/placeholder/DropperRecordExpansion.java deleted file mode 100644 index 885b954..0000000 --- a/src/main/java/net/knarcraft/minigames/placeholder/DropperRecordExpansion.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.knarcraft.minigames.placeholder; - -import net.knarcraft.minigames.MiniGames; -import net.knarcraft.minigames.arena.ArenaGameMode; -import net.knarcraft.minigames.arena.dropper.DropperArenaGameMode; -import org.jetbrains.annotations.NotNull; - -/** - * A placeholder expansion for dropper record placeholders - */ -public class DropperRecordExpansion extends RecordExpansion { - - /** - * Initializes a new record expansion - * - * @param plugin

A reference to the dropper plugin

- */ - public DropperRecordExpansion(MiniGames plugin) { - super(plugin.getDropperArenaHandler()); - } - - @Override - public String getIdentifier() { - return "dropper"; - } - - @Override - protected @NotNull ArenaGameMode parseGameMode(@NotNull String gameMode) { - return DropperArenaGameMode.matchGameMode(gameMode); - } - -} diff --git a/src/main/java/net/knarcraft/minigames/placeholder/ParkourExpansion.java b/src/main/java/net/knarcraft/minigames/placeholder/ParkourExpansion.java new file mode 100644 index 0000000..ba9ba60 --- /dev/null +++ b/src/main/java/net/knarcraft/minigames/placeholder/ParkourExpansion.java @@ -0,0 +1,73 @@ +package net.knarcraft.minigames.placeholder; + +import me.clip.placeholderapi.expansion.PlaceholderExpansion; +import net.knarcraft.minigames.MiniGames; +import net.knarcraft.minigames.arena.parkour.ParkourArena; +import net.knarcraft.minigames.arena.parkour.ParkourArenaGameMode; +import net.knarcraft.minigames.arena.parkour.ParkourArenaHandler; +import net.knarcraft.minigames.placeholder.parsing.PlayerPlaceholderParser; +import net.knarcraft.minigames.placeholder.parsing.RecordPlaceholderParser; +import org.bukkit.OfflinePlayer; +import org.jetbrains.annotations.NotNull; + +/** + * A placeholderAPI expansion for Parkour-related placeholders + */ +public class ParkourExpansion extends PlaceholderExpansion { + + private final @NotNull RecordPlaceholderParser recordPlaceholderParser; + private final @NotNull PlayerPlaceholderParser playerPlaceholderParser; + + /** + * Instantiates a new dropper expansion + * + * @param plugin

A reference to the mini-games plugin

+ */ + public ParkourExpansion(@NotNull MiniGames plugin) { + ParkourArenaHandler arenaHandler = plugin.getParkourArenaHandler(); + this.recordPlaceholderParser = new RecordPlaceholderParser(arenaHandler, ParkourArenaGameMode::matchGamemode); + this.playerPlaceholderParser = new PlayerPlaceholderParser<>(arenaHandler, ParkourArenaGameMode::matchGamemode, + plugin.getParkourArenaPlayerRegistry()); + } + + /** + * Clears record caches + */ + public void clearCaches() { + this.recordPlaceholderParser.clearCaches(); + } + + @Override + public String getIdentifier() { + return "parkour"; + } + + @Override + public String getAuthor() { + return "EpicKnarvik97"; + } + + @Override + public String getVersion() { + return "1.0.0"; + } + + @Override + public boolean persist() { + return true; + } + + @Override + public String onRequest(OfflinePlayer player, String parameters) { + String[] parts = parameters.split("_"); + // Record is used as the prefix for all record placeholders in case more placeholder types are added + if (parts[0].equalsIgnoreCase("record") && parts.length >= 7) { + return recordPlaceholderParser.onRequest(parameters, parts); + } else if (parts[0].equalsIgnoreCase("players")) { + return this.playerPlaceholderParser.onRequest(parameters, parts); + } else { + return parameters; + } + } + +} diff --git a/src/main/java/net/knarcraft/minigames/placeholder/ParkourRecordExpansion.java b/src/main/java/net/knarcraft/minigames/placeholder/ParkourRecordExpansion.java deleted file mode 100644 index 11fdcbe..0000000 --- a/src/main/java/net/knarcraft/minigames/placeholder/ParkourRecordExpansion.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.knarcraft.minigames.placeholder; - -import net.knarcraft.minigames.MiniGames; -import net.knarcraft.minigames.arena.ArenaGameMode; -import net.knarcraft.minigames.arena.parkour.ParkourArenaGameMode; -import org.jetbrains.annotations.NotNull; - -/** - * A placeholder expansion for parkour record placeholders - */ -public class ParkourRecordExpansion extends RecordExpansion { - - /** - * Initializes a new record expansion - * - * @param plugin

A reference to the dropper plugin

- */ - public ParkourRecordExpansion(MiniGames plugin) { - super(plugin.getParkourArenaHandler()); - } - - @Override - public String getIdentifier() { - return "parkour"; - } - - @Override - protected @NotNull ArenaGameMode parseGameMode(@NotNull String gameMode) { - return ParkourArenaGameMode.matchGamemode(gameMode); - } - -} diff --git a/src/main/java/net/knarcraft/minigames/placeholder/parsing/PlayerInfoType.java b/src/main/java/net/knarcraft/minigames/placeholder/parsing/PlayerInfoType.java new file mode 100644 index 0000000..e482181 --- /dev/null +++ b/src/main/java/net/knarcraft/minigames/placeholder/parsing/PlayerInfoType.java @@ -0,0 +1,37 @@ +package net.knarcraft.minigames.placeholder.parsing; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The types of player information that can be retrieved in placeholders + */ +public enum PlayerInfoType { + + /** + * The number of current players + */ + COUNT, + + /** + * Information about a single player + */ + PLAYER, + ; + + /** + * Gets the info type specified in the given string + * + * @param type

The string specifying the info type

+ * @return

The info type, or null if not found

+ */ + public static @Nullable PlayerInfoType getFromString(@NotNull String type) { + for (PlayerInfoType infoType : PlayerInfoType.values()) { + if (infoType.name().equalsIgnoreCase(type)) { + return infoType; + } + } + return null; + } + +} diff --git a/src/main/java/net/knarcraft/minigames/placeholder/parsing/PlayerPlaceholderParser.java b/src/main/java/net/knarcraft/minigames/placeholder/parsing/PlayerPlaceholderParser.java new file mode 100644 index 0000000..7870fe6 --- /dev/null +++ b/src/main/java/net/knarcraft/minigames/placeholder/parsing/PlayerPlaceholderParser.java @@ -0,0 +1,271 @@ +package net.knarcraft.minigames.placeholder.parsing; + +import net.knarcraft.minigames.MiniGames; +import net.knarcraft.minigames.arena.Arena; +import net.knarcraft.minigames.arena.ArenaGameMode; +import net.knarcraft.minigames.arena.ArenaGroup; +import net.knarcraft.minigames.arena.ArenaHandler; +import net.knarcraft.minigames.arena.ArenaPlayerRegistry; +import net.knarcraft.minigames.arena.ArenaSession; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.function.Function; +import java.util.logging.Level; + +/** + * A parser for player-related placeholders + */ +public class PlayerPlaceholderParser { + + private final @NotNull ArenaHandler arenaHandler; + private final @NotNull Function gameModeParser; + private final ArenaPlayerRegistry playerRegistry; + + /** + * Initializes a new player placeholder parser + * + * @param arenaHandler

The arena handler to get arenas from

+ * @param gameModeParser

The function to use for parsing the specified game-mode

+ * @param playerRegistry

The player registry to get player info from

+ */ + public PlayerPlaceholderParser(@NotNull ArenaHandler arenaHandler, + @NotNull Function gameModeParser, + ArenaPlayerRegistry playerRegistry) { + this.arenaHandler = arenaHandler; + this.gameModeParser = gameModeParser; + this.playerRegistry = playerRegistry; + } + + /** + * The method to run when parsing a record placeholder request + * + * @param parameters

The parameters specified

+ * @return

The resulting string

+ */ + @NotNull + public String onRequest(@NotNull String parameters, @NotNull String[] parts) { + if (parts.length < 6) { + return parameters; + } + + // String selector = parts[1]; // The selector for which aspect of players to get. Playing is the only one available yet. + String gameModeName = parts[2]; + ArenaGameMode gameMode = gameModeParser.apply(gameModeName); + if (gameModeName.equalsIgnoreCase("combined") || gameModeName.equalsIgnoreCase("all")) { + gameMode = null; + } + + SelectionType selectionType = SelectionType.getFromString(parts[3]); + String identifier = parts[4]; + + // The type of info to get. Either count (number of players) or player_position (a named player). + PlayerInfoType infoType = PlayerInfoType.getFromString(parts[5]); + if (infoType == null) { + return parameters; + } + + String info = null; + if (selectionType == SelectionType.GROUP) { + ArenaGroup group = arenaHandler.getGroup(identifier); + if (group != null) { + info = getGroupInfo(group, gameMode, infoType, parts); + } + } else if (selectionType == SelectionType.ARENA) { + info = getArenaInfo(identifier, gameMode, infoType, parts); + } + + return Objects.requireNonNullElse(info, parameters); + } + + /** + * Gets information about an arena group's players + * + * @param group

The group to get info about

+ * @param gameMode

The game-mode to get information for

+ * @param infoType

The type of information to get

+ * @param parts

The placeholder arguments specified by a user

+ * @return

The specified group info, or null if the placeholder is invalid

+ */ + @Nullable + private String getGroupInfo(@NotNull ArenaGroup group, @Nullable ArenaGameMode gameMode, + @NotNull PlayerInfoType infoType, @NotNull String[] parts) { + List arenaIds = group.getArenas(); + List arenas = new ArrayList<>(); + for (UUID arenaId : arenaIds) { + K arena = arenaHandler.getArena(arenaId); + if (arena != null) { + arenas.add(arena); + } + } + + if (infoType == PlayerInfoType.COUNT) { + int playerCount = 0; + for (K arena : arenas) { + playerCount += getArenaPlayers(arena, gameMode).size(); + } + return String.valueOf(playerCount); + } else if (infoType == PlayerInfoType.PLAYER) { + if (parts.length < 7) { + return null; + } + Integer playerNumber = getPositionNumber(parts[6]); + + List arenaPlayerNames = new ArrayList<>(); + for (K arena : arenas) { + arenaPlayerNames.addAll(getArenaPlayersSorted(arena, gameMode)); + } + arenaPlayerNames.sort(Comparator.naturalOrder()); + if (playerNumber != null) { + if (playerNumber >= arenaPlayerNames.size()) { + return ""; + } else { + return arenaPlayerNames.get(playerNumber); + } + } + } + return null; + } + + /** + * Gets information about an arena's players + * + * @param arenaName

The name of the arena

+ * @param gameMode

The game-mode to get information for

+ * @param infoType

The type of information to get

+ * @param parts

The placeholder arguments specified by a user

+ * @return

The specified arena info, or null if the placeholder is invalid

+ */ + @Nullable + private String getArenaInfo(@NotNull String arenaName, @Nullable ArenaGameMode gameMode, + @NotNull PlayerInfoType infoType, @NotNull String[] parts) { + if (infoType == PlayerInfoType.COUNT) { + Set arenaPlayers = getArenaPlayers(arenaName, gameMode); + if (arenaPlayers != null) { + return String.valueOf(arenaPlayers.size()); + } + } else if (infoType == PlayerInfoType.PLAYER) { + if (parts.length < 7) { + return null; + } + Integer playerNumber = getPositionNumber(parts[6]); + List players = getArenaPlayersSorted(arenaName, gameMode); + if (playerNumber != null && players != null) { + if (playerNumber >= players.size()) { + return ""; + } else { + return players.get(playerNumber); + } + } + } + return null; + } + + /** + * Gets the position number from the given string + * + * @param positionNumber

The position number to parse

+ * @return

The position number, or null if not valid

+ */ + @Nullable + private Integer getPositionNumber(@NotNull String positionNumber) { + try { + return Integer.parseInt(positionNumber) - 1; + } catch (NumberFormatException exception) { + MiniGames.log(Level.WARNING, "Invalid placeholder given. " + positionNumber + + " supplied instead of player number."); + return null; + } + } + + /** + * Gets names of all players in an arena in sorted order + * + * @param arenaName

The name of the arena to get players from

+ * @param arenaGameMode

The game-mode to get players for

+ * @return

Player names in sorted order, or null if the arena name is invalid

+ */ + @Nullable + private List getArenaPlayersSorted(@NotNull String arenaName, @Nullable ArenaGameMode arenaGameMode) { + K arena = arenaHandler.getArena(arenaName); + if (arena == null) { + return null; + } + return getArenaPlayersSorted(arena, arenaGameMode); + } + + /** + * Gets names of all players in an arena in sorted order + * + * @param arena

The arena to get players from

+ * @param arenaGameMode

The game-mode to get players for

+ * @return

Player names in sorted order, or null if the arena name is invalid

+ */ + @NotNull + private List getArenaPlayersSorted(@NotNull K arena, @Nullable ArenaGameMode arenaGameMode) { + Set players = getArenaPlayers(arena, arenaGameMode); + List playerNames = new ArrayList<>(players.size()); + for (UUID playerId : players) { + Player player = Bukkit.getPlayer(playerId); + if (player != null) { + playerNames.add(player.getName()); + } + } + playerNames.sort(Comparator.naturalOrder()); + return playerNames; + } + + /** + * Gets all players from the given arena + * + * @param arenaName

The name of the arena to get players from

+ * @param arenaGameMode

The game-mode to get players for

+ * @return

The players in the given arena playing the given game-mode

+ */ + @Nullable + private Set getArenaPlayers(@NotNull String arenaName, @Nullable ArenaGameMode arenaGameMode) { + K arena = arenaHandler.getArena(arenaName); + if (arena == null) { + return null; + } + + return getArenaPlayers(arena, arenaGameMode); + } + + /** + * Gets all players from the given arena + * + * @param arena

The arena to get players from

+ * @param arenaGameMode

The game-mode to get players for

+ * @return

The players in the given arena playing the given game-mode

+ */ + @NotNull + private Set getArenaPlayers(@NotNull K arena, @Nullable ArenaGameMode arenaGameMode) { + // If getting count for any game-mode, skip filtering + Set players = playerRegistry.getPlayingPlayers(arena); + if (arenaGameMode == null) { + return players; + } + + Set output = new HashSet<>(); + for (UUID playerId : players) { + ArenaSession arenaSession = playerRegistry.getArenaSession(playerId); + if (arenaSession == null || arenaSession.getGameMode() != arenaGameMode) { + continue; + } + + output.add(playerId); + } + return output; + } + +} diff --git a/src/main/java/net/knarcraft/minigames/placeholder/RecordExpansion.java b/src/main/java/net/knarcraft/minigames/placeholder/parsing/RecordPlaceholderParser.java similarity index 75% rename from src/main/java/net/knarcraft/minigames/placeholder/RecordExpansion.java rename to src/main/java/net/knarcraft/minigames/placeholder/parsing/RecordPlaceholderParser.java index c14965d..20692ed 100644 --- a/src/main/java/net/knarcraft/minigames/placeholder/RecordExpansion.java +++ b/src/main/java/net/knarcraft/minigames/placeholder/parsing/RecordPlaceholderParser.java @@ -1,6 +1,5 @@ -package net.knarcraft.minigames.placeholder; +package net.knarcraft.minigames.placeholder.parsing; -import me.clip.placeholderapi.expansion.PlaceholderExpansion; import net.knarcraft.minigames.MiniGames; import net.knarcraft.minigames.arena.Arena; import net.knarcraft.minigames.arena.ArenaGameMode; @@ -8,12 +7,10 @@ import net.knarcraft.minigames.arena.ArenaGroup; import net.knarcraft.minigames.arena.ArenaHandler; import net.knarcraft.minigames.arena.ArenaRecordsRegistry; import net.knarcraft.minigames.arena.record.ArenaRecord; -import net.knarcraft.minigames.placeholder.parsing.InfoType; -import net.knarcraft.minigames.placeholder.parsing.SelectionType; +import net.knarcraft.minigames.placeholder.GroupRecordCache; import net.knarcraft.minigames.property.RecordType; import net.knarcraft.minigames.util.GroupRecordHelper; import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -26,51 +23,45 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; +import java.util.function.Function; import java.util.function.Supplier; import java.util.logging.Level; /** - * A placeholder expansion for parkour record placeholders + * A parser for record-related placeholders */ -public abstract class RecordExpansion extends PlaceholderExpansion { +public class RecordPlaceholderParser { - private final ArenaHandler arenaHandler; - private final Map>> groupRecordDeathsCache; - private final Map>> groupRecordTimeCache; + private final @NotNull ArenaHandler arenaHandler; + private final @NotNull Map>> groupRecordDeathsCache; + private final @NotNull Map>> groupRecordTimeCache; + private final @NotNull Function gameModeParser; /** - * Initializes a new record expansion + * Initializes a new record placeholder parser */ - public RecordExpansion(ArenaHandler arenaHandler) { + public RecordPlaceholderParser(@NotNull ArenaHandler arenaHandler, + @NotNull Function gameModeParser) { this.groupRecordDeathsCache = new HashMap<>(); this.groupRecordTimeCache = new HashMap<>(); this.arenaHandler = arenaHandler; + this.gameModeParser = gameModeParser; } - @Override - public String getAuthor() { - return "EpicKnarvik97"; - } - - @Override - public String getVersion() { - return "1.0.0"; - } - - @Override - public boolean persist() { - return true; - } - - @Override - public String onRequest(OfflinePlayer player, String parameters) { - String[] parts = parameters.split("_"); - // Record is used as the prefix for all record placeholders in case more placeholder types are added - if (parts.length < 7 || !parts[0].equals("record")) { + /** + * The method to run when parsing a record placeholder request + * + * @param parameters

The parameters specified

+ * @return

The resulting string

+ */ + @NotNull + public String onRequest(@NotNull String parameters, @NotNull String[] parts) { + if (parts.length < 7) { return parameters; } + RecordType recordType = RecordType.getFromString(parts[1]); - ArenaGameMode gameMode = parseGameMode(parts[2]); + ArenaGameMode gameMode = gameModeParser.apply(parts[2]); SelectionType selectionType = SelectionType.getFromString(parts[3]); String identifier = parts[4]; int recordNumber; @@ -78,7 +69,7 @@ public abstract class RecordExpansion extends PlaceholderExpansion { recordNumber = Integer.parseInt(parts[5]) - 1; } catch (NumberFormatException exception) { MiniGames.log(Level.WARNING, "Invalid placeholder given. " + parts[5] + - " supplied instead of record placement."); + " supplied instead of record position."); return parameters; } InfoType infoType = InfoType.getFromString(parts[6]); @@ -97,14 +88,6 @@ public abstract class RecordExpansion extends PlaceholderExpansion { return Objects.requireNonNullElse(info, parameters); } - /** - * Parses the game-mode specified in the given string - * - * @param gameMode

The game-mode to parse

- * @return

The parsed game-mode

- */ - protected abstract @NotNull ArenaGameMode parseGameMode(@NotNull String gameMode); - /** * Clears all record caches */ @@ -124,9 +107,10 @@ public abstract class RecordExpansion extends PlaceholderExpansion { * @param infoType

The type of info (player, value, combined) to get

* @return

The selected information about the record, or null if not found

*/ - private @Nullable String getGroupRecord(@NotNull ArenaHandler arenaHandler, @NotNull String identifier, - @NotNull ArenaGameMode gameMode, @NotNull RecordType recordType, - int recordNumber, @NotNull InfoType infoType) { + @Nullable + private String getGroupRecord(@NotNull ArenaHandler arenaHandler, @NotNull String identifier, + @NotNull ArenaGameMode gameMode, @NotNull RecordType recordType, + int recordNumber, @NotNull InfoType infoType) { // Allow specifying the group UUID or the arena name ArenaGroup group; try { @@ -162,9 +146,10 @@ public abstract class RecordExpansion extends PlaceholderExpansion { * @param arenaHandler

The handler to get arenas from

* @return

The record, or null if not found

*/ - private @Nullable ArenaRecord getGroupTimeRecord(@NotNull ArenaGroup group, - @NotNull ArenaGameMode gameMode, int recordNumber, - @NotNull ArenaHandler arenaHandler) { + @Nullable + private ArenaRecord getGroupTimeRecord(@NotNull ArenaGroup group, + @NotNull ArenaGameMode gameMode, int recordNumber, + @NotNull ArenaHandler arenaHandler) { return getCachedGroupRecord(group, gameMode, RecordType.TIME, recordNumber, groupRecordTimeCache, () -> GroupRecordHelper.getCombinedTime(group, gameMode, arenaHandler)); } @@ -178,9 +163,10 @@ public abstract class RecordExpansion extends PlaceholderExpansion { * @param arenaHandler

The handler to get arenas from

* @return

The record, or null if not found

*/ - private @Nullable ArenaRecord getGroupDeathRecord(@NotNull ArenaGroup group, - @NotNull ArenaGameMode gameMode, int recordNumber, - @NotNull ArenaHandler arenaHandler) { + @Nullable + private ArenaRecord getGroupDeathRecord(@NotNull ArenaGroup group, + @NotNull ArenaGameMode gameMode, int recordNumber, + @NotNull ArenaHandler arenaHandler) { return getCachedGroupRecord(group, gameMode, RecordType.DEATHS, recordNumber, groupRecordDeathsCache, () -> GroupRecordHelper.getCombinedDeaths(group, gameMode, arenaHandler)); } @@ -197,12 +183,13 @@ public abstract class RecordExpansion extends PlaceholderExpansion { * @param

The type of the provided records

* @return

The specified record, or null if not found

*/ - private > @Nullable ArenaRecord getCachedGroupRecord(@NotNull ArenaGroup group, - @NotNull ArenaGameMode gameMode, - @NotNull RecordType recordType, - int recordNumber, - @NotNull Map>> caches, - @NotNull Supplier>> recordProvider) { + @Nullable + private > ArenaRecord getCachedGroupRecord(@NotNull ArenaGroup group, + @NotNull ArenaGameMode gameMode, + @NotNull RecordType recordType, + int recordNumber, + @NotNull Map>> caches, + @NotNull Supplier>> recordProvider) { UUID groupId = group.getGroupId(); if (!caches.containsKey(groupId)) { caches.put(groupId, new HashSet<>()); @@ -244,9 +231,10 @@ public abstract class RecordExpansion extends PlaceholderExpansion { * @param infoType

The type of info (player, value, combined) to get

* @return

The selected information about the record, or null if not found

*/ - private @Nullable String getArenaRecord(@NotNull ArenaHandler arenaHandler, @NotNull String identifier, - @NotNull ArenaGameMode gameMode, @NotNull RecordType recordType, - int recordNumber, @NotNull InfoType infoType) { + @Nullable + private String getArenaRecord(@NotNull ArenaHandler arenaHandler, @NotNull String identifier, + @NotNull ArenaGameMode gameMode, @NotNull RecordType recordType, + int recordNumber, @NotNull InfoType infoType) { // Allow specifying the arena UUID or the arena name Arena arena; try { @@ -278,8 +266,9 @@ public abstract class RecordExpansion extends PlaceholderExpansion { * @param recordNumber

The position of the record to get (1st place, 2nd place, etc.)

* @return

The record, or null if not found

*/ - private @Nullable ArenaRecord getRecord(@NotNull ArenaRecordsRegistry recordsRegistry, - @NotNull RecordType recordType, int recordNumber) { + @Nullable + private ArenaRecord getRecord(@NotNull ArenaRecordsRegistry recordsRegistry, + @NotNull RecordType recordType, int recordNumber) { return switch (recordType) { case TIME -> getRecord(new HashSet<>(recordsRegistry.getShortestTimeMilliSecondsRecords()), recordNumber); case DEATHS -> getRecord(new HashSet<>(recordsRegistry.getLeastDeathsRecords()), recordNumber); @@ -294,7 +283,8 @@ public abstract class RecordExpansion extends PlaceholderExpansion { * @param

The type of record in the record list

* @return

The record, or null if index is out of bounds

*/ - private > @Nullable ArenaRecord getRecord(Set> records, int index) { + @Nullable + private > ArenaRecord getRecord(@NotNull Set> records, int index) { List> sorted = getSortedRecords(records); if (index < sorted.size() && index >= 0) { return sorted.get(index); @@ -310,6 +300,7 @@ public abstract class RecordExpansion extends PlaceholderExpansion { * @param arenaRecord

The record to get the data from

* @return

The requested data as a string, or null

*/ + @Nullable private String getRecordData(@NotNull InfoType infoType, @NotNull ArenaRecord arenaRecord) { return switch (infoType) { case PLAYER -> getPlayerName(arenaRecord.getUserId()); @@ -325,8 +316,8 @@ public abstract class RecordExpansion extends PlaceholderExpansion { * @param

The type of the records

* @return

The sorted records

*/ - private > @NotNull List> getSortedRecords( - @NotNull Set> recordSet) { + @NotNull + private > List> getSortedRecords(@NotNull Set> recordSet) { List> records = new ArrayList<>(recordSet); Collections.sort(records); return records; @@ -338,6 +329,7 @@ public abstract class RecordExpansion extends PlaceholderExpansion { * @param playerId

The id of the player to get the name for

* @return

The name of the player, or a string representation of the UUID if not found

*/ + @Nullable private String getPlayerName(@NotNull UUID playerId) { return Bukkit.getOfflinePlayer(playerId).getName(); } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index e3822cf..ce7938a 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -7,6 +7,8 @@ description: A plugin that adds various mini-games softdepend: - PlaceholderAPI - Vault + - Geyser-Spigot + - floodgate # Note to self: Aliases must be lowercase! commands: