diff --git a/bukkit/acf-bukkit.iml b/bukkit/acf-bukkit.iml index 81e6649a..579fdd23 100644 --- a/bukkit/acf-bukkit.iml +++ b/bukkit/acf-bukkit.iml @@ -19,10 +19,10 @@ - - + + diff --git a/bukkit/src/main/java/co/aikar/commands/BukkitCommandManager.java b/bukkit/src/main/java/co/aikar/commands/BukkitCommandManager.java index fe5e12f0..cab82955 100644 --- a/bukkit/src/main/java/co/aikar/commands/BukkitCommandManager.java +++ b/bukkit/src/main/java/co/aikar/commands/BukkitCommandManager.java @@ -30,7 +30,6 @@ import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Server; import org.bukkit.command.Command; -import org.bukkit.command.CommandException; import org.bukkit.command.CommandMap; import org.bukkit.command.CommandSender; import org.bukkit.command.SimpleCommandMap; @@ -38,13 +37,13 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @@ -61,14 +60,22 @@ public class BukkitCommandManager extends CommandManager { protected BukkitCommandContexts contexts; protected BukkitCommandCompletions completions; MCTiming commandTiming; + protected BukkitLocales locales; @SuppressWarnings("JavaReflectionMemberAccess") public BukkitCommandManager(Plugin plugin) { this.plugin = plugin; - String pluginName = "acf-" + plugin.getDescription().getName(); - this.locales.addMessageBundles("acf-minecraft", pluginName, pluginName.toLowerCase()); this.timingManager = TimingManager.of(plugin); this.commandTiming = this.timingManager.of("Commands"); + this.commandMap = hookCommandMap(); + this.formatters.put(MessageType.ERROR, defaultFormatter = new BukkitMessageFormatter(ChatColor.RED, ChatColor.YELLOW, ChatColor.RED)); + this.formatters.put(MessageType.SYNTAX, new BukkitMessageFormatter(ChatColor.YELLOW, ChatColor.GREEN, ChatColor.WHITE)); + this.formatters.put(MessageType.INFO, new BukkitMessageFormatter(ChatColor.BLUE, ChatColor.DARK_GREEN, ChatColor.GREEN)); + Bukkit.getPluginManager().registerEvents(new ACFBukkitListener(plugin), plugin); + getLocales(); // auto load locales + } + + @NotNull private CommandMap hookCommandMap() { CommandMap commandMap = null; try { Server server = Bukkit.getServer(); @@ -80,7 +87,8 @@ public class BukkitCommandManager extends CommandManager { this.log(LogLevel.ERROR, "We are going to try to hijack it back and resolve this, but you are now in dangerous territory."); this.log(LogLevel.ERROR, "We can not guarantee things are going to work."); Field cmField = server.getClass().getDeclaredField("commandMap"); - cmField.set(server, commandMap = new ProxyCommandMap(commandMap)); + commandMap = new ProxyCommandMap(this, commandMap); + cmField.set(server, commandMap); this.log(LogLevel.INFO, "Injected Proxy Command Map... good luck..."); } Field knownCommands = SimpleCommandMap.class.getDeclaredField("knownCommands"); @@ -91,17 +99,33 @@ public class BukkitCommandManager extends CommandManager { this.log(LogLevel.ERROR, "Failed to get Command Map. ACF will not function."); ACFUtil.sneaky(e); } - this.commandMap = commandMap; - this.formatters.put(MessageType.ERROR, new BukkitMessageFormatter(ChatColor.RED, ChatColor.YELLOW, ChatColor.RED)); - this.formatters.put(MessageType.SYNTAX, new BukkitMessageFormatter(ChatColor.YELLOW, ChatColor.GREEN, ChatColor.WHITE)); - this.formatters.put(MessageType.INFO, new BukkitMessageFormatter(ChatColor.BLUE, ChatColor.DARK_GREEN, ChatColor.GREEN)); - Bukkit.getPluginManager().registerEvents(new ACFBukkitListener(plugin), plugin); + return commandMap; } public Plugin getPlugin() { return this.plugin; } + public BukkitMessageFormatter setFormat(MessageType type, BukkitMessageFormatter formatter) { + return (BukkitMessageFormatter) formatters.put(type, formatter); + } + + public BukkitMessageFormatter getFormat(MessageType type) { + return (BukkitMessageFormatter) formatters.getOrDefault(type, defaultFormatter); + } + + public void setFormat(MessageType type, ChatColor... colors) { + BukkitMessageFormatter format = getFormat(type); + for (int i = 0; i < colors.length; i++) { + format.setColor(i, colors[i]); + } + } + + public void setFormat(MessageType type, int i, ChatColor color) { + BukkitMessageFormatter format = getFormat(type); + format.setColor(i, color); + } + @Override public boolean isCommandIssuer(Class type) { return CommandSender.class.isAssignableFrom(type); @@ -123,6 +147,17 @@ public class BukkitCommandManager extends CommandManager { return completions; } + + @Override + public BukkitLocales getLocales() { + if (this.locales == null) { + this.locales = new BukkitLocales(this); + this.locales.loadLanguages(); + } + return locales; + } + + @Override public boolean hasRegisteredCommands() { return !registeredCommands.isEmpty(); @@ -240,79 +275,4 @@ public class BukkitCommandManager extends CommandManager { } } } - - class ProxyCommandMap extends SimpleCommandMap { - - CommandMap proxied; - - ProxyCommandMap(CommandMap proxied) { - super(Bukkit.getServer()); - this.proxied = proxied; - } - - @Override - public void registerAll(String fallbackPrefix, List commands) { - proxied.registerAll(fallbackPrefix, commands); - } - - @Override - public boolean register(String label, String fallbackPrefix, Command command) { - if (isOurCommand(command)) { - return super.register(label, fallbackPrefix, command); - } else { - return proxied.register(label, fallbackPrefix, command); - } - } - - boolean isOurCommand(String cmdLine) { - String[] args = ACFPatterns.SPACE.split(cmdLine); - return args.length != 0 && isOurCommand(knownCommands.get(args[0].toLowerCase(Locale.ENGLISH))); - - } - boolean isOurCommand(Command command) { - return command instanceof RootCommand && ((RootCommand) command).getManager() == BukkitCommandManager.this; - } - - @Override - public boolean register(String fallbackPrefix, Command command) { - if (isOurCommand(command)) { - return super.register(fallbackPrefix, command); - } else { - return proxied.register(fallbackPrefix, command); - } - } - - @Override - public boolean dispatch(CommandSender sender, String cmdLine) throws CommandException { - if (isOurCommand(cmdLine)) { - return super.dispatch(sender, cmdLine); - } else { - return proxied.dispatch(sender, cmdLine); - } - } - - @Override - public void clearCommands() { - super.clearCommands();; - proxied.clearCommands(); - } - - @Override - public Command getCommand(String name) { - if (isOurCommand(name)) { - return super.getCommand(name); - } else { - return proxied.getCommand(name); - } - } - - @Override - public List tabComplete(CommandSender sender, String cmdLine) throws IllegalArgumentException { - if (isOurCommand(cmdLine)) { - return super.tabComplete(sender, cmdLine); - } else { - return proxied.tabComplete(sender, cmdLine); - } - } - } } diff --git a/bukkit/src/main/java/co/aikar/commands/BukkitLocales.java b/bukkit/src/main/java/co/aikar/commands/BukkitLocales.java new file mode 100644 index 00000000..da0ee649 --- /dev/null +++ b/bukkit/src/main/java/co/aikar/commands/BukkitLocales.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package co.aikar.commands; + +import co.aikar.locales.MessageKey; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; +import java.util.Locale; + +public class BukkitLocales extends Locales { + private final BukkitCommandManager manager; + + public BukkitLocales(BukkitCommandManager manager) { + super(manager); + this.manager = manager; + } + + @Override + public void loadLanguages() { + super.loadLanguages(); + String pluginName = "acf-" + manager.plugin.getDescription().getName(); + addMessageBundles("acf-minecraft", pluginName, pluginName.toLowerCase()); + } + + /** + * Loads the given file + * @param file + * @param locale + * @return If any language keys were added + * @throws IOException + * @throws InvalidConfigurationException + */ + public boolean loadYamlLanguageFile(File file, Locale locale) throws IOException, InvalidConfigurationException { + YamlConfiguration yamlConfiguration = new YamlConfiguration(); + yamlConfiguration.load(file); + return loadLanguage(yamlConfiguration, locale); + } + + /** + * Loads a file out of the plugins data folder by the given name + * @param file + * @param locale + * @return If any language keys were added + * @throws IOException + * @throws InvalidConfigurationException + */ + public boolean loadYamlLanguageFile(String file, Locale locale) throws IOException, InvalidConfigurationException { + YamlConfiguration yamlConfiguration = new YamlConfiguration(); + yamlConfiguration.load(new File(this.manager.plugin.getDataFolder(), file)); + return loadLanguage(yamlConfiguration, locale); + } + + /** + * Loads every message from the Configuration object. Any nested values will be treated as namespace + * so acf-core:\n\tfoo: bar will be acf-core.foo = bar + * @param config + * @param locale + * @return If any language keys were added + */ + public boolean loadLanguage(FileConfiguration config, Locale locale) { + boolean loaded = false; + for (String parentKey : config.getKeys(false)) { + ConfigurationSection inner = config.getConfigurationSection(parentKey); + if (inner == null) { + continue; + } + for (String key : inner.getKeys(false)) { + String value = inner.getString(key); + if (value != null && !value.isEmpty()) { + addMessage(locale, MessageKey.of(parentKey + "." + key), value); + loaded = true; + } + } + } + + return loaded; + } +} diff --git a/bukkit/src/main/java/co/aikar/commands/MinecraftMessageKeys.java b/bukkit/src/main/java/co/aikar/commands/MinecraftMessageKeys.java index e438b2e1..5503a5be 100644 --- a/bukkit/src/main/java/co/aikar/commands/MinecraftMessageKeys.java +++ b/bukkit/src/main/java/co/aikar/commands/MinecraftMessageKeys.java @@ -24,6 +24,7 @@ package co.aikar.commands; import co.aikar.locales.MessageKey; +import co.aikar.locales.MessageKeyProvider; public enum MinecraftMessageKeys implements MessageKeyProvider { INVALID_WORLD, diff --git a/bukkit/src/main/java/co/aikar/commands/ProxyCommandMap.java b/bukkit/src/main/java/co/aikar/commands/ProxyCommandMap.java new file mode 100644 index 00000000..834ced43 --- /dev/null +++ b/bukkit/src/main/java/co/aikar/commands/ProxyCommandMap.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package co.aikar.commands; + +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandException; +import org.bukkit.command.CommandMap; +import org.bukkit.command.CommandSender; +import org.bukkit.command.SimpleCommandMap; + +import java.util.List; +import java.util.Locale; + +class ProxyCommandMap extends SimpleCommandMap { + + private BukkitCommandManager manager; + CommandMap proxied; + + ProxyCommandMap(BukkitCommandManager manager, CommandMap proxied) { + super(Bukkit.getServer()); + this.manager = manager; + this.proxied = proxied; + } + + @Override + public void registerAll(String fallbackPrefix, List commands) { + proxied.registerAll(fallbackPrefix, commands); + } + + @Override + public boolean register(String label, String fallbackPrefix, Command command) { + if (isOurCommand(command)) { + return super.register(label, fallbackPrefix, command); + } else { + return proxied.register(label, fallbackPrefix, command); + } + } + + boolean isOurCommand(String cmdLine) { + String[] args = ACFPatterns.SPACE.split(cmdLine); + return args.length != 0 && isOurCommand(knownCommands.get(args[0].toLowerCase(Locale.ENGLISH))); + + } + boolean isOurCommand(Command command) { + return command instanceof RootCommand && ((RootCommand) command).getManager() == manager; + } + + @Override + public boolean register(String fallbackPrefix, Command command) { + if (isOurCommand(command)) { + return super.register(fallbackPrefix, command); + } else { + return proxied.register(fallbackPrefix, command); + } + } + + @Override + public boolean dispatch(CommandSender sender, String cmdLine) throws CommandException { + if (isOurCommand(cmdLine)) { + return super.dispatch(sender, cmdLine); + } else { + return proxied.dispatch(sender, cmdLine); + } + } + + @Override + public void clearCommands() { + super.clearCommands();; + proxied.clearCommands(); + } + + @Override + public Command getCommand(String name) { + if (isOurCommand(name)) { + return super.getCommand(name); + } else { + return proxied.getCommand(name); + } + } + + @Override + public List tabComplete(CommandSender sender, String cmdLine) throws IllegalArgumentException { + if (isOurCommand(cmdLine)) { + return super.tabComplete(sender, cmdLine); + } else { + return proxied.tabComplete(sender, cmdLine); + } + } +} diff --git a/bungee/acf-bungee.iml b/bungee/acf-bungee.iml index 6fce7dba..1314a2c7 100644 --- a/bungee/acf-bungee.iml +++ b/bungee/acf-bungee.iml @@ -18,10 +18,15 @@ - - + + + + + + + @@ -29,11 +34,11 @@ - - - - - + + + + + diff --git a/bungee/src/main/java/co/aikar/commands/BungeeCommandManager.java b/bungee/src/main/java/co/aikar/commands/BungeeCommandManager.java index 002665d7..0a8b7a59 100644 --- a/bungee/src/main/java/co/aikar/commands/BungeeCommandManager.java +++ b/bungee/src/main/java/co/aikar/commands/BungeeCommandManager.java @@ -44,20 +44,40 @@ public class BungeeCommandManager extends CommandManager { protected Map registeredCommands = new HashMap<>(); protected BungeeCommandContexts contexts; protected BungeeCommandCompletions completions; + protected BungeeLocales locales; public BungeeCommandManager(Plugin plugin) { this.plugin = plugin; - String pluginName = "acf-" + plugin.getDescription().getName(); - this.locales.addMessageBundles("acf-minecraft", pluginName, pluginName.toLowerCase()); - this.formatters.put(MessageType.ERROR, new BungeeMessageFormatter(ChatColor.RED, ChatColor.YELLOW, ChatColor.RED)); + this.formatters.put(MessageType.ERROR, defaultFormatter = new BungeeMessageFormatter(ChatColor.RED, ChatColor.YELLOW, ChatColor.RED)); this.formatters.put(MessageType.SYNTAX, new BungeeMessageFormatter(ChatColor.YELLOW, ChatColor.GREEN, ChatColor.WHITE)); this.formatters.put(MessageType.INFO, new BungeeMessageFormatter(ChatColor.BLUE, ChatColor.DARK_GREEN, ChatColor.GREEN)); + getLocales(); // auto load locales } public Plugin getPlugin() { return this.plugin; } + public BungeeMessageFormatter setFormat(MessageType type, BungeeMessageFormatter formatter) { + return (BungeeMessageFormatter) formatters.put(type, formatter); + } + + public BungeeMessageFormatter getFormat(MessageType type) { + return (BungeeMessageFormatter) formatters.getOrDefault(type, defaultFormatter); + } + + public void setFormat(MessageType type, ChatColor... colors) { + BungeeMessageFormatter format = getFormat(type); + for (int i = 0; i < colors.length; i++) { + format.setColor(i, colors[i]); + } + } + + public void setFormat(MessageType type, int i, ChatColor color) { + BungeeMessageFormatter format = getFormat(type); + format.setColor(i, color); + } + @Override public synchronized CommandContexts getCommandContexts() { if (this.contexts == null) { @@ -74,6 +94,16 @@ public class BungeeCommandManager extends CommandManager { return completions; } + @Override + public BungeeLocales getLocales() { + if (this.locales == null) { + this.locales = new BungeeLocales(this); + this.locales.loadLanguages(); + } + return locales; + } + + @Override public void registerCommand(BaseCommand command) { command.onRegister(this); diff --git a/bungee/src/main/java/co/aikar/commands/BungeeLocales.java b/bungee/src/main/java/co/aikar/commands/BungeeLocales.java new file mode 100644 index 00000000..e77a7d17 --- /dev/null +++ b/bungee/src/main/java/co/aikar/commands/BungeeLocales.java @@ -0,0 +1,18 @@ +package co.aikar.commands; + +public class BungeeLocales extends Locales { + private final BungeeCommandManager manager; + + public BungeeLocales(BungeeCommandManager manager) { + super(manager); + + this.manager = manager; + } + + @Override + public void loadLanguages() { + super.loadLanguages(); + String pluginName = "acf-" + manager.plugin.getDescription().getName(); + addMessageBundles("acf-minecraft", pluginName, pluginName.toLowerCase()); + } +} diff --git a/bungee/src/main/java/co/aikar/commands/MinecraftMessageKeys.java b/bungee/src/main/java/co/aikar/commands/MinecraftMessageKeys.java index af84b083..4b3df34d 100644 --- a/bungee/src/main/java/co/aikar/commands/MinecraftMessageKeys.java +++ b/bungee/src/main/java/co/aikar/commands/MinecraftMessageKeys.java @@ -1,6 +1,7 @@ package co.aikar.commands; import co.aikar.locales.MessageKey; +import co.aikar.locales.MessageKeyProvider; public enum MinecraftMessageKeys implements MessageKeyProvider { USERNAME_TOO_SHORT, diff --git a/core/acf-core.iml b/core/acf-core.iml index 750c642e..f609017e 100644 --- a/core/acf-core.iml +++ b/core/acf-core.iml @@ -16,9 +16,9 @@ - + diff --git a/core/src/main/java/co/aikar/commands/CommandIssuer.java b/core/src/main/java/co/aikar/commands/CommandIssuer.java index 738ba950..6a253cfd 100644 --- a/core/src/main/java/co/aikar/commands/CommandIssuer.java +++ b/core/src/main/java/co/aikar/commands/CommandIssuer.java @@ -24,6 +24,7 @@ package co.aikar.commands; import co.aikar.locales.MessageKey; +import co.aikar.locales.MessageKeyProvider; public interface CommandIssuer { /** diff --git a/core/src/main/java/co/aikar/commands/CommandManager.java b/core/src/main/java/co/aikar/commands/CommandManager.java index 067f308c..633d3829 100644 --- a/core/src/main/java/co/aikar/commands/CommandManager.java +++ b/core/src/main/java/co/aikar/commands/CommandManager.java @@ -24,6 +24,8 @@ package co.aikar.commands; import co.aikar.locales.MessageKey; +import co.aikar.locales.MessageKeyProvider; +import com.google.common.collect.Sets; import java.lang.reflect.Method; import java.lang.reflect.Parameter; @@ -38,9 +40,10 @@ public abstract class CommandManager { static ThreadLocal> commandOperationContext = ThreadLocal.withInitial(Stack::new); protected Map rootCommands = new HashMap<>(); protected CommandReplacements replacements = new CommandReplacements(this); - protected Locales locales = new Locales(this); protected ExceptionHandler defaultExceptionHandler = null; + protected Set supportedLanguages = Sets.newHashSet(Locale.ENGLISH); protected Map formatters = new IdentityHashMap<>(); + protected MessageFormatter defaultFormatter; { MessageFormatter plain = new MessageFormatter() { @Override @@ -48,6 +51,7 @@ public abstract class CommandManager { return message; } }; + defaultFormatter = plain; formatters.put(MessageType.INFO, plain); formatters.put(MessageType.SYNTAX, plain); formatters.put(MessageType.ERROR, plain); @@ -93,6 +97,12 @@ public abstract class CommandManager { public abstract RootCommand createRootCommand(String cmd); + /** + * Returns a Locales Manager to add and modify language tables for your commands. + * @return + */ + public abstract Locales getLocales(); + public abstract R createCommandContext(RegisteredCommand command, Parameter parameter, CommandIssuer sender, List args, int i, Map passedArgs); public abstract CommandCompletionContext createCompletionContext(RegisteredCommand command, CommandIssuer sender, String input, String config, String[] args); @@ -116,14 +126,6 @@ public abstract class CommandManager { return replacements; } - /** - * Returns a Locales Manager to add and modify language tables for your commands. - * @return - */ - Locales getLocales() { - return locales; - } - public boolean hasPermission(CommandIssuer issuer, String permission) { return permission == null || permission.isEmpty() || issuer.hasPermission(permission); } @@ -167,22 +169,23 @@ public abstract class CommandManager { public void sendMessage(Object issuerArg, MessageType type, MessageKeyProvider key, String... replacements) { sendMessage(issuerArg, type, key.getMessageKey(), replacements); } + public void sendMessage(Object issuerArg, MessageType type, MessageKey key, String... replacements) { CommandIssuer issuer = issuerArg instanceof CommandIssuer ? (CommandIssuer) issuerArg : getCommandIssuer(issuerArg); String message = getLocales().getMessage(issuer, key); if (replacements.length > 0) { message = ACFUtil.replaceStrings(message, replacements); } - MessageFormatter formatter = formatters.get(type); + MessageFormatter formatter = formatters.getOrDefault(type, defaultFormatter); if (formatter != null) { message = formatter.format(message); } + for (String msg : ACFPatterns.NEWLINE.split(message)) { issuer.sendMessageInternal(msg); } } - public Locale getIssuerLocale(CommandIssuer issuer) { return getLocales().getDefaultLocale(); } @@ -196,4 +199,24 @@ public abstract class CommandManager { args ); } + + /** + * Gets a list of all currently supported languages for this manager. + * These locales will be automatically loaded from + * @return + */ + public Set getSupportedLanguages() { + return supportedLanguages; + } + + /** + * Adds a new locale to the list of automatic Locales to load Message Bundles for. + * All bundles loaded under the previous supported languages will now automatically load for this new locale too. + * + * @param locale + */ + public void addSupportedLanguage(Locale locale) { + supportedLanguages.add(locale); + getLocales().loadMissingBundles(); + } } diff --git a/core/src/main/java/co/aikar/commands/InvalidCommandArgument.java b/core/src/main/java/co/aikar/commands/InvalidCommandArgument.java index 43d2f3ca..e6cf2060 100644 --- a/core/src/main/java/co/aikar/commands/InvalidCommandArgument.java +++ b/core/src/main/java/co/aikar/commands/InvalidCommandArgument.java @@ -24,6 +24,7 @@ package co.aikar.commands; import co.aikar.locales.MessageKey; +import co.aikar.locales.MessageKeyProvider; public class InvalidCommandArgument extends Exception { final boolean showSyntax; diff --git a/core/src/main/java/co/aikar/commands/Locales.java b/core/src/main/java/co/aikar/commands/Locales.java index 7a019624..c698a524 100644 --- a/core/src/main/java/co/aikar/commands/Locales.java +++ b/core/src/main/java/co/aikar/commands/Locales.java @@ -23,44 +23,66 @@ package co.aikar.commands; -import co.aikar.locales.LanguageTable; import co.aikar.locales.LocaleManager; import co.aikar.locales.MessageKey; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.SetMultimap; import org.jetbrains.annotations.NotNull; +import java.util.HashMap; import java.util.Locale; import java.util.Map; @SuppressWarnings("WeakerAccess") public class Locales { - - private static final Locale[] CORE_LANGUAGES = new Locale[]{ - Locale.ENGLISH - }; private final CommandManager manager; private final LocaleManager localeManager; + private final SetMultimap loadedBundles = HashMultimap.create(); - Locales(CommandManager manager) { + public Locales(CommandManager manager) { this.manager = manager; - this.localeManager = LocaleManager.create(manager.getClass(), manager::getIssuerLocale); - this.localeManager.addMessageBundle("acf-core", CORE_LANGUAGES); + this.localeManager = LocaleManager.create(manager::getIssuerLocale); + } + + public void loadLanguages() { + addMessageBundles("acf-core"); } public Locale getDefaultLocale() { return this.localeManager.getDefaultLocale(); } + /** + * Looks for all previously loaded bundles, and if any new Supported Languages have been added, load them. + */ + public void loadMissingBundles() { + for (Locale locale : manager.getSupportedLanguages()) { + for (String bundleName : loadedBundles.keys()) { + addMessageBundle(bundleName, locale); + } + } + } public void addMessageBundles(String... bundleNames) { for (String bundleName : bundleNames) { - this.localeManager.addMessageBundle(bundleName, CORE_LANGUAGES); + for (Locale locale : manager.getSupportedLanguages()) { + addMessageBundle(bundleName, locale); + } } } public void addMessageBundle(String bundleName, Locale locale) { - this.localeManager.addMessageBundle(bundleName, locale); + if (!loadedBundles.containsEntry(bundleName, locale)) { + loadedBundles.put(bundleName, locale); + this.localeManager.addMessageBundle(bundleName, locale); + } } + public void addMessageStrings(Locale locale, @NotNull Map messages) { + Map map = new HashMap<>(messages.size()); + messages.forEach((key, value) -> map.put(MessageKey.of(key), value)); + addMessages(locale, map); + } public void addMessages(Locale locale, @NotNull Map messages) { this.localeManager.addMessages(locale, messages); } diff --git a/core/src/main/java/co/aikar/commands/MessageKeyProvider.java b/core/src/main/java/co/aikar/commands/MessageKeyProvider.java deleted file mode 100644 index 3b88cc9a..00000000 --- a/core/src/main/java/co/aikar/commands/MessageKeyProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package co.aikar.commands; - -import co.aikar.locales.MessageKey; - -public interface MessageKeyProvider { - MessageKey getMessageKey(); -} diff --git a/core/src/main/java/co/aikar/commands/MessageKeys.java b/core/src/main/java/co/aikar/commands/MessageKeys.java index 9cb3a788..7ea7673b 100644 --- a/core/src/main/java/co/aikar/commands/MessageKeys.java +++ b/core/src/main/java/co/aikar/commands/MessageKeys.java @@ -24,6 +24,7 @@ package co.aikar.commands; import co.aikar.locales.MessageKey; +import co.aikar.locales.MessageKeyProvider; /** * Enum Name = MessageKey in lowercase prefixed with acf-core. diff --git a/example/acf-example.iml b/example/acf-example.iml index b14239c2..f108849d 100644 --- a/example/acf-example.iml +++ b/example/acf-example.iml @@ -21,13 +21,15 @@ + + - + @@ -37,8 +39,6 @@ - - diff --git a/paper/acf-paper.iml b/paper/acf-paper.iml index 9269e893..07830e2c 100644 --- a/paper/acf-paper.iml +++ b/paper/acf-paper.iml @@ -18,11 +18,11 @@ + + - - diff --git a/sponge/acf-sponge.iml b/sponge/acf-sponge.iml index ca8de4b2..ee0aaf6f 100644 --- a/sponge/acf-sponge.iml +++ b/sponge/acf-sponge.iml @@ -18,10 +18,10 @@ - - + + diff --git a/sponge/src/main/java/co/aikar/commands/MinecraftMessageKeys.java b/sponge/src/main/java/co/aikar/commands/MinecraftMessageKeys.java index e438b2e1..5503a5be 100644 --- a/sponge/src/main/java/co/aikar/commands/MinecraftMessageKeys.java +++ b/sponge/src/main/java/co/aikar/commands/MinecraftMessageKeys.java @@ -24,6 +24,7 @@ package co.aikar.commands; import co.aikar.locales.MessageKey; +import co.aikar.locales.MessageKeyProvider; public enum MinecraftMessageKeys implements MessageKeyProvider { INVALID_WORLD, diff --git a/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java b/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java index 7006f1b6..f2f9de5d 100644 --- a/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java +++ b/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java @@ -30,6 +30,7 @@ import org.slf4j.Logger; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.plugin.PluginContainer; +import org.spongepowered.api.text.format.TextColor; import org.spongepowered.api.text.format.TextColors; import java.lang.reflect.Method; @@ -46,16 +47,42 @@ public class SpongeCommandManager extends CommandManager { protected SpongeCommandContexts contexts; protected SpongeCommandCompletions completions; private Timing commandTiming; + protected SpongeLocales locales; public SpongeCommandManager(PluginContainer plugin) { this.plugin = plugin; String pluginName = "acf-" + plugin.getName(); - this.locales.addMessageBundles("acf-minecraft", pluginName, pluginName.toLowerCase()); + getLocales().addMessageBundles("acf-minecraft", pluginName, pluginName.toLowerCase()); this.commandTiming = Timings.of(plugin, "Commands"); - this.formatters.put(MessageType.ERROR, new SpongeMessageFormatter(TextColors.RED, TextColors.YELLOW, TextColors.RED)); + this.formatters.put(MessageType.ERROR, defaultFormatter = new SpongeMessageFormatter(TextColors.RED, TextColors.YELLOW, TextColors.RED)); this.formatters.put(MessageType.SYNTAX, new SpongeMessageFormatter(TextColors.YELLOW, TextColors.GREEN, TextColors.WHITE)); this.formatters.put(MessageType.INFO, new SpongeMessageFormatter(TextColors.BLUE, TextColors.DARK_GREEN, TextColors.GREEN)); + getLocales(); // auto load locales + } + + public PluginContainer getPlugin() { + return plugin; + } + + public SpongeMessageFormatter setFormat(MessageType type, SpongeMessageFormatter formatter) { + return (SpongeMessageFormatter) formatters.put(type, formatter); + } + + public SpongeMessageFormatter getFormat(MessageType type) { + return (SpongeMessageFormatter) formatters.getOrDefault(type, defaultFormatter); + } + + public void setFormat(MessageType type, TextColor... colors) { + SpongeMessageFormatter format = getFormat(type); + for (int i = 0; i < colors.length; i++) { + format.setColor(i, colors[i]); + } + } + + public void setFormat(MessageType type, int i, TextColor color) { + SpongeMessageFormatter format = getFormat(type); + format.setColor(i, color); } @Override @@ -79,6 +106,15 @@ public class SpongeCommandManager extends CommandManager { return completions; } + @Override + public SpongeLocales getLocales() { + if (this.locales == null) { + this.locales = new SpongeLocales(this); + this.locales.loadLanguages(); + } + return locales; + } + @Override public boolean hasRegisteredCommands() { return !registeredCommands.isEmpty(); diff --git a/sponge/src/main/java/co/aikar/commands/SpongeLocales.java b/sponge/src/main/java/co/aikar/commands/SpongeLocales.java new file mode 100644 index 00000000..a0889998 --- /dev/null +++ b/sponge/src/main/java/co/aikar/commands/SpongeLocales.java @@ -0,0 +1,17 @@ +package co.aikar.commands; + +public class SpongeLocales extends Locales{ + private final SpongeCommandManager manager; + + public SpongeLocales(SpongeCommandManager manager) { + super(manager); + this.manager = manager; + } + + @Override + public void loadLanguages() { + super.loadLanguages(); + String pluginName = "acf-" + manager.plugin.getName(); + addMessageBundles("acf-minecraft", pluginName, pluginName.toLowerCase()); + } +}