From 8ea930a5f3ea3d68da0e340a443dfc16509a09fc Mon Sep 17 00:00:00 2001 From: EpicKnarvik97 Date: Sun, 9 Jul 2023 18:20:31 +0200 Subject: [PATCH] Makes all messages configurable --- README.md | 14 + pom.xml | 12 + .../net/knarcraft/minigames/MiniGames.java | 46 +++ .../minigames/arena/AbstractArenaSession.java | 21 +- .../minigames/arena/dropper/DropperArena.java | 2 +- .../arena/dropper/DropperArenaHandler.java | 13 +- .../arena/dropper/DropperArenaSession.java | 9 +- .../minigames/arena/parkour/ParkourArena.java | 9 +- .../arena/parkour/ParkourArenaHandler.java | 13 +- .../arena/parkour/ParkourArenaSession.java | 8 +- .../minigames/command/LeaveArenaCommand.java | 8 +- .../minigames/command/MenuCommand.java | 6 +- .../minigames/command/ReloadCommand.java | 5 +- .../dropper/CreateDropperArenaCommand.java | 11 +- .../dropper/DropperGroupListCommand.java | 11 +- .../dropper/DropperGroupSetCommand.java | 8 +- .../dropper/DropperGroupSwapCommand.java | 12 +- .../dropper/EditDropperArenaCommand.java | 21 +- .../dropper/JoinDropperArenaCommand.java | 25 +- .../dropper/ListDropperArenaCommand.java | 8 +- .../dropper/RemoveDropperArenaCommand.java | 9 +- .../parkour/CreateParkourArenaCommand.java | 10 +- .../parkour/EditParkourArenaCommand.java | 21 +- .../parkour/JoinParkourArenaCommand.java | 24 +- .../parkour/ListParkourArenaCommand.java | 8 +- .../parkour/ParkourGroupListCommand.java | 11 +- .../parkour/ParkourGroupSetCommand.java | 8 +- .../parkour/ParkourGroupSwapCommand.java | 12 +- .../parkour/RemoveParkourArenaCommand.java | 9 +- .../knarcraft/minigames/config/Message.java | 305 ------------------ .../config/MiniGameConfiguration.java | 5 +- .../minigames/config/MiniGameMessage.java | 238 ++++++++++++++ .../container/PlaceholderContainer.java | 41 --- .../minigames/listener/CommandListener.java | 4 +- .../minigames/listener/InteractListener.java | 2 - .../minigames/listener/MoveListener.java | 5 +- .../minigames/property/PersistentDataKey.java | 1 - .../minigames/util/ArenaStorageHelper.java | 2 +- .../knarcraft/minigames/util/ColorHelper.java | 29 -- .../util/DropperArenaStorageHelper.java | 12 +- .../minigames/util/MaterialHelper.java | 77 ----- .../util/ParkourArenaStorageHelper.java | 12 +- .../minigames/util/PlayerTeleporter.java | 8 +- src/main/resources/config.yml | 3 + src/main/resources/strings.yml | 43 +++ 45 files changed, 563 insertions(+), 598 deletions(-) delete mode 100644 src/main/java/net/knarcraft/minigames/config/Message.java create mode 100644 src/main/java/net/knarcraft/minigames/config/MiniGameMessage.java delete mode 100644 src/main/java/net/knarcraft/minigames/container/PlaceholderContainer.java delete mode 100644 src/main/java/net/knarcraft/minigames/util/ColorHelper.java delete mode 100644 src/main/java/net/knarcraft/minigames/util/MaterialHelper.java create mode 100644 src/main/resources/strings.yml diff --git a/README.md b/README.md index 4f084d8..85f68f7 100644 --- a/README.md +++ b/README.md @@ -259,6 +259,20 @@ Example tags: - +FENCE_GATES - +FENCES +## Language customization + +Most or all strings are customizable. If you place a strings.yml file in the plugin folder, it will take +priority over built-in languages. If you want to change strings, look at MiniGames/src/main/resources/strings.yml for +the proper keys. All strings have the format: ENUM: "Displayed string". The enum must be identical as it defines which +string you have changed. All strings belonging to a language are beneath the language code and indented with two spaces. + +The easiest way to add a new language is to copy an existing language and paste it into your custom strings.yml and +change strings as necessary. If you don't include all strings, the remaining will use the built-in English translation. +Remember to change the language code to whichever you use for your custom language. + +The interval messages are unique in that if several values are separated by comma (option1,option2,option3), a random +message will be chosen each time it's displayed. + ## License MiniGames is licensed under the GNU Public License Version 3.0. This includes every source and resource file. See the diff --git a/pom.xml b/pom.xml index 7f7c102..67c25eb 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,12 @@ false + + net.knarcraft:knarlib + + net/knarcraft/knarlib/** + + net.knarcraft:knargui @@ -113,5 +119,11 @@ 1.0-SNAPSHOT compile + + net.knarcraft + knarlib + 1.2.3 + compile + diff --git a/src/main/java/net/knarcraft/minigames/MiniGames.java b/src/main/java/net/knarcraft/minigames/MiniGames.java index 2a34c74..6ee55b8 100644 --- a/src/main/java/net/knarcraft/minigames/MiniGames.java +++ b/src/main/java/net/knarcraft/minigames/MiniGames.java @@ -1,6 +1,9 @@ package net.knarcraft.minigames; import net.knarcraft.knargui.GUIListener; +import net.knarcraft.knarlib.formatting.StringFormatter; +import net.knarcraft.knarlib.formatting.Translator; +import net.knarcraft.knarlib.property.ColorConversion; import net.knarcraft.minigames.arena.ArenaPlayerRegistry; import net.knarcraft.minigames.arena.ArenaSession; import net.knarcraft.minigames.arena.PlayerVisibilityManager; @@ -48,6 +51,7 @@ import net.knarcraft.minigames.command.parkour.ParkourGroupSwapCommand; import net.knarcraft.minigames.command.parkour.RemoveParkourArenaCommand; import net.knarcraft.minigames.command.parkour.RemoveParkourArenaTabCompleter; import net.knarcraft.minigames.config.DropperConfiguration; +import net.knarcraft.minigames.config.MiniGameMessage; import net.knarcraft.minigames.config.ParkourConfiguration; import net.knarcraft.minigames.config.SharedConfiguration; import net.knarcraft.minigames.container.SerializableMaterial; @@ -59,6 +63,7 @@ import net.knarcraft.minigames.listener.MoveListener; import net.knarcraft.minigames.listener.PlayerStateChangeListener; import net.knarcraft.minigames.placeholder.DropperRecordExpansion; import net.knarcraft.minigames.placeholder.ParkourRecordExpansion; +import net.md_5.bungee.api.ChatColor; import org.bukkit.Bukkit; import org.bukkit.command.CommandExecutor; import org.bukkit.command.PluginCommand; @@ -89,6 +94,8 @@ public final class MiniGames extends JavaPlugin { private ParkourArenaHandler parkourArenaHandler; private ArenaPlayerRegistry parkourArenaPlayerRegistry; private PlayerVisibilityManager playerVisibilityManager; + private Translator translator; + private StringFormatter stringFormatter; /** * Gets an instance of this plugin @@ -173,6 +180,24 @@ public final class MiniGames extends JavaPlugin { return this.playerVisibilityManager; } + /** + * Gets the translator to get messages from + * + * @return

