Adds some important changes

Adds code for translating and formatting messages
Registers strings used in CommandConfig as translatable
Makes sure to keep track of portals whose destinations are overridden to prevent permanent destination change, or portals whose destinations are overridden even after they are closed
This commit is contained in:
2022-06-01 03:13:25 +02:00
parent 66d37cddcb
commit 95a996ff9c
10 changed files with 458 additions and 13 deletions

View File

@@ -4,7 +4,10 @@ import net.TheDgtl.Stargate.api.StargateAPI;
import net.TheDgtl.Stargate.config.ConfigurationOption;
import net.knarcraft.stargatecommand.command.CommandStarGateCommand;
import net.knarcraft.stargatecommand.command.StargateCommandTabCompleter;
import net.knarcraft.stargatecommand.formatting.Translator;
import net.knarcraft.stargatecommand.listener.StargateListener;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.ServicesManager;
import org.bukkit.plugin.java.JavaPlugin;
@@ -18,6 +21,7 @@ import java.util.List;
@SuppressWarnings("unused")
public class StargateCommand extends JavaPlugin {
private static StargateCommand instance;
private List<ConfigurationOption> bannedConfigOptions;
@Override
@@ -26,6 +30,8 @@ public class StargateCommand extends JavaPlugin {
if (bannedConfigOptions == null) {
initializeBannedConfigOptions();
}
instance = this;
Translator.loadLanguages("en");
//Get the Stargate API
ServicesManager servicesManager = this.getServer().getServicesManager();
RegisteredServiceProvider<StargateAPI> stargateProvider = servicesManager.getRegistration(StargateAPI.class);
@@ -38,6 +44,8 @@ public class StargateCommand extends JavaPlugin {
stargateCommand.setExecutor(new CommandStarGateCommand(stargateAPI, bannedConfigOptions));
stargateCommand.setTabCompleter(new StargateCommandTabCompleter(stargateAPI, bannedConfigOptions));
}
PluginManager pluginManager = getServer().getPluginManager();
pluginManager.registerEvents(new StargateListener(), this);
} else {
throw new IllegalStateException("Unable to hook into Stargate. Make sure the Stargate plugin is installed " +
"and enabled.");
@@ -49,6 +57,15 @@ public class StargateCommand extends JavaPlugin {
//Currently, nothing needs to be disabled
}
/**
* Gets an instance of this plugin
*
* @return <p>An instance of this plugin</p>
*/
public static StargateCommand getInstance() {
return instance;
}
/**
* Initializes the list of banned configuration options
*

View File

@@ -3,6 +3,9 @@ package net.knarcraft.stargatecommand.command;
import net.TheDgtl.Stargate.config.ConfigurationAPI;
import net.TheDgtl.Stargate.config.ConfigurationOption;
import net.TheDgtl.Stargate.config.OptionDataType;
import net.knarcraft.stargatecommand.formatting.StringFormatter;
import net.knarcraft.stargatecommand.formatting.TranslatableMessage;
import net.knarcraft.stargatecommand.formatting.Translator;
import net.md_5.bungee.api.ChatColor;
import org.apache.commons.lang.StringUtils;
import org.bukkit.command.Command;
@@ -14,6 +17,9 @@ import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.List;
import static net.knarcraft.stargatecommand.formatting.StringFormatter.getTranslatedErrorMessage;
import static net.knarcraft.stargatecommand.formatting.StringFormatter.getTranslatedInfoMessage;
/**
* This command represents the config command for changing config values
*/
@@ -40,7 +46,7 @@ public class CommandConfig implements CommandExecutor {
@NotNull String[] args) {
if (commandSender instanceof Player player) {
if (!player.hasPermission("stargate.command.config")) {
player.sendMessage("Permission Denied");
player.sendMessage(getTranslatedErrorMessage(TranslatableMessage.PERMISSION_DENIED));
return true;
}
}
@@ -53,7 +59,7 @@ public class CommandConfig implements CommandExecutor {
return true;
}
} catch (IllegalArgumentException exception) {
commandSender.sendMessage("Invalid configuration option specified");
commandSender.sendMessage(getTranslatedErrorMessage(TranslatableMessage.INVALID_CONFIGURATION_OPTION));
return true;
}
if (args.length > 1) {
@@ -83,7 +89,8 @@ public class CommandConfig implements CommandExecutor {
try {
ChatColor.of(value.toUpperCase());
} catch (IllegalArgumentException | NullPointerException ignored) {
commandSender.sendMessage(ChatColor.RED + "Invalid color given");
commandSender.sendMessage(StringFormatter.replacePlaceholder(getTranslatedErrorMessage(
TranslatableMessage.INVALID_DATATYPE_GIVEN), "{datatype}", "color"));
return;
}
}
@@ -135,7 +142,8 @@ public class CommandConfig implements CommandExecutor {
*/
private boolean checkIfValueMatchesDatatype(OptionDataType dataType, String value, CommandSender commandSender) {
if (!matchesOptionDataType(dataType, value)) {
commandSender.sendMessage(String.format("Invalid %s given",
commandSender.sendMessage(StringFormatter.replacePlaceholder(getTranslatedErrorMessage(
TranslatableMessage.INVALID_DATATYPE_GIVEN), "{datatype}",
dataType.name().toLowerCase().replace('_', ' ')));
return false;
} else {
@@ -162,7 +170,7 @@ public class CommandConfig implements CommandExecutor {
private void saveAndReload(CommandSender commandSender) {
configurationAPI.saveConfiguration();
configurationAPI.reload();
commandSender.sendMessage("Config updated");
commandSender.sendMessage(getTranslatedInfoMessage(TranslatableMessage.CONFIG_UPDATED));
}
/**
@@ -178,13 +186,13 @@ public class CommandConfig implements CommandExecutor {
int intValue = Integer.parseInt(value);
if ((selectedOption == ConfigurationOption.USE_COST || selectedOption == ConfigurationOption.CREATION_COST) && intValue < 0) {
commandSender.sendMessage(ChatColor.RED + "This config option cannot be negative.");
commandSender.sendMessage(getTranslatedErrorMessage(TranslatableMessage.POSITIVE_NUMBER_REQUIRED));
return null;
}
return intValue;
} catch (NumberFormatException exception) {
commandSender.sendMessage(ChatColor.RED + "Invalid number given");
commandSender.sendMessage(getTranslatedErrorMessage(TranslatableMessage.INVALID_NUMBER_GIVEN));
return null;
}
}
@@ -202,13 +210,13 @@ public class CommandConfig implements CommandExecutor {
double doubleValue = Double.parseDouble(value);
if (selectedOption == ConfigurationOption.GATE_EXIT_SPEED_MULTIPLIER && doubleValue < 0) {
commandSender.sendMessage(ChatColor.RED + "This config option cannot be negative.");
commandSender.sendMessage(getTranslatedErrorMessage(TranslatableMessage.POSITIVE_NUMBER_REQUIRED));
return null;
}
return doubleValue;
} catch (NumberFormatException exception) {
commandSender.sendMessage(ChatColor.RED + "Invalid number given");
commandSender.sendMessage(getTranslatedErrorMessage(TranslatableMessage.INVALID_NUMBER_GIVEN));
return null;
}
}
@@ -222,7 +230,8 @@ public class CommandConfig implements CommandExecutor {
private void printConfigOptionValue(CommandSender sender, ConfigurationOption option) {
Object value = configurationAPI.getConfigurationOptionValue(option);
sender.sendMessage(getOptionDescription(option));
sender.sendMessage(ChatColor.GREEN + "Current value: " + ChatColor.GOLD + value);
sender.sendMessage(StringFormatter.replacePlaceholder(Translator.getTranslatedMessage(
TranslatableMessage.CONFIG_OPTION_CURRENT_VALUE), "{value}", String.valueOf(value)));
}
/**
@@ -231,7 +240,7 @@ public class CommandConfig implements CommandExecutor {
* @param sender <p>The command sender to display the config list to</p>
*/
private void displayConfigValues(CommandSender sender) {
sender.sendMessage(ChatColor.GREEN + "Stargate " + ChatColor.GOLD + "Config values:");
sender.sendMessage(Translator.getTranslatedMessage(TranslatableMessage.CONFIG_VALUES_HEADER));
for (ConfigurationOption option : ConfigurationOption.values()) {
if (!bannedConfigOptions.contains(option)) {
@@ -252,8 +261,9 @@ public class CommandConfig implements CommandExecutor {
if (option.getDataType() == OptionDataType.STRING_LIST) {
stringValue = "[" + StringUtils.join((String[]) defaultValue, ",") + "]";
}
return ChatColor.GOLD + option.name() + ChatColor.WHITE + " - " + ChatColor.GREEN + option.getDescription() +
ChatColor.DARK_GRAY + " (Default: " + ChatColor.GRAY + stringValue + ChatColor.DARK_GRAY + ")";
return StringFormatter.replacePlaceholders(Translator.getTranslatedMessage(
TranslatableMessage.CONFIG_OPTION_DESCRIPTION), new String[]{"{name}", "{description}", "{value}"},
new String[]{option.name(), option.getDescription(), stringValue});
}
}

View File

@@ -5,6 +5,7 @@ import net.TheDgtl.Stargate.manager.PermissionManager;
import net.TheDgtl.Stargate.network.Network;
import net.TheDgtl.Stargate.network.RegistryAPI;
import net.TheDgtl.Stargate.network.portal.RealPortal;
import net.knarcraft.stargatecommand.manager.OverrideManager;
import net.knarcraft.stargatecommand.util.PortalFinderHelper;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
@@ -74,6 +75,7 @@ public class CommandDial implements CommandExecutor {
return true;
}
originPortal.overrideDestination(targetPortal);
OverrideManager.storeOverriddenDestination(originPortal);
originPortal.open(player);
player.sendMessage("Your Stargate has been prepared");

View File

@@ -0,0 +1,107 @@
package net.knarcraft.stargatecommand.formatting;
import net.md_5.bungee.api.ChatColor;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A formatter for formatting displayed messages
*/
public class StringFormatter {
/**
* Replaces a placeholder in a string
*
* @param input <p>The input string to replace in</p>
* @param placeholder <p>The placeholder to replace</p>
* @param replacement <p>The replacement value</p>
* @return <p>The input string with the placeholder replaced</p>
*/
public static String replacePlaceholder(String input, String placeholder, String replacement) {
return input.replace(placeholder, replacement);
}
/**
* Replaces placeholders in a string
*
* @param input <p>The input string to replace in</p>
* @param placeholders <p>The placeholders to replace</p>
* @param replacements <p>The replacement values</p>
* @return <p>The input string with placeholders replaced</p>
*/
public static String replacePlaceholders(String input, String[] placeholders, String[] replacements) {
for (int i = 0; i < Math.min(placeholders.length, replacements.length); i++) {
input = replacePlaceholder(input, placeholders[i], replacements[i]);
}
return input;
}
/**
* Gets a translated and formatted info message
*
* @param translatableMessage <p>The translatable message to translate and format</p>
* @return <p>The translated and formatted message</p>
*/
public static String getTranslatedInfoMessage(TranslatableMessage translatableMessage) {
return formatInfoMessage(Translator.getTranslatedMessage(translatableMessage));
}
/**
* Gets a translated and formatted error message
*
* @param translatableMessage <p>The translatable message to translate and format</p>
* @return <p>The translated and formatted message</p>
*/
public static String getTranslatedErrorMessage(TranslatableMessage translatableMessage) {
return formatErrorMessage(Translator.getTranslatedMessage(translatableMessage));
}
/**
* Formats an information message by adding the prefix and text color
*
* @param message <p>The message to format</p>
* @return <p>The formatted message</p>
*/
public static String formatInfoMessage(String message) {
return ChatColor.DARK_GREEN + formatMessage(message);
}
/**
* Formats an error message by adding the prefix and text color
*
* @param message <p>The message to format</p>
* @return <p>The formatted message</p>
*/
public static String formatErrorMessage(String message) {
return ChatColor.DARK_RED + formatMessage(message);
}
/**
* Formats a message by adding the prefix and text color
*
* @param message <p>The message to format</p>
* @return <p>The formatted message</p>
*/
private static String formatMessage(String message) {
return Translator.getTranslatedMessage(TranslatableMessage.PREFIX) + " " +
ChatColor.RESET + message;
}
/**
* Translates all found color codes to formatting in a string
*
* @param message <p>The string to search for color codes</p>
* @return <p>The message with color codes translated</p>
*/
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()));
}
return message;
}
}

View File

@@ -0,0 +1,58 @@
package net.knarcraft.stargatecommand.formatting;
/**
* An enum representing all translatable messages
*/
public enum TranslatableMessage {
/**
* The prefix to display in messages
*/
PREFIX,
/**
* The message displayed when a player is denied the usage of a command
*/
PERMISSION_DENIED,
/**
* The message displayed when the user provides an invalid configuration option for the /sgc config command
*/
INVALID_CONFIGURATION_OPTION,
/**
* The message displayed when the user provides an invalid value for the required datatype
*/
INVALID_DATATYPE_GIVEN,
/**
* The message to display after a configuration value has been successfully updated
*/
CONFIG_UPDATED,
/**
* The message to display if a negative number is provided, but a positive number is required
*/
POSITIVE_NUMBER_REQUIRED,
/**
* The message to display if a number is expected, but a non-number is provided
*/
INVALID_NUMBER_GIVEN,
/**
* The message to display when displaying the current value of a configuration option
*/
CONFIG_OPTION_CURRENT_VALUE,
/**
* The header to display when showing all configuration options and their values
*/
CONFIG_VALUES_HEADER,
/**
* The message to display when showing a full description of a configuration option
*/
CONFIG_OPTION_DESCRIPTION,
}

View File

@@ -0,0 +1,118 @@
package net.knarcraft.stargatecommand.formatting;
import net.knarcraft.stargatecommand.StargateCommand;
import net.knarcraft.stargatecommand.util.FileHelper;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
/**
* A tool to get strings translated to the correct language
*/
public final class Translator {
private static Map<TranslatableMessage, String> translatedMessages;
private static Map<TranslatableMessage, String> backupTranslatedMessages;
private Translator() {
}
/**
* Loads the languages used by this translator
*/
public static void loadLanguages(String selectedLanguage) {
backupTranslatedMessages = loadTranslatedMessages("en");
translatedMessages = loadCustomTranslatedMessages(selectedLanguage);
if (translatedMessages == null) {
translatedMessages = loadTranslatedMessages(selectedLanguage);
}
}
/**
* Gets a translated version of the given translatable message
*
* @param translatableMessage <p>The message to translate</p>
* @return <p>The translated message</p>
*/
public static String getTranslatedMessage(TranslatableMessage translatableMessage) {
if (translatedMessages == null) {
return "Translated strings not loaded";
}
String translatedMessage;
if (translatedMessages.containsKey(translatableMessage)) {
translatedMessage = translatedMessages.get(translatableMessage);
} else if (backupTranslatedMessages.containsKey(translatableMessage)) {
translatedMessage = backupTranslatedMessages.get(translatableMessage);
} else {
translatedMessage = translatableMessage.toString();
}
return StringFormatter.translateAllColorCodes(translatedMessage);
}
/**
* Loads all translated messages for the given language
*
* @param language <p>The language chosen by the user</p>
* @return <p>A mapping of all strings for the given language</p>
*/
public static Map<TranslatableMessage, String> loadTranslatedMessages(String language) {
try {
BufferedReader reader = FileHelper.getBufferedReaderForInternalFile("/strings.yml");
return loadTranslatableMessages(language, reader);
} catch (FileNotFoundException e) {
StargateCommand.getInstance().getLogger().log(Level.SEVERE, "Unable to load translated messages");
return null;
}
}
/**
* Tries to load translated messages from a custom strings.yml file
*
* @param language <p>The selected language</p>
* @return <p>The loaded translated strings, or null if no custom language file exists</p>
*/
public static Map<TranslatableMessage, String> loadCustomTranslatedMessages(String language) {
File strings = new File(StargateCommand.getInstance().getDataFolder(), "strings.yml");
if (!strings.exists()) {
StargateCommand.getInstance().getLogger().log(Level.FINEST, "Strings file not found");
return null;
}
try {
StargateCommand.getInstance().getLogger().log(Level.WARNING, "Loading custom strings...");
return loadTranslatableMessages(language, new BufferedReader(new InputStreamReader(new FileInputStream(strings))));
} catch (FileNotFoundException e) {
StargateCommand.getInstance().getLogger().log(Level.WARNING, "Unable to load custom messages");
return null;
}
}
/**
* Loads translatable messages from the given reader
*
* @param language <p>The selected language</p>
* @param reader <p>The buffered reader to read from</p>
* @return <p>The loaded translated strings</p>
*/
private static Map<TranslatableMessage, String> loadTranslatableMessages(String language, BufferedReader reader) {
Map<TranslatableMessage, String> translatedMessages = new HashMap<>();
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(reader);
for (TranslatableMessage message : TranslatableMessage.values()) {
String translated = configuration.getString(language + "." + message.toString());
if (translated != null) {
translatedMessages.put(message, translated);
}
}
return translatedMessages;
}
}

View File

@@ -0,0 +1,44 @@
package net.knarcraft.stargatecommand.listener;
import net.TheDgtl.Stargate.event.StargateCloseEvent;
import net.TheDgtl.Stargate.event.StargateDeactivateEvent;
import net.TheDgtl.Stargate.event.StargatePortalEvent;
import net.TheDgtl.Stargate.network.portal.Portal;
import net.knarcraft.stargatecommand.manager.OverrideManager;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
/**
* A listener for listening to Stargate events
*/
public class StargateListener implements Listener {
@EventHandler
public void teleportListener(StargatePortalEvent event) {
removeOverriddenDestination(event.getPortal());
}
@EventHandler
public void deactivateListener(StargateDeactivateEvent event) {
removeOverriddenDestination(event.getPortal());
}
@EventHandler
public void closeListener(StargateCloseEvent event) {
removeOverriddenDestination(event.getPortal());
}
/**
* Removes the override for the given portal, if this plugin has overridden its destination
*
* @param portal <p>The portal to remove the override from</p>
*/
private void removeOverriddenDestination(Portal portal) {
boolean isOverridden = OverrideManager.hasOverriddenDestination(portal);
if (isOverridden) {
portal.overrideDestination(null);
OverrideManager.removeOverriddenDestination(portal);
}
}
}

View File

@@ -0,0 +1,46 @@
package net.knarcraft.stargatecommand.manager;
import net.TheDgtl.Stargate.network.portal.Portal;
import java.util.ArrayList;
import java.util.List;
/**
* A manager for managing overridden destinations
*/
public final class OverrideManager {
private static final List<Portal> overriddenPortals = new ArrayList<>();
private OverrideManager() {
}
/**
* Stores an over-ridden destination
*
* @param portal <p>The portal whose destination was overridden</p>
*/
public static void storeOverriddenDestination(Portal portal) {
overriddenPortals.add(portal);
}
/**
* Removes an over-ridden destination for a portal
*
* @param portal <p>The portal to remove the overridden destination for</p>
*/
public static void removeOverriddenDestination(Portal portal) {
overriddenPortals.remove(portal);
}
/**
* Gets whether the given portal's destination is currently overridden
*
* @param portal <p>The portal with a possibly overridden destination</p>
*/
public static boolean hasOverriddenDestination(Portal portal) {
return overriddenPortals.contains(portal);
}
}

View File

@@ -0,0 +1,32 @@
package net.knarcraft.stargatecommand.util;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
/**
* A helper class for dealing with files
*/
public final class FileHelper {
private FileHelper() {
}
/**
* Gets a buffered reader for
*
* @return <p>A buffered read for reading the file</p>
* @throws FileNotFoundException <p>If unable to get an input stream for the given file</p>
*/
public static BufferedReader getBufferedReaderForInternalFile(String file) throws FileNotFoundException {
InputStream inputStream = FileHelper.class.getResourceAsStream(file);
if (inputStream == null) {
throw new FileNotFoundException("Unable to read the given file");
}
return new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
}
}

View File

@@ -0,0 +1,11 @@
en:
PREFIX: "[StargateCommand]"
PERMISSION_DENIED: "Permission Denied"
INVALID_CONFIGURATION_OPTION: "Invalid configuration option specified"
INVALID_DATATYPE_GIVEN: "Invalid {datatype} given"
CONFIG_UPDATED: "Configuration updated"
POSITIVE_NUMBER_REQUIRED: "This config option cannot be negative"
INVALID_NUMBER_GIVEN: "Invalid number given"
CONFIG_OPTION_CURRENT_VALUE: "&aCurrent value: &6{value}"
CONFIG_VALUES_HEADER: "&aStargate &6Config values:"
CONFIG_OPTION_DESCRIPTION: "&6{name}&f - &a{description}&8 (Default: &7{value}&8)"