The result of the record
- * @param typeThe type of record set (time or deaths)
+ * @param recordTypeThe type of record set (time or deaths)
*/ - protected void announceRecord(@NotNull RecordResult recordResult, @NotNull String type) { + protected void announceRecord(@NotNull RecordResult recordResult, @NotNull RecordType recordType) { if (recordResult == RecordResult.NONE) { return; } @@ -75,11 +78,15 @@ public abstract class AbstractArenaSession implements ArenaSession { default -> throw new IllegalStateException("Unexpected value: " + recordResult); }; StringFormatter stringFormatter = MiniGames.getInstance().getStringFormatter(); - String recordInfo = stringFormatter.replacePlaceholder(recordInfoMiniGameMessage, "{recordType}", type); + String recordInfo = stringFormatter.replacePlaceholder(recordInfoMiniGameMessage, "{recordType}", + recordType.name().toLowerCase().replace("_", " ")); stringFormatter.displaySuccessMessage(player, stringFormatter.replacePlaceholders( MiniGameMessage.SUCCESS_RECORD_ACHIEVED, new String[]{"{gameMode}", "{recordInfo}"}, new String[]{gameModeString, recordInfo})); + + // Reward the player + rewardRecord(recordResult, recordType); } /** @@ -88,8 +95,32 @@ public abstract class AbstractArenaSession implements ArenaSession { protected void registerRecord() { ArenaRecordsRegistry recordsRegistry = this.arena.getData().getRecordRegistries().get(this.gameMode); long timeElapsed = System.currentTimeMillis() - this.startTime; - announceRecord(recordsRegistry.registerTimeRecord(this.player.getUniqueId(), timeElapsed), "time"); - announceRecord(recordsRegistry.registerDeathRecord(this.player.getUniqueId(), this.deaths), "least deaths"); + announceRecord(recordsRegistry.registerTimeRecord(this.player.getUniqueId(), timeElapsed), RecordType.TIME); + announceRecord(recordsRegistry.registerDeathRecord(this.player.getUniqueId(), this.deaths), RecordType.DEATHS); + } + + /** + * Rewards the specified achieved record + * + * @param recordResultThe result of the record achieved
+ * @param recordTypeThe type of record achieved
+ */ + protected void rewardRecord(RecordResult recordResult, RecordType recordType) { + RewardCondition condition = null; + if (recordResult == RecordResult.WORLD_RECORD) { + if (recordType == RecordType.DEATHS) { + condition = RewardCondition.GLOBAL_DEATH_RECORD; + } else if (recordType == RecordType.TIME) { + condition = RewardCondition.GLOBAL_TIME_RECORD; + } + } else if (recordResult == RecordResult.PERSONAL_BEST) { + if (recordType == RecordType.DEATHS) { + condition = RewardCondition.PERSONAL_DEATH_RECORD; + } else if (recordType == RecordType.TIME) { + condition = RewardCondition.PERSONAL_TIME_RECORD; + } + } + RewardHelper.grantRewards(this.player, this.arena.getRewards(condition)); } /** diff --git a/src/main/java/net/knarcraft/minigames/arena/Arena.java b/src/main/java/net/knarcraft/minigames/arena/Arena.java index ad15e81..ecb4574 100644 --- a/src/main/java/net/knarcraft/minigames/arena/Arena.java +++ b/src/main/java/net/knarcraft/minigames/arena/Arena.java @@ -1,10 +1,13 @@ package net.knarcraft.minigames.arena; +import net.knarcraft.minigames.arena.reward.Reward; +import net.knarcraft.minigames.arena.reward.RewardCondition; import org.bukkit.Location; import org.bukkit.block.Block; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Set; import java.util.UUID; /** @@ -91,4 +94,27 @@ public interface Arena { */ @Nullable Location getExitLocation(); + /** + * Adds a reward to this arena + * + * @param rewardConditionThe condition for the reward to be granted
+ * @param rewardThe reward to be granted
+ */ + void addReward(@NotNull RewardCondition rewardCondition, @NotNull Reward reward); + + /** + * Clears this arena's rewards for the given condition + * + * @param rewardConditionThe reward condition to clear all rewards for
+ */ + void clearRewards(@NotNull RewardCondition rewardCondition); + + /** + * Gets all rewards for the given reward condition + * + * @param rewardConditionThe condition to get the rewards for
+ * @returnAll rewards
+ */ + @NotNull SetThe velocity to use for players' vertical velocity
* @param playerHorizontalVelocityThe velocity to use for players' horizontal velocity (-1 to 1)
* @param winBlockTypeThe material of the block players have to hit to win this dropper arena
+ * @param rewardsThe rewards given by this arena
* @param dropperArenaDataThe arena data keeping track of which players have done what in this arena
* @param arenaHandlerThe arena handler used for saving any changes
*/ public DropperArena(@NotNull UUID arenaId, @NotNull String arenaName, @NotNull Location spawnLocation, @Nullable Location exitLocation, double playerVerticalVelocity, float playerHorizontalVelocity, - @NotNull Material winBlockType, @NotNull DropperArenaData dropperArenaData, - @NotNull DropperArenaHandler arenaHandler) { + @NotNull Material winBlockType, @NotNull MapThe id of the arena
- * @param arenaNameThe name of the arena
- * @param spawnLocationThe location players spawn in when entering the arena
- * @param exitLocationThe location the players are teleported to when exiting the arena, or null
- * @param winBlockTypeThe material of the block players have to hit to win this parkour arena
- * @param winLocationThe location a player has to reach to win this arena
- * @param parkourArenaDataThe arena data keeping track of which players have done what in this arena
- * @param arenaHandlerThe arena handler used for saving any changes
+ * @param arenaIdThe id of the arena
+ * @param arenaNameThe name of the arena
+ * @param spawnLocationThe location players spawn in when entering the arena
+ * @param exitLocationThe location the players are teleported to when exiting the arena, or null
+ * @param winBlockTypeThe material of the block players have to hit to win this parkour arena
+ * @param winLocationThe location a player has to reach to win this arena
+ * @param killPlaneBlockNamesThe names of the type of blocks
+ * @param checkpointsThe checkpoints set for this arena
+ * @param rewardsThe rewards given by this arena
+ * @param parkourArenaDataThe arena data keeping track of which players have done what in this arena
+ * @param arenaHandlerThe arena handler used for saving any changes
*/ public ParkourArena(@NotNull UUID arenaId, @NotNull String arenaName, @NotNull Location spawnLocation, @Nullable Location exitLocation, @NotNull Material winBlockType, @Nullable Location winLocation, @Nullable SetThe string specifying a reward condition
+ * @returnThe matching reward condition, or null if not found
+ */ + public static @Nullable RewardCondition getFromString(@NotNull String condition) { + for (RewardCondition rewardCondition : RewardCondition.values()) { + if (rewardCondition.name().equalsIgnoreCase(condition.replace("-", "_"))) { + return rewardCondition; + } + } + + return null; + } + + @NotNull + @Override + public MapThe data to deserialize
+ * @returnThe deserialized reward condition
+ */ + @SuppressWarnings({"unused"}) + public static @NotNull RewardCondition deserialize(@NotNull MapA reward object
+ * @returnThe reward type of the given object, or null if not recognized
+ */ + public staticThe string specifying a reward type
+ * @returnThe matching reward type, or null if not found
+ */ + public static RewardType getFromString(@NotNull String condition) { + for (RewardType rewardType : RewardType.values()) { + if (rewardType.name().equalsIgnoreCase(condition.replace("-", "_"))) { + return rewardType; + } + } + + return null; + } + +} diff --git a/src/main/java/net/knarcraft/minigames/command/SetArenaRewardCommand.java b/src/main/java/net/knarcraft/minigames/command/SetArenaRewardCommand.java new file mode 100644 index 0000000..10fe008 --- /dev/null +++ b/src/main/java/net/knarcraft/minigames/command/SetArenaRewardCommand.java @@ -0,0 +1,90 @@ +package net.knarcraft.minigames.command; + +import net.knarcraft.minigames.MiniGames; +import net.knarcraft.minigames.arena.Arena; +import net.knarcraft.minigames.arena.reward.Reward; +import net.knarcraft.minigames.arena.reward.RewardCondition; +import net.knarcraft.minigames.config.MiniGameMessage; +import net.knarcraft.minigames.util.RewardHelper; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; + +/** + * The command used for setting arena rewards + */ +public class SetArenaRewardCommand implements CommandExecutor { + + @Override + public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, + @NotNull String[] arguments) { + if (!(commandSender instanceof Player player)) { + MiniGames.getInstance().getStringFormatter().displayErrorMessage(commandSender, + MiniGameMessage.ERROR_PLAYER_ONLY); + return false; + } + + if (arguments.length < 4) { + return false; + } + + /* + + /MiniGamesReward add dropperThe player to reward
+ * @param rewardsThe rewards to give
+ */ + public static void grantRewards(@NotNull Player player, @NotNull CollectionThe player that specified the reward
+ * @param typeStringThe string given to specify the reward type
+ * @param firstArgumentThe first reward argument given by the player, or null
+ * @param secondArgumentThe second reward argument given by the player, or null
+ * @param allArgumentsA list of all the reward arguments, in case the reward is a command reward
+ * @returnThe parsed reward, or null if some input was invalid
+ */ + public static @Nullable Reward parseRewardInput(@NotNull Player player, + @NotNull String typeString, + @Nullable String firstArgument, + @Nullable String secondArgument, + @NotNull String[] allArguments) { + RewardType rewardType = RewardType.getFromString(typeString); + if (rewardType == null) { + MiniGames.getInstance().getStringFormatter().displayErrorMessage(player, + MiniGameMessage.ERROR_REWARD_TYPE_INVALID); + return null; + } + + if (rewardType != RewardType.ITEM && firstArgument == null) { + return null; + } + + try { + return switch (rewardType) { + case COMMAND -> new CommandReward(getArrayAsString(allArguments)); + case ECONOMY -> new EconomyReward(getDouble(firstArgument)); + case PERMISSION -> new PermissionReward(getWorld(secondArgument), firstArgument); + case ITEM -> new ItemReward(getItem(player, firstArgument, secondArgument)); + }; + } catch (IllegalArgumentException exception) { + MiniGames.getInstance().getStringFormatter().displayErrorMessage(player, exception.getMessage()); + return null; + } + } + + /** + * Gets a double from the given input + * + * @param inputThe input representing a double
+ * @returnThe double specified
+ * @throws IllegalArgumentExceptionIf the input is not a number or is not positive
+ */ + private static double getDouble(@NotNull String input) throws IllegalArgumentException { + IllegalArgumentException invalidException = new IllegalArgumentException( + MiniGames.getInstance().getTranslator().getTranslatedMessage(MiniGameMessage.ERROR_INVALID_NUMBER)); + try { + double number = Double.parseDouble(input); + if (number <= 0) { + throw invalidException; + } + return number; + } catch (NumberFormatException exception) { + throw invalidException; + } + } + + /** + * Gets the world specified in the given identifier + * + * @param worldIdentifierA world UUID or name
+ * @returnThe world, or null if no such world exists
+ */ + private static @Nullable World getWorld(@Nullable String worldIdentifier) { + if (worldIdentifier == null || worldIdentifier.isBlank()) { + return null; + } + World world; + try { + UUID worldId = UUID.fromString(worldIdentifier); + world = Bukkit.getWorld(worldId); + } catch (IllegalArgumentException exception) { + world = Bukkit.getWorld(worldIdentifier); + } + if (world != null) { + return world; + } else { + throw new IllegalArgumentException(MiniGames.getInstance().getTranslator().getTranslatedMessage( + MiniGameMessage.ERROR_INVALID_WORLD)); + } + } + + /** + * Gets an item stack according to the given input + * + * @param playerThe player that caused this method to execute
+ * @param argument1The first argument given by the player, or null
+ * @param argument2The second argument given by the player, or null
+ * @returnAn item stack as described, or the player's held item
+ * @throws IllegalArgumentExceptionIf an invalid material was specified
+ */ + private static @NotNull ItemStack getItem(@NotNull Player player, @Nullable String argument1, + @Nullable String argument2) throws IllegalArgumentException { + if (argument1 != null) { + Material material = MaterialHelper.loadMaterialString(argument1, MiniGames.getInstance().getLogger()); + int amount; + try { + if (argument2 != null) { + amount = Integer.parseInt(argument2); + } else { + amount = 1; + } + } catch (NumberFormatException exception) { + amount = 1; + } + if (material == null || material.isAir()) { + throw new IllegalArgumentException(MiniGames.getInstance().getTranslator().getTranslatedMessage( + MiniGameMessage.ERROR_INVALID_MATERIAL)); + } + return new ItemStack(material, amount); + } else { + ItemStack inHand = player.getInventory().getItemInMainHand(); + if (!inHand.getType().isAir()) { + return inHand; + } else { + throw new IllegalArgumentException(MiniGames.getInstance().getTranslator().getTranslatedMessage( + MiniGameMessage.ERROR_INVALID_MATERIAL)); + } + } + } + + /** + * Gets the string array as a space separated string + * + * @param arrayThe array to get as a string
+ * @returnThe array as a string
+ */ + private static String getArrayAsString(@NotNull String[] array) { + String output = String.join(" ", array); + if (output.isBlank()) { + throw new IllegalArgumentException(MiniGames.getInstance().getTranslator().getTranslatedMessage( + MiniGameMessage.ERROR_INVALID_COMMAND_STRING)); + } else { + return output; + } + } + +} diff --git a/src/main/java/net/knarcraft/minigames/util/RewardStorageHelper.java b/src/main/java/net/knarcraft/minigames/util/RewardStorageHelper.java new file mode 100644 index 0000000..ae4a552 --- /dev/null +++ b/src/main/java/net/knarcraft/minigames/util/RewardStorageHelper.java @@ -0,0 +1,67 @@ +package net.knarcraft.minigames.util; + +import net.knarcraft.minigames.arena.Arena; +import net.knarcraft.minigames.arena.reward.Reward; +import net.knarcraft.minigames.arena.reward.RewardCondition; +import org.bukkit.configuration.ConfigurationSection; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * A helper class for loading and storing rewards + */ +public class RewardStorageHelper { + + /** + * Loads the rewards contained at the given path + * + * @param configurationSectionThe configuration section containing the reward
+ * @param keyThe section key to search
+ * @returnThe loaded rewards
+ */ + public static MapThe arena to save rewards for
+ * @param configurationSectionThe configuration section to save the rewards at
+ * @param keyThe section key to save at
+ */ + public static void saveRewards(@NotNull Arena arena, @NotNull ConfigurationSection configurationSection, + @NotNull String key) { + for (RewardCondition condition : RewardCondition.values()) { + configurationSection.set(key + "." + condition.name(), + new ArrayList<>(arena.getRewards(condition))); + } + } + +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 07c19c0..7d04a3c 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -28,6 +28,12 @@ commands: - mmenu usage: /