The translator

+ */ + public Translator getTranslator() { + return this.translator; + } + + /** + * Gets the string formatter to get formatted messages from + * + * @return

The string formatter

+ */ + public StringFormatter getStringFormatter() { + return this.stringFormatter; + } + /** * Gets the current session of the given player * @@ -208,6 +233,8 @@ public final class MiniGames extends JavaPlugin { // Reload configuration this.reloadConfig(); + translator.loadLanguages(this.getDataFolder(), "en", + getConfig().getString("language", "en")); this.sharedConfiguration.load(this.getConfig()); this.dropperConfiguration.load(this.getConfig()); this.parkourConfiguration.load(this.getConfig()); @@ -290,6 +317,9 @@ public final class MiniGames extends JavaPlugin { getConfig().options().copyDefaults(true); saveConfig(); reloadConfig(); + + setupStringFormatter(); + this.sharedConfiguration = new SharedConfiguration(this.getConfig()); this.dropperConfiguration = new DropperConfiguration(this.getConfig()); this.parkourConfiguration = new ParkourConfiguration(this.getConfig()); @@ -375,4 +405,20 @@ public final class MiniGames extends JavaPlugin { registerCommand("parkourGroupList", new ParkourGroupListCommand(), null); } + /** + * Sets up the translator and the string formatter + */ + private void setupStringFormatter() { + translator = new Translator(); + translator.registerMessageCategory(MiniGameMessage.ERROR_PLAYER_ONLY); + translator.loadLanguages(this.getDataFolder(), "en", + getConfig().getString("language", "en")); + stringFormatter = new StringFormatter(this.getDescription().getName(), translator); + stringFormatter.setColorConversion(ColorConversion.RGB); + stringFormatter.setNamePrefix("#546EED[&r&l"); + stringFormatter.setNameSuffix("#546EED]"); + stringFormatter.setErrorColor(ChatColor.RED); + stringFormatter.setSuccessColor(ChatColor.GREEN); + } + } diff --git a/src/main/java/net/knarcraft/minigames/arena/AbstractArenaSession.java b/src/main/java/net/knarcraft/minigames/arena/AbstractArenaSession.java index 971eece..16362fb 100644 --- a/src/main/java/net/knarcraft/minigames/arena/AbstractArenaSession.java +++ b/src/main/java/net/knarcraft/minigames/arena/AbstractArenaSession.java @@ -1,8 +1,8 @@ package net.knarcraft.minigames.arena; +import net.knarcraft.knarlib.formatting.StringFormatter; import net.knarcraft.minigames.MiniGames; -import net.knarcraft.minigames.config.Message; -import net.knarcraft.minigames.container.PlaceholderContainer; +import net.knarcraft.minigames.config.MiniGameMessage; import net.knarcraft.minigames.property.RecordResult; import net.knarcraft.minigames.util.PlayerTeleporter; import org.bukkit.Location; @@ -44,7 +44,7 @@ public abstract class AbstractArenaSession implements ArenaSession { // Make the player visible to everyone MiniGames.getInstance().getPlayerVisibilityManager().showPlayersFor(player); - player.sendMessage(Message.SUCCESS_ARENA_QUIT.getMessage()); + MiniGames.getInstance().getStringFormatter().displaySuccessMessage(player, MiniGameMessage.SUCCESS_ARENA_QUIT); } @Override @@ -69,16 +69,17 @@ public abstract class AbstractArenaSession implements ArenaSession { // Gets a string representation of the played game-mode String gameModeString = getGameModeString(); - Message recordInfoMessage = switch (recordResult) { - case WORLD_RECORD -> Message.RECORD_ACHIEVED_GLOBAL; - case PERSONAL_BEST -> Message.RECORD_ACHIEVED_PERSONAL; + MiniGameMessage recordInfoMiniGameMessage = switch (recordResult) { + case WORLD_RECORD -> MiniGameMessage.RECORD_ACHIEVED_GLOBAL; + case PERSONAL_BEST -> MiniGameMessage.RECORD_ACHIEVED_PERSONAL; default -> throw new IllegalStateException("Unexpected value: " + recordResult); }; - String recordInfo = recordInfoMessage.getPartialMessage("{recordType}", type); + StringFormatter stringFormatter = MiniGames.getInstance().getStringFormatter(); + String recordInfo = stringFormatter.replacePlaceholder(recordInfoMiniGameMessage, "{recordType}", type); - PlaceholderContainer placeholderContainer = new PlaceholderContainer().add("{gameMode}", gameModeString); - placeholderContainer.add("{recordInfo}", recordInfo); - player.sendMessage(Message.SUCCESS_RECORD_ACHIEVED.getMessage(placeholderContainer)); + stringFormatter.displaySuccessMessage(player, stringFormatter.replacePlaceholders( + MiniGameMessage.SUCCESS_RECORD_ACHIEVED, new String[]{"{gameMode}", "{recordInfo}"}, + new String[]{gameModeString, recordInfo})); } /** diff --git a/src/main/java/net/knarcraft/minigames/arena/dropper/DropperArena.java b/src/main/java/net/knarcraft/minigames/arena/dropper/DropperArena.java index eb5cbc0..ba3d627 100644 --- a/src/main/java/net/knarcraft/minigames/arena/dropper/DropperArena.java +++ b/src/main/java/net/knarcraft/minigames/arena/dropper/DropperArena.java @@ -206,7 +206,7 @@ public class DropperArena implements Arena { try { DropperArenaStorageHelper.saveDropperArenaData(getData()); return true; - } catch (IOException e) { + } catch (IOException exception) { return false; } } diff --git a/src/main/java/net/knarcraft/minigames/arena/dropper/DropperArenaHandler.java b/src/main/java/net/knarcraft/minigames/arena/dropper/DropperArenaHandler.java index bc07a47..1bb3f5b 100644 --- a/src/main/java/net/knarcraft/minigames/arena/dropper/DropperArenaHandler.java +++ b/src/main/java/net/knarcraft/minigames/arena/dropper/DropperArenaHandler.java @@ -3,7 +3,7 @@ package net.knarcraft.minigames.arena.dropper; import net.knarcraft.minigames.MiniGames; import net.knarcraft.minigames.arena.ArenaHandler; import net.knarcraft.minigames.arena.ArenaPlayerRegistry; -import net.knarcraft.minigames.config.Message; +import net.knarcraft.minigames.config.MiniGameMessage; import net.knarcraft.minigames.util.DropperArenaStorageHelper; import java.io.IOException; @@ -32,9 +32,10 @@ public class DropperArenaHandler extends ArenaHandler(this.arenaGroups.values())); - } catch (IOException e) { - MiniGames.log(Level.SEVERE, Message.ERROR_CANNOT_SAVE_ARENA_GROUPS.getMessage()); - MiniGames.log(Level.SEVERE, e.getMessage()); + } catch (IOException exception) { + MiniGames.log(Level.SEVERE, MiniGames.getInstance().getTranslator().getTranslatedMessage( + MiniGameMessage.ERROR_CANNOT_SAVE_ARENA_GROUPS)); + MiniGames.log(Level.SEVERE, exception.getMessage()); } } @@ -54,10 +55,10 @@ public class DropperArenaHandler extends ArenaHandler(killPlaneBlockNames)); + new ArrayList<>(killPlaneBlockNames), "+", MiniGames.getInstance().getLogger()); this.checkpoints = checkpoints; this.parkourArenaData = parkourArenaData; this.parkourArenaHandler = arenaHandler; @@ -250,7 +250,7 @@ public class ParkourArena implements Arena { try { ParkourArenaStorageHelper.saveParkourArenaData(getData()); return true; - } catch (IOException e) { + } catch (IOException exception) { return false; } } @@ -366,7 +366,8 @@ public class ParkourArena implements Arena { if (killPlaneBlockNames.isEmpty()) { this.killPlaneBlocks = null; } else { - Set parsed = MaterialHelper.loadMaterialList(new ArrayList<>(killPlaneBlockNames)); + Set parsed = MaterialHelper.loadMaterialList(new ArrayList<>(killPlaneBlockNames), "+", + MiniGames.getInstance().getLogger()); if (parsed.isEmpty()) { return false; } diff --git a/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArenaHandler.java b/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArenaHandler.java index 7e52ff6..ba769da 100644 --- a/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArenaHandler.java +++ b/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArenaHandler.java @@ -3,7 +3,7 @@ package net.knarcraft.minigames.arena.parkour; import net.knarcraft.minigames.MiniGames; import net.knarcraft.minigames.arena.ArenaHandler; import net.knarcraft.minigames.arena.ArenaPlayerRegistry; -import net.knarcraft.minigames.config.Message; +import net.knarcraft.minigames.config.MiniGameMessage; import net.knarcraft.minigames.util.ParkourArenaStorageHelper; import java.io.IOException; @@ -32,9 +32,10 @@ public class ParkourArenaHandler extends ArenaHandler(this.arenaGroups.values())); - } catch (IOException e) { - MiniGames.log(Level.SEVERE, Message.ERROR_CANNOT_SAVE_ARENA_GROUPS.getMessage()); - MiniGames.log(Level.SEVERE, e.getMessage()); + } catch (IOException exception) { + MiniGames.log(Level.SEVERE, MiniGames.getInstance().getTranslator().getTranslatedMessage( + MiniGameMessage.ERROR_CANNOT_SAVE_ARENA_GROUPS)); + MiniGames.log(Level.SEVERE, exception.getMessage()); } } @@ -54,10 +55,10 @@ public class ParkourArenaHandler extends ArenaHandlerThis should in theory be impossible, as players cannot use any commands except /miniGamesLeave while playing - * in an arena.

- */ - ERROR_ALREADY_PLAYING("&cYou are already playing a mini-game!"), - - /** - * The message displayed if a player tries to join an arena with a passenger or riding a vehicle - */ - ERROR_JOIN_IN_VEHICLE_OR_PASSENGER("&cYou cannot join an arena while inside a vehicle or carrying a passenger."), - - /** - * The message displayed if the player tries to change an unrecognized arena property - */ - ERROR_UNKNOWN_PROPERTY("&cUnknown property specified."), - - /** - * The message displayed if the given input to /dEdit or /pEdit's value is invalid - */ - ERROR_PROPERTY_INPUT_INVALID("&cUnable to change the property. Make sure your input is valid!"), - - /** - * The message displayed if the first arena specified in /dgSwap or /pgSwap is invalid - */ - ERROR_ARENA_1_NOT_FOUND("&cUnable to find the first specified arena."), - - /** - * The message displayed if the second arena specified in /dgSwap or /pgSwap is invalid - */ - ERROR_ARENA_2_NOT_FOUND("&cUnable to find the second specified dropper arena."), - - /** - * The message displayed if the two groups specified for /dgSwap or /pgSwap are in different arenas - */ - ERROR_SWAP_DIFFERENT_GROUPS("&cYou cannot swap arenas in different groups!"), - - /** - * The message displayed if a player tries to use any command other than /mLeave while in an arena - */ - ERROR_ILLEGAL_COMMAND("&cYou cannot use that command while in an arena!"), - - /** - * The message displayed if the player is trying to join a parkour arena on hardcore which has no checkpoints - */ - ERROR_HARDCORE_NO_CHECKPOINTS("&cThis arena cannot be played in hardcore mode as it has no checkpoints!"), - - /* **************** * - * Success messages * - * **************** */ - - /** - * The message displayed if an arena's group has been changed - */ - SUCCESS_ARENA_GROUP_UPDATED("&aThe arena's group has been updated"), - - /** - * The message displayed if the MiniGames plugin is reloaded - */ - SUCCESS_PLUGIN_RELOADED("&aPlugin reloaded!"), - - /** - * The message displayed if a new arena has been created - */ - SUCCESS_ARENA_CREATED("&aThe arena was successfully created!"), - - /** - * The message displayed if a player clears/wins an arena for the first time - */ - SUCCESS_ARENA_FIRST_CLEAR("&aYou cleared the arena!"), - - /** - * The message displayed when a player wins an arena - */ - SUCCESS_ARENA_WIN("&aYou won!"), - - /** - * The message displayed when a player quits an arena - */ - SUCCESS_ARENA_QUIT("&aYou quit the arena!"), - - /** - * The message used to display the current value of an arena property - */ - SUCCESS_CURRENT_VALUE("&aCurrent value of {property} is: {value}"), - - /** - * The message used to announce that an arena property has been changed - */ - SUCCESS_PROPERTY_CHANGED("&aProperty {property} successfully changed"), - - /** - * The message displayed when two arenas' order in a group have been swapped - */ - SUCCESS_ARENAS_SWAPPED("&aThe arenas have been swapped!"), - - /** - * The message displayed when an arena has been removed - */ - SUCCESS_ARENA_REMOVED("&aThe specified arena has been successfully removed"), - - /** - * The header displayed before listing all dropper arenas - */ - SUCCESS_DROPPER_ARENAS_LIST("&aDropper arenas:&r"), - - /** - * The header displayed before listing all parkour arenas - */ - SUCCESS_PARKOUR_ARENAS_LIST("&aParkour arenas:&r"), - - /** - * The message displayed when a player reaches a new checkpoint in a parkour arena - */ - SUCCESS_CHECKPOINT_REACHED("&aCheckpoint reached!"), - - /** - * The header displayed before listing all arenas (stages) in a group - */ - SUCCESS_GROUP_STAGES("&a{group}'s stages:&r"), - - /** - * The message displayed when a new record has been achieved - */ - SUCCESS_RECORD_ACHIEVED("&aYou just set a {recordInfo} on the {gameMode} game-mode!"), - - /** - * The partial message used to describe that the player achieved a world record - */ - RECORD_ACHIEVED_GLOBAL("new {recordType} record"), - - /** - * The partial message used to describe that the player achieved a personal best record - */ - RECORD_ACHIEVED_PERSONAL("personal {recordType} record"), - - /** - * The message displayed when a player joins an arena - */ - SUCCESS_ARENA_JOINED("&aYou joined the arena."), - ; - - private final @NotNull String defaultMessage; - - /** - * Instantiates a new message - * - * @param defaultMessage

The default value of the message

- */ - Message(@NotNull String defaultMessage) { - this.defaultMessage = defaultMessage; - } - - /** - * Gets the message this enum represents - * - * @return

The formatted message

- */ - public @NotNull String getMessage() { - return formatMessage(this.defaultMessage); - } - - /** - * Gets the message this enum represents - * - * @param placeholder

The placeholder to replace

- * @param replacement

The replacement to use

- * @return

The formatted message

- */ - public @NotNull String getMessage(@NotNull String placeholder, @NotNull String replacement) { - return formatMessage(this.defaultMessage.replace(placeholder, replacement)); - } - - /** - * Gets the message this enum represents, intended for display within another message - * - * @param placeholder

The placeholder to replace

- * @param replacement

The replacement to use

- * @return

The formatted message

- */ - public @NotNull String getPartialMessage(@NotNull String placeholder, @NotNull String replacement) { - return ColorHelper.translateAllColorCodes(this.defaultMessage.replace(placeholder, replacement)); - } - - /** - * Gets the message this enum represents - * - * @param placeholders

The placeholder -> replacement map specifying necessary replacements

- * @return

The formatted message

- */ - public @NotNull String getMessage(@NotNull PlaceholderContainer placeholders) { - String replaced = this.defaultMessage; - for (Map.Entry entry : placeholders.getPlaceholders().entrySet()) { - replaced = replaced.replace(entry.getKey(), entry.getValue()); - } - return formatMessage(replaced); - } - - /** - * Gets the formatted version of the given message - * - * @param message

The message to format

- * @return

The formatted message

- */ - private @NotNull String formatMessage(@NotNull String message) { - String prefix = MiniGames.getInstance().getDescription().getPrefix(); - return ColorHelper.translateAllColorCodes("#546EED[&r&l" + prefix + "#546EED]&r " + message); - } - -} diff --git a/src/main/java/net/knarcraft/minigames/config/MiniGameConfiguration.java b/src/main/java/net/knarcraft/minigames/config/MiniGameConfiguration.java index 6786308..d9ba06e 100644 --- a/src/main/java/net/knarcraft/minigames/config/MiniGameConfiguration.java +++ b/src/main/java/net/knarcraft/minigames/config/MiniGameConfiguration.java @@ -1,6 +1,7 @@ package net.knarcraft.minigames.config; -import net.knarcraft.minigames.util.MaterialHelper; +import net.knarcraft.knarlib.util.MaterialHelper; +import net.knarcraft.minigames.MiniGames; import org.bukkit.Material; import org.bukkit.configuration.file.FileConfiguration; import org.jetbrains.annotations.NotNull; @@ -46,7 +47,7 @@ public abstract class MiniGameConfiguration { */ public @NotNull Set loadMaterialList(@NotNull String path) { List blockWhitelist = configuration.getList(path, new ArrayList<>()); - return MaterialHelper.loadMaterialList(blockWhitelist); + return MaterialHelper.loadMaterialList(blockWhitelist, "+", MiniGames.getInstance().getLogger()); } } diff --git a/src/main/java/net/knarcraft/minigames/config/MiniGameMessage.java b/src/main/java/net/knarcraft/minigames/config/MiniGameMessage.java new file mode 100644 index 0000000..4fb9d62 --- /dev/null +++ b/src/main/java/net/knarcraft/minigames/config/MiniGameMessage.java @@ -0,0 +1,238 @@ +package net.knarcraft.minigames.config; + +import net.knarcraft.knarlib.formatting.TranslatableMessage; +import org.jetbrains.annotations.NotNull; + +/** + * A message which ca be displayed to the user + */ +public enum MiniGameMessage implements TranslatableMessage { + + /* ************** * + * Error messages * + * ************** */ + + /** + * The message displayed if saving arena groups fails + */ + ERROR_CANNOT_SAVE_ARENA_GROUPS, + + /** + * The message displayed if an un-parse-able message is given by a user + */ + ERROR_MATERIAL_NOT_PARSE_ABLE, + + /** + * The message displayed if a player tries to be teleported to/from an arena with a passenger + */ + ERROR_TELEPORT_WITH_PASSENGER, + + /** + * The message displayed if a player tries to be teleported to/from an arena with a vehicle + */ + ERROR_TELEPORT_IN_VEHICLE, + + /** + * The message displayed if an arena cannot be loaded + */ + ERROR_ARENA_NOT_LOADED, + + /** + * The message displayed if an arena's data cannot be loaded + */ + ERROR_ARENA_DATA_NOT_LOADED, + + /** + * The message displayed if the user specifies an unrecognized arena + */ + ERROR_ARENA_NOT_FOUND, + + /** + * The message displayed if the user specifies an unrecognized group + */ + ERROR_GROUP_NOT_FOUND, + + /** + * The message displayed if the console tries to execute a player-only command + */ + ERROR_PLAYER_ONLY, + + /** + * The message displayed if the name of an arena is duplicated + */ + ERROR_ARENA_NAME_COLLISION, + + /** + * The message displayed if the player is required to win on the default difficulty first + */ + ERROR_NORMAL_MODE_REQUIRED, + + /** + * The message displayed if the player is required to win on the default difficulty for all arenas in the group first + */ + ERROR_GROUP_NORMAL_MODE_REQUIRED, + + /** + * The message displayed if the player is required to beat the previous arena in the group + */ + ERROR_PREVIOUS_ARENA_REQUIRED, + + /** + * The message displayed if player teleportation failed for some reason + */ + ERROR_ARENA_TELEPORT_FAILED, + + /** + * The message displayed if the player tries to quit the arena while not in an arena + */ + ERROR_NOT_IN_ARENA, + + /** + * The message displayed if the player tries to join an arena while already playing + * + *

This should in theory be impossible, as players cannot use any commands except /miniGamesLeave while playing + * in an arena.

+ */ + ERROR_ALREADY_PLAYING, + + /** + * The message displayed if a player tries to join an arena with a passenger or riding a vehicle + */ + ERROR_JOIN_IN_VEHICLE_OR_PASSENGER, + + /** + * The message displayed if the player tries to change an unrecognized arena property + */ + ERROR_UNKNOWN_PROPERTY, + + /** + * The message displayed if the given input to /dEdit or /pEdit's value is invalid + */ + ERROR_PROPERTY_INPUT_INVALID, + + /** + * The message displayed if the first arena specified in /dgSwap or /pgSwap is invalid + */ + ERROR_ARENA_1_NOT_FOUND, + + /** + * The message displayed if the second arena specified in /dgSwap or /pgSwap is invalid + */ + ERROR_ARENA_2_NOT_FOUND, + + /** + * The message displayed if the two groups specified for /dgSwap or /pgSwap are in different arenas + */ + ERROR_SWAP_DIFFERENT_GROUPS, + + /** + * The message displayed if a player tries to use any command other than /mLeave while in an arena + */ + ERROR_ILLEGAL_COMMAND, + + /** + * The message displayed if the player is trying to join a parkour arena on hardcore which has no checkpoints + */ + ERROR_HARDCORE_NO_CHECKPOINTS, + + /* **************** * + * Success messages * + * **************** */ + + /** + * The message displayed if an arena's group has been changed + */ + SUCCESS_ARENA_GROUP_UPDATED, + + /** + * The message displayed if the MiniGames plugin is reloaded + */ + SUCCESS_PLUGIN_RELOADED, + + /** + * The message displayed if a new arena has been created + */ + SUCCESS_ARENA_CREATED, + + /** + * The message displayed if a player clears/wins an arena for the first time + */ + SUCCESS_ARENA_FIRST_CLEAR, + + /** + * The message displayed when a player wins an arena + */ + SUCCESS_ARENA_WIN, + + /** + * The message displayed when a player quits an arena + */ + SUCCESS_ARENA_QUIT, + + /** + * The message used to display the current value of an arena property + */ + SUCCESS_CURRENT_VALUE, + + /** + * The message used to announce that an arena property has been changed + */ + SUCCESS_PROPERTY_CHANGED, + + /** + * The message displayed when two arenas' order in a group have been swapped + */ + SUCCESS_ARENAS_SWAPPED, + + /** + * The message displayed when an arena has been removed + */ + SUCCESS_ARENA_REMOVED, + + /** + * The header displayed before listing all dropper arenas + */ + SUCCESS_DROPPER_ARENAS_LIST, + + /** + * The header displayed before listing all parkour arenas + */ + SUCCESS_PARKOUR_ARENAS_LIST, + + /** + * The message displayed when a player reaches a new checkpoint in a parkour arena + */ + SUCCESS_CHECKPOINT_REACHED, + + /** + * The header displayed before listing all arenas (stages) in a group + */ + SUCCESS_GROUP_STAGES, + + /** + * The message displayed when a new record has been achieved + */ + SUCCESS_RECORD_ACHIEVED, + + /** + * The partial message used to describe that the player achieved a world record + */ + RECORD_ACHIEVED_GLOBAL, + + /** + * The partial message used to describe that the player achieved a personal best record + */ + RECORD_ACHIEVED_PERSONAL, + + /** + * The message displayed when a player joins an arena + */ + SUCCESS_ARENA_JOINED, + ; + + @Override + public @NotNull TranslatableMessage[] getAllMessages() { + return MiniGameMessage.values(); + } + +} diff --git a/src/main/java/net/knarcraft/minigames/container/PlaceholderContainer.java b/src/main/java/net/knarcraft/minigames/container/PlaceholderContainer.java deleted file mode 100644 index ca88158..0000000 --- a/src/main/java/net/knarcraft/minigames/container/PlaceholderContainer.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.knarcraft.minigames.container; - -import java.util.HashMap; -import java.util.Map; - -/** - * A container for keeping track of several placeholder to value mappings - */ -public class PlaceholderContainer { - - private final Map placeholders; - - /** - * Instantiates a new placeholder container - */ - public PlaceholderContainer() { - this.placeholders = new HashMap<>(); - } - - /** - * Gets all placeholders - * - * @return

All placeholders

- */ - public Map getPlaceholders() { - return new HashMap<>(this.placeholders); - } - - /** - * Adds a new placeholder - * - * @param placeholder

The placeholder to register

- * @param value

The value of the placeholder

- * @return

This object

- */ - public PlaceholderContainer add(String placeholder, String value) { - this.placeholders.put(placeholder, value); - return this; - } - -} diff --git a/src/main/java/net/knarcraft/minigames/listener/CommandListener.java b/src/main/java/net/knarcraft/minigames/listener/CommandListener.java index 7557242..7d64d86 100644 --- a/src/main/java/net/knarcraft/minigames/listener/CommandListener.java +++ b/src/main/java/net/knarcraft/minigames/listener/CommandListener.java @@ -2,7 +2,7 @@ package net.knarcraft.minigames.listener; import net.knarcraft.minigames.MiniGames; import net.knarcraft.minigames.arena.ArenaSession; -import net.knarcraft.minigames.config.Message; +import net.knarcraft.minigames.config.MiniGameMessage; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -43,7 +43,7 @@ public class CommandListener implements Listener { } } - player.sendMessage(Message.ERROR_ILLEGAL_COMMAND.getMessage()); + MiniGames.getInstance().getStringFormatter().displayErrorMessage(player, MiniGameMessage.ERROR_ILLEGAL_COMMAND); event.setCancelled(true); } diff --git a/src/main/java/net/knarcraft/minigames/listener/InteractListener.java b/src/main/java/net/knarcraft/minigames/listener/InteractListener.java index fe96318..c16b95b 100644 --- a/src/main/java/net/knarcraft/minigames/listener/InteractListener.java +++ b/src/main/java/net/knarcraft/minigames/listener/InteractListener.java @@ -46,8 +46,6 @@ public class InteractListener implements Listener { ArenaGUI.getLeaveAction().run(event.getPlayer()); } else if (persistentData == PersistentDataKey.GIVE_UP_ITEM.getDataValue()) { ParkourGUI.getGiveUpAction().run(event.getPlayer()); - } else if (persistentData == PersistentDataKey.TOGGLE_PLAYERS_ITEM.getDataValue()) { - //TODO: Figure out how in the world this should be done, as the existing code cannot be re-used } } } diff --git a/src/main/java/net/knarcraft/minigames/listener/MoveListener.java b/src/main/java/net/knarcraft/minigames/listener/MoveListener.java index f11ee9f..5e50440 100644 --- a/src/main/java/net/knarcraft/minigames/listener/MoveListener.java +++ b/src/main/java/net/knarcraft/minigames/listener/MoveListener.java @@ -9,7 +9,7 @@ import net.knarcraft.minigames.arena.parkour.ParkourArena; import net.knarcraft.minigames.arena.parkour.ParkourArenaGameMode; import net.knarcraft.minigames.arena.parkour.ParkourArenaSession; import net.knarcraft.minigames.config.DropperConfiguration; -import net.knarcraft.minigames.config.Message; +import net.knarcraft.minigames.config.MiniGameMessage; import net.knarcraft.minigames.config.ParkourConfiguration; import net.knarcraft.minigames.config.SharedConfiguration; import org.bukkit.Bukkit; @@ -121,7 +121,8 @@ public class MoveListener implements Listener { // Register the checkpoint arenaSession.registerCheckpoint(checkpoint.clone()); - player.sendMessage(Message.SUCCESS_CHECKPOINT_REACHED.getMessage()); + MiniGames.getInstance().getStringFormatter().displaySuccessMessage(player, + MiniGameMessage.SUCCESS_CHECKPOINT_REACHED); return; } } diff --git a/src/main/java/net/knarcraft/minigames/property/PersistentDataKey.java b/src/main/java/net/knarcraft/minigames/property/PersistentDataKey.java index a3343ab..4536ded 100644 --- a/src/main/java/net/knarcraft/minigames/property/PersistentDataKey.java +++ b/src/main/java/net/knarcraft/minigames/property/PersistentDataKey.java @@ -8,7 +8,6 @@ public enum PersistentDataKey { MENU_ITEM("MiniGamesMenu", 1799804), LEAVE_ITEM("MiniGamesAction", 1799871), GIVE_UP_ITEM("MiniGamesAction", 1799872), - TOGGLE_PLAYERS_ITEM("MiniGamesAction", 1799873), ; private final String keyName; diff --git a/src/main/java/net/knarcraft/minigames/util/ArenaStorageHelper.java b/src/main/java/net/knarcraft/minigames/util/ArenaStorageHelper.java index 9abfd2d..34ac68a 100644 --- a/src/main/java/net/knarcraft/minigames/util/ArenaStorageHelper.java +++ b/src/main/java/net/knarcraft/minigames/util/ArenaStorageHelper.java @@ -35,7 +35,7 @@ public final class ArenaStorageHelper { try { configuration.save(new File(MiniGames.getInstance().getDataFolder(), key + "EntryStates.yml")); - } catch (IOException e) { + } catch (IOException exception) { MiniGames.log(Level.SEVERE, "Unable to save entry states to disk"); } } diff --git a/src/main/java/net/knarcraft/minigames/util/ColorHelper.java b/src/main/java/net/knarcraft/minigames/util/ColorHelper.java deleted file mode 100644 index 4b79d19..0000000 --- a/src/main/java/net/knarcraft/minigames/util/ColorHelper.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.knarcraft.minigames.util; - -import net.md_5.bungee.api.ChatColor; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A helper class for converting colors - */ -public class ColorHelper { - - /** - * Translates all found color codes to formatting in a string - * - * @param message

The string to search for color codes

- * @return

The message with color codes translated

- */ - public static String translateAllColorCodes(String message) { - message = ChatColor.translateAlternateColorCodes('&', message); - Pattern pattern = Pattern.compile("&?(#[a-fA-F0-9]{6})"); - Matcher matcher = pattern.matcher(message); - while (matcher.find()) { - message = message.replace(matcher.group(), "" + ChatColor.of(matcher.group(1))); - } - return message; - } - -} diff --git a/src/main/java/net/knarcraft/minigames/util/DropperArenaStorageHelper.java b/src/main/java/net/knarcraft/minigames/util/DropperArenaStorageHelper.java index 524b736..0b2c22d 100644 --- a/src/main/java/net/knarcraft/minigames/util/DropperArenaStorageHelper.java +++ b/src/main/java/net/knarcraft/minigames/util/DropperArenaStorageHelper.java @@ -9,8 +9,7 @@ import net.knarcraft.minigames.arena.dropper.DropperArenaGameMode; import net.knarcraft.minigames.arena.dropper.DropperArenaGroup; import net.knarcraft.minigames.arena.dropper.DropperArenaRecordsRegistry; import net.knarcraft.minigames.arena.dropper.DropperArenaStorageKey; -import net.knarcraft.minigames.config.Message; -import net.knarcraft.minigames.container.PlaceholderContainer; +import net.knarcraft.minigames.config.MiniGameMessage; import net.knarcraft.minigames.container.SerializableMaterial; import net.knarcraft.minigames.container.SerializableUUID; import org.bukkit.Location; @@ -161,8 +160,9 @@ public final class DropperArenaStorageHelper { DropperArenaStorageKey.WIN_BLOCK_TYPE.getKey()); if (arenaName == null || spawnLocation == null) { - MiniGames.log(Level.SEVERE, Message.ERROR_ARENA_NOT_LOADED.getMessage(new PlaceholderContainer().add( - "{section}", configurationSection.getName()).add("{file}", "dropper_arenas"))); + MiniGames.log(Level.SEVERE, MiniGames.getInstance().getStringFormatter().replacePlaceholders( + MiniGameMessage.ERROR_ARENA_NOT_LOADED, new String[]{"{section}", "{file}"}, + new String[]{configurationSection.getName(), "dropper_arenas"})); return null; } if (winBlockType == null) { @@ -172,8 +172,8 @@ public final class DropperArenaStorageHelper { // Generate new, empty arena data if not available DropperArenaData arenaData = loadDropperArenaData(arenaId); if (arenaData == null) { - MiniGames.log(Level.SEVERE, Message.ERROR_ARENA_DATA_NOT_LOADED.getMessage("{arena}", - arenaId.toString())); + MiniGames.log(Level.SEVERE, MiniGames.getInstance().getStringFormatter().replacePlaceholder( + MiniGameMessage.ERROR_ARENA_DATA_NOT_LOADED, "{arena}", arenaId.toString())); arenaData = getEmptyDropperData(arenaId); } diff --git a/src/main/java/net/knarcraft/minigames/util/MaterialHelper.java b/src/main/java/net/knarcraft/minigames/util/MaterialHelper.java deleted file mode 100644 index 2a50b5a..0000000 --- a/src/main/java/net/knarcraft/minigames/util/MaterialHelper.java +++ /dev/null @@ -1,77 +0,0 @@ -package net.knarcraft.minigames.util; - -import net.knarcraft.minigames.MiniGames; -import net.knarcraft.minigames.config.Message; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.Tag; -import org.jetbrains.annotations.NotNull; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.logging.Level; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A helper class for dealing with and parsing materials - */ -public final class MaterialHelper { - - private MaterialHelper() { - - } - - /** - * Loads the materials specified in the block whitelist - */ - public static @NotNull Set loadMaterialList(@NotNull List materials) { - Set parsedMaterials = new HashSet<>(); - for (Object value : materials) { - if (!(value instanceof String string)) { - continue; - } - - // Try to parse a material tag first - if (parseMaterialTag(parsedMaterials, string)) { - continue; - } - - // Try to parse a material name - Material matched = Material.matchMaterial(string); - if (matched != null) { - parsedMaterials.add(matched); - } else { - MiniGames.log(Level.WARNING, Message.ERROR_MATERIAL_NOT_PARSE_ABLE.getMessage("{material}", string)); - } - } - return parsedMaterials; - } - - /** - * Tries to parse the material tag in the specified material name - * - * @param targetSet

The set all parsed materials should be added to

- * @param materialName

The material name that might be a material tag

- * @return

True if a tag was found

- */ - private static boolean parseMaterialTag(@NotNull Set targetSet, @NotNull String materialName) { - Pattern pattern = Pattern.compile("^\\+([a-zA-Z_]+)"); - Matcher matcher = pattern.matcher(materialName); - if (matcher.find()) { - // The material is a material tag - Tag tag = Bukkit.getTag(Tag.REGISTRY_BLOCKS, NamespacedKey.minecraft( - matcher.group(1).toLowerCase()), Material.class); - if (tag != null) { - targetSet.addAll(tag.getValues()); - } else { - MiniGames.log(Level.WARNING, "Unable to parse: " + materialName); - } - return true; - } - return false; - } - -} diff --git a/src/main/java/net/knarcraft/minigames/util/ParkourArenaStorageHelper.java b/src/main/java/net/knarcraft/minigames/util/ParkourArenaStorageHelper.java index 375ab4b..1c00c64 100644 --- a/src/main/java/net/knarcraft/minigames/util/ParkourArenaStorageHelper.java +++ b/src/main/java/net/knarcraft/minigames/util/ParkourArenaStorageHelper.java @@ -9,8 +9,7 @@ import net.knarcraft.minigames.arena.parkour.ParkourArenaGameMode; import net.knarcraft.minigames.arena.parkour.ParkourArenaGroup; import net.knarcraft.minigames.arena.parkour.ParkourArenaRecordsRegistry; import net.knarcraft.minigames.arena.parkour.ParkourArenaStorageKey; -import net.knarcraft.minigames.config.Message; -import net.knarcraft.minigames.container.PlaceholderContainer; +import net.knarcraft.minigames.config.MiniGameMessage; import net.knarcraft.minigames.container.SerializableMaterial; import net.knarcraft.minigames.container.SerializableUUID; import org.bukkit.Location; @@ -166,8 +165,9 @@ public final class ParkourArenaStorageHelper { // The arena name and spawn location must be present if (arenaName == null || spawnLocation == null) { - MiniGames.log(Level.SEVERE, Message.ERROR_ARENA_NOT_LOADED.getMessage(new PlaceholderContainer().add( - "{section}", configurationSection.getName()).add("{file}", "parkour_arena"))); + MiniGames.log(Level.SEVERE, MiniGames.getInstance().getStringFormatter().replacePlaceholders( + MiniGameMessage.ERROR_ARENA_NOT_LOADED, new String[]{"{section}", "{file}"}, + new String[]{configurationSection.getName(), "parkour_arena"})); return null; } @@ -179,8 +179,8 @@ public final class ParkourArenaStorageHelper { // Generate new, empty arena data if not available ParkourArenaData arenaData = loadParkourArenaData(arenaId); if (arenaData == null) { - MiniGames.log(Level.SEVERE, Message.ERROR_ARENA_DATA_NOT_LOADED.getMessage("{arena}", - arenaId.toString())); + MiniGames.log(Level.SEVERE, MiniGames.getInstance().getStringFormatter().replacePlaceholder( + MiniGameMessage.ERROR_ARENA_DATA_NOT_LOADED, "{arena}", arenaId.toString())); arenaData = getEmptyParkourData(arenaId); } diff --git a/src/main/java/net/knarcraft/minigames/util/PlayerTeleporter.java b/src/main/java/net/knarcraft/minigames/util/PlayerTeleporter.java index 974a042..af700f7 100644 --- a/src/main/java/net/knarcraft/minigames/util/PlayerTeleporter.java +++ b/src/main/java/net/knarcraft/minigames/util/PlayerTeleporter.java @@ -1,7 +1,7 @@ package net.knarcraft.minigames.util; import net.knarcraft.minigames.MiniGames; -import net.knarcraft.minigames.config.Message; +import net.knarcraft.minigames.config.MiniGameMessage; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Entity; @@ -36,7 +36,8 @@ public final class PlayerTeleporter { passenger.teleport(location); } } else { - player.sendMessage(Message.ERROR_TELEPORT_WITH_PASSENGER.getMessage()); + MiniGames.getInstance().getStringFormatter().displayErrorMessage(player, + MiniGameMessage.ERROR_TELEPORT_WITH_PASSENGER); return false; } } @@ -46,7 +47,8 @@ public final class PlayerTeleporter { player.eject(); vehicle.teleport(location); } else { - player.sendMessage(Message.ERROR_TELEPORT_IN_VEHICLE.getMessage()); + MiniGames.getInstance().getStringFormatter().displayErrorMessage(player, + MiniGameMessage.ERROR_TELEPORT_IN_VEHICLE); return false; } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index c57c19e..63423cb 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,4 +1,7 @@ # Configuration values for mini-games + +# The chosen language for Launchpad. You can use "en" or any custom language specified in strings.yml +language: en parkour: # Whether to enforce the order in which a player must reach checkpoints. Enabling this ensures that a player cannot # trigger a previous checkpoint by accident. It also ensures players cannot skip a checkpoint, even if the arena diff --git a/src/main/resources/strings.yml b/src/main/resources/strings.yml new file mode 100644 index 0000000..cf2062a --- /dev/null +++ b/src/main/resources/strings.yml @@ -0,0 +1,43 @@ +en: + ERROR_CANNOT_SAVE_ARENA_GROUPS: "Unable to save current arena groups! Data loss can occur!" + ERROR_MATERIAL_NOT_PARSE_ABLE: "Unable to parse material: {material}" + ERROR_TELEPORT_WITH_PASSENGER: "You cannot be teleported with a passenger!" + ERROR_TELEPORT_IN_VEHICLE: "You cannot be teleported while in a vehicle" + ERROR_ARENA_NOT_LOADED: "Could not load the arena at configuration section {section}. Please check the {file} storage file for issues." + ERROR_ARENA_DATA_NOT_LOADED: "Unable to load arena data for dropper arena: {arena}" + ERROR_ARENA_NOT_FOUND: "Unable to find the specified arena." + ERROR_GROUP_NOT_FOUND: "Unable to find the specified group!" + ERROR_PLAYER_ONLY: "This command must be used by a player" + ERROR_ARENA_NAME_COLLISION: "There already exists an arena with that name!" + ERROR_NORMAL_MODE_REQUIRED: "You must complete this arena in normal mode first!" + ERROR_GROUP_NORMAL_MODE_REQUIRED: "You have not yet beaten the default game-mode for all arenas in this group!" + ERROR_PREVIOUS_ARENA_REQUIRED: "You have not yet beaten the previous arena!" + ERROR_ARENA_TELEPORT_FAILED: "Unable to teleport you to the arena." + ERROR_NOT_IN_ARENA: "You are not in a mini-games arena!" + ERROR_ALREADY_PLAYING: "You are already playing a mini-game!" + ERROR_JOIN_IN_VEHICLE_OR_PASSENGER: "You cannot join an arena while inside a vehicle or carrying a passenger." + ERROR_UNKNOWN_PROPERTY: "Unknown property specified." + ERROR_PROPERTY_INPUT_INVALID: "Unable to change the property. Make sure your input is valid!" + ERROR_ARENA_1_NOT_FOUND: "Unable to find the first specified arena." + ERROR_ARENA_2_NOT_FOUND: "Unable to find the second specified dropper arena." + ERROR_SWAP_DIFFERENT_GROUPS: "You cannot swap arenas in different groups!" + ERROR_ILLEGAL_COMMAND: "You cannot use that command while in an arena!" + ERROR_HARDCORE_NO_CHECKPOINTS: "This arena cannot be played in hardcore mode as it has no checkpoints!" + SUCCESS_ARENA_GROUP_UPDATED: "The arena's group has been updated" + SUCCESS_PLUGIN_RELOADED: "Plugin reloaded!" + SUCCESS_ARENA_CREATED: "The arena was successfully created!" + SUCCESS_ARENA_FIRST_CLEAR: "You cleared the arena!" + SUCCESS_ARENA_WIN: "You won!" + SUCCESS_ARENA_QUIT: "You quit the arena!" + SUCCESS_CURRENT_VALUE: "Current value of {property} is: {value}" + SUCCESS_PROPERTY_CHANGED: "Property {property} successfully changed" + SUCCESS_ARENAS_SWAPPED: "The arenas have been swapped!" + SUCCESS_ARENA_REMOVED: "The specified arena has been successfully removed" + SUCCESS_DROPPER_ARENAS_LIST: "Dropper arenas:&r" + SUCCESS_PARKOUR_ARENAS_LIST: "Parkour arenas:&r" + SUCCESS_CHECKPOINT_REACHED: "Checkpoint reached!" + SUCCESS_GROUP_STAGES: "{group}'s stages:&r" + SUCCESS_RECORD_ACHIEVED: "You just set a {recordInfo} on the {gameMode} game-mode!" + RECORD_ACHIEVED_GLOBAL: "new {recordType} record" + RECORD_ACHIEVED_PERSONAL: "personal {recordType} record" + SUCCESS_ARENA_JOINED: "You joined the arena." \ No newline at end of file