diff --git a/.gitignore b/.gitignore index cfe9fa50..fe5b3b35 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ .idea/dictionaries .idea/misc.xml .idea/libraries +.idea/uiDesigner.xml .idea/kotlinc.xml diff --git a/.idea/codeInsightSettings.xml b/.idea/codeInsightSettings.xml new file mode 100644 index 00000000..e3f4d2b0 --- /dev/null +++ b/.idea/codeInsightSettings.xml @@ -0,0 +1,8 @@ + + + + + java.awt + + + \ No newline at end of file diff --git a/.idea/fileTemplates/includes/File Header.java b/.idea/fileTemplates/includes/File Header.java new file mode 100644 index 00000000..e69de29b diff --git a/bukkit/acf-bukkit.iml b/bukkit/acf-bukkit.iml index 5e19d3d6..ab67942b 100644 --- a/bukkit/acf-bukkit.iml +++ b/bukkit/acf-bukkit.iml @@ -14,6 +14,7 @@ + diff --git a/bukkit/pom.xml b/bukkit/pom.xml index 121655e4..e720ee8d 100644 --- a/bukkit/pom.xml +++ b/bukkit/pom.xml @@ -86,5 +86,10 @@ + + + ${project.basedir}/../languages/minecraft/ + + diff --git a/bukkit/src/main/java/co/aikar/commands/ACFBukkitUtil.java b/bukkit/src/main/java/co/aikar/commands/ACFBukkitUtil.java index 99c59aaa..ff643718 100644 --- a/bukkit/src/main/java/co/aikar/commands/ACFBukkitUtil.java +++ b/bukkit/src/main/java/co/aikar/commands/ACFBukkitUtil.java @@ -23,6 +23,7 @@ package co.aikar.commands; +import co.aikar.locales.MessageKey; import com.google.common.collect.Iterables; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -60,6 +61,12 @@ public class ACFBukkitUtil { return ChatColor.translateAlternateColorCodes('&', message); } + public static void sendMsg(CommandIssuer issuer, MessageKey key, String... replacements) { + sendMsg(issuer, MessageType.INFO, key, replacements); + } + public static void sendMsg(CommandIssuer issuer, MessageType type, MessageKey key, String... replacements) { + issuer.sendMessage(type, key, replacements); + } public static void sendMsg(CommandSender player, String message) { message = color(message); for (String msg : ACFPatterns.NEWLINE.split(message)) { @@ -232,6 +239,14 @@ public class ACFBukkitUtil { return loc1.getWorld() == loc2.getWorld() && loc1.distance(loc2) <= dist; } + /** + * Please move to the CommandIssuer version + * @param requester + * @param origName + * @deprecated + * @return + */ + @Deprecated public static Player findPlayerSmart(CommandSender requester, String origName) { if (origName == null) { return null; @@ -278,8 +293,60 @@ public class ACFBukkitUtil { Player player = Iterables.getOnlyElement(confirmList); sendMsg(requester, "&cWarning: " + player.getDisplayName() + "&c is vanished. Do not blow their cover!\n" + - "&cTo confirm your action, add &f:confirm&c to the end of their name. \n" + - "&bEx: &e/g " + player.getName() + ":confirm"); + "&cTo confirm your action, add &f:confirm&c to the end of their name. \n" + + "&bEx: &e/g " + player.getName() + ":confirm"); + return null; + } + } + + return matches.get(0); + } + public static Player findPlayerSmart(CommandIssuer issuer, String origName) { + CommandSender requester = issuer.getIssuer(); + if (origName == null) { + return null; + } + String name = ACFUtil.replace(origName, ":confirm", ""); + if (name.length() < 3) { + issuer.sendError(BukkitMessageKeys.USERNAME_TOO_SHORT); + return null; + } + if (!isValidName(name)) { + issuer.sendError(BukkitMessageKeys.IS_NOT_A_VALID_NAME, "{name}", name); + return null; + } + + List matches = Bukkit.getServer().matchPlayer(name); + List confirmList = new ArrayList<>(); + + // Remove confirmList players from smart matching. + Iterator iter = matches.iterator(); + while (iter.hasNext()) { + Player player = iter.next(); + if (requester instanceof Player && !((Player) requester).canSee(player)) { + if (requester.hasPermission("acf.seevanish")) { + if (!origName.endsWith(":confirm")) { + confirmList.add(player); + iter.remove(); + } + } else { + iter.remove(); + } + } + } + + if (matches.size() > 1 || confirmList.size() > 1) { + requester.sendMessage("§cMultiple players matched '" + name + "', please be more specific"); + return null; + } + + if (matches.isEmpty()) { + if (confirmList.isEmpty()) { + requester.sendMessage("§cNo player matching '" + name + "' is connected to this server"); + return null; + } else { + Player player = Iterables.getOnlyElement(confirmList); + issuer.sendMessage(MessageType.INFO, BukkitMessageKeys.PLAYER_IS_VANISHED_CONFIRM, "{vanished}", player.getName()); return null; } } diff --git a/bukkit/src/main/java/co/aikar/commands/BukkitCommandContexts.java b/bukkit/src/main/java/co/aikar/commands/BukkitCommandContexts.java index 853ac64e..a0491973 100644 --- a/bukkit/src/main/java/co/aikar/commands/BukkitCommandContexts.java +++ b/bukkit/src/main/java/co/aikar/commands/BukkitCommandContexts.java @@ -47,7 +47,7 @@ public class BukkitCommandContexts extends CommandContexts getOnlinePlayer(c.getSender(), c.popFirstArg(), c.hasAnnotation(Optional.class))); + registerContext(OnlinePlayer.class, c -> getOnlinePlayer(c.getIssuer(), c.popFirstArg(), c.hasAnnotation(Optional.class))); registerContext(OnlinePlayer[].class, (c) -> { CommandSender sender = c.getSender(); final String input = c.popFirstArg(); @@ -59,7 +59,7 @@ public class BukkitCommandContexts extends CommandContexts { Player player = c.getSender() instanceof Player ? (Player) c.getSender() : null; if (player == null && !c.hasAnnotation(Optional.class)) { - throw new InvalidCommandArgument("Requires a player to run this command", false); + throw new InvalidCommandArgument(MessageKeys.NOT_ALLOWED_ON_CONSOLE, false); } PlayerInventory inventory = player != null ? player.getInventory() : null; if (inventory != null && c.hasFlag("itemheld") && !ACFBukkitUtil.isValidItem(inventory.getItem(inventory.getHeldItemSlot()))) { - throw new InvalidCommandArgument("You must be holding an item in your main hand.", false); + throw new InvalidCommandArgument(BukkitMessageKeys.YOU_MUST_BE_HOLDING_ITEM, false); } return player; }); @@ -113,9 +113,9 @@ public class BukkitCommandContexts extends CommandContexts ChatColor.YELLOW + ACFUtil.simplifyString(color.name())) - .collect(Collectors.joining("&c, ")); + .collect(Collectors.joining(", ")); - throw new InvalidCommandArgument("Please specify one of: " + valid); + throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, "{valid}", valid); } return match; }); @@ -132,13 +132,14 @@ public class BukkitCommandContexts extends CommandContexts { - BukkitCommandExecutionContext(RegisteredCommand cmd, Parameter param, CommandIssuer sender, List args, +public class BukkitCommandExecutionContext extends CommandExecutionContext { + BukkitCommandExecutionContext(RegisteredCommand cmd, Parameter param, BukkitCommandIssuer sender, List args, int index, Map passedArgs) { super(cmd, param, sender, args, index, passedArgs); } diff --git a/bukkit/src/main/java/co/aikar/commands/BukkitCommandManager.java b/bukkit/src/main/java/co/aikar/commands/BukkitCommandManager.java index 270f85dd..2dc33819 100644 --- a/bukkit/src/main/java/co/aikar/commands/BukkitCommandManager.java +++ b/bukkit/src/main/java/co/aikar/commands/BukkitCommandManager.java @@ -65,6 +65,7 @@ public class BukkitCommandManager extends CommandManager { @SuppressWarnings("JavaReflectionMemberAccess") public BukkitCommandManager(Plugin plugin) { this.plugin = plugin; + this.locales.addMessageBundle("acf-minecraft", Locale.ENGLISH); this.timingManager = TimingManager.of(plugin); this.commandTiming = this.timingManager.of("Commands"); CommandMap commandMap = null; @@ -193,7 +194,8 @@ public class BukkitCommandManager extends CommandManager { @Override public R createCommandContext(RegisteredCommand command, Parameter parameter, CommandIssuer sender, List args, int i, Map passedArgs) { - return (R) new BukkitCommandExecutionContext(command, parameter, sender, args, i, passedArgs); + //noinspection unchecked + return (R) new BukkitCommandExecutionContext(command, parameter, (BukkitCommandIssuer) sender, args, i, passedArgs); } @Override diff --git a/bukkit/src/main/java/co/aikar/commands/BukkitMessageKeys.java b/bukkit/src/main/java/co/aikar/commands/BukkitMessageKeys.java new file mode 100644 index 00000000..63a39976 --- /dev/null +++ b/bukkit/src/main/java/co/aikar/commands/BukkitMessageKeys.java @@ -0,0 +1,37 @@ +/* + * 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 enum BukkitMessageKeys implements MessageKeyProvider { + INVALID_WORLD, + YOU_MUST_BE_HOLDING_ITEM, + PLAYER_IS_VANISHED_CONFIRM, USERNAME_TOO_SHORT, IS_NOT_A_VALID_NAME; + + private final MessageKey key = MessageKey.of(this.name().toLowerCase()); + public MessageKey getMessageKey() { + return key; + } +} diff --git a/bungee/pom.xml b/bungee/pom.xml index e3189cf6..b2841d05 100644 --- a/bungee/pom.xml +++ b/bungee/pom.xml @@ -36,5 +36,12 @@ provided + + + + ${project.basedir}/../languages/minecraft/ + + + diff --git a/bungee/src/main/java/co/aikar/commands/ACFBungeeUtil.java b/bungee/src/main/java/co/aikar/commands/ACFBungeeUtil.java index 55e8948b..096edca5 100644 --- a/bungee/src/main/java/co/aikar/commands/ACFBungeeUtil.java +++ b/bungee/src/main/java/co/aikar/commands/ACFBungeeUtil.java @@ -23,6 +23,7 @@ package co.aikar.commands; +import co.aikar.locales.MessageKey; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.ProxyServer; @@ -38,6 +39,12 @@ public class ACFBungeeUtil { return ChatColor.translateAlternateColorCodes('&', message); } + public static void sendMsg(CommandIssuer issuer, MessageKey key, String... replacements) { + sendMsg(issuer, MessageType.INFO, key, replacements); + } + public static void sendMsg(CommandIssuer issuer, MessageType type, MessageKey key, String... replacements) { + issuer.sendMessage(type, key, replacements); + } public static void sendMsg(CommandSender player, String message) { message = color(message); for (String msg : ACFPatterns.NEWLINE.split(message)) { diff --git a/bungee/src/main/java/co/aikar/commands/BungeeCommandContexts.java b/bungee/src/main/java/co/aikar/commands/BungeeCommandContexts.java index cb9a0924..0fb83c17 100644 --- a/bungee/src/main/java/co/aikar/commands/BungeeCommandContexts.java +++ b/bungee/src/main/java/co/aikar/commands/BungeeCommandContexts.java @@ -44,7 +44,8 @@ public class BungeeCommandContexts extends CommandContexts { ProxiedPlayer proxiedPlayer = c.getSender() instanceof ProxiedPlayer ? (ProxiedPlayer) c.getSender() : null; if (proxiedPlayer == null && !c.hasAnnotation(Optional.class)) { - throw new InvalidCommandArgument("Requires a player to run this command", false); + throw new InvalidCommandArgument(MessageKeys.NOT_ALLOWED_ON_CONSOLE, false); } return proxiedPlayer; }); @@ -74,9 +75,9 @@ public class BungeeCommandContexts extends CommandContexts ChatColor.YELLOW + ACFUtil.simplifyString(color.name())) - .collect(Collectors.joining("&c, ")); + .collect(Collectors.joining(", ")); - throw new InvalidCommandArgument("Please specify one of: " + valid); + throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, "{valid}", valid); } return match; }); diff --git a/bungee/src/main/java/co/aikar/commands/BungeeCommandExecutionContext.java b/bungee/src/main/java/co/aikar/commands/BungeeCommandExecutionContext.java index e8439177..01853b79 100644 --- a/bungee/src/main/java/co/aikar/commands/BungeeCommandExecutionContext.java +++ b/bungee/src/main/java/co/aikar/commands/BungeeCommandExecutionContext.java @@ -29,9 +29,9 @@ import java.lang.reflect.Parameter; import java.util.List; import java.util.Map; -public class BungeeCommandExecutionContext extends CommandExecutionContext { +public class BungeeCommandExecutionContext extends CommandExecutionContext { - BungeeCommandExecutionContext(RegisteredCommand cmd, Parameter param, CommandIssuer sender, List args, int index, Map passedArgs) { + BungeeCommandExecutionContext(RegisteredCommand cmd, Parameter param, BungeeCommandIssuer sender, List args, int index, Map passedArgs) { super(cmd, param, sender, args, index, passedArgs); } diff --git a/bungee/src/main/java/co/aikar/commands/BungeeCommandManager.java b/bungee/src/main/java/co/aikar/commands/BungeeCommandManager.java index 93e484bb..879ce531 100644 --- a/bungee/src/main/java/co/aikar/commands/BungeeCommandManager.java +++ b/bungee/src/main/java/co/aikar/commands/BungeeCommandManager.java @@ -33,6 +33,7 @@ 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; @@ -47,6 +48,7 @@ public class BungeeCommandManager extends CommandManager { public BungeeCommandManager(Plugin plugin) { this.plugin = plugin; + this.locales.addMessageBundle("acf-minecraft", Locale.ENGLISH); this.formatters.put(MessageType.ERROR, 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)); @@ -112,7 +114,7 @@ public class BungeeCommandManager extends CommandManager { @Override public R createCommandContext(RegisteredCommand command, Parameter parameter, CommandIssuer sender, List args, int i, Map passedArgs) { //noinspection unchecked - return (R) new BungeeCommandExecutionContext(command, parameter, sender, args, i, passedArgs); + return (R) new BungeeCommandExecutionContext(command, parameter, (BungeeCommandIssuer) sender, args, i, passedArgs); } @Override diff --git a/core/pom.xml b/core/pom.xml index f34f4908..5f80262b 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -85,5 +85,10 @@ + + + ${project.basedir}/../languages/core/ + + diff --git a/core/src/main/java/co/aikar/commands/BaseCommand.java b/core/src/main/java/co/aikar/commands/BaseCommand.java index 36395ae3..203617b1 100644 --- a/core/src/main/java/co/aikar/commands/BaseCommand.java +++ b/core/src/main/java/co/aikar/commands/BaseCommand.java @@ -200,7 +200,7 @@ public abstract class BaseCommand { if (parameters.length == 1) { subCommand = (BaseCommand) declaredConstructor.newInstance(this); } else { - manager.log(LogLevel.INFO, "Found unusable constructor: " + declaredConstructor.getName() + "(" + Stream.of(parameters).map(p -> p.getType().getSimpleName() + " " + p.getName()).collect(Collectors.joining(", ")) + ")"); + manager.log(LogLevel.INFO, "Found unusable constructor: " + declaredConstructor.getName() + "(" + Stream.of(parameters).map(p -> p.getType().getSimpleName() + " " + p.getName()).collect(Collectors.joining(", ")) + ")"); } } if (subCommand != null) { diff --git a/core/src/main/java/co/aikar/commands/CommandContexts.java b/core/src/main/java/co/aikar/commands/CommandContexts.java index 8f34b2a5..81173e13 100644 --- a/core/src/main/java/co/aikar/commands/CommandContexts.java +++ b/core/src/main/java/co/aikar/commands/CommandContexts.java @@ -29,14 +29,13 @@ import co.aikar.commands.annotation.Values; import co.aikar.commands.contexts.ContextResolver; import co.aikar.commands.contexts.IssuerAwareContextResolver; import co.aikar.commands.contexts.IssuerOnlyContextResolver; -import co.aikar.commands.contexts.SenderAwareContextResolver; import com.google.common.collect.Maps; import java.util.List; import java.util.Map; @SuppressWarnings("WeakerAccess") -public class CommandContexts > { +public class CommandContexts > { protected final Map, ContextResolver> contextMap = Maps.newHashMap(); protected final CommandManager manager; @@ -46,14 +45,14 @@ public class CommandContexts > { try { return ACFUtil.parseNumber(c.popFirstArg(), c.hasFlag("suffixes")).intValue(); } catch (NumberFormatException e) { - throw new InvalidCommandArgument("Must be a number"); + throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); } }); registerContext(Long.class, (c) -> { try { return ACFUtil.parseNumber(c.popFirstArg(), c.hasFlag("suffixes")).longValue(); } catch (NumberFormatException e) { - throw new InvalidCommandArgument("Must be a number"); + throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); } }); @@ -61,21 +60,21 @@ public class CommandContexts > { try { return ACFUtil.parseNumber(c.popFirstArg(), c.hasFlag("suffixes")).floatValue(); } catch (NumberFormatException e) { - throw new InvalidCommandArgument("Must be a number"); + throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); } }); registerContext(Double.class, (c) -> { try { return ACFUtil.parseNumber(c.popFirstArg(), c.hasFlag("suffixes")).doubleValue(); } catch (NumberFormatException e) { - throw new InvalidCommandArgument("Must be a number"); + throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); } }); registerContext(Number.class, (c) -> { try { return ACFUtil.parseNumber(c.popFirstArg(), c.hasFlag("suffixes")); } catch (NumberFormatException e) { - throw new InvalidCommandArgument("Must be a number"); + throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); } }); registerContext(Boolean.class, (c) -> { @@ -99,12 +98,12 @@ public class CommandContexts > { Integer maxLen = c.getFlagValue("maxlen", (Integer) null); if (minLen != null) { if (ret.length() < minLen) { - throw new InvalidCommandArgument("Must be at least " + minLen + " characters long"); + throw new InvalidCommandArgument(MessageKeys.MUST_BE_MIN_LENGTH, "{min}", String.valueOf(minLen)); } } if (maxLen != null) { if (ret.length() > maxLen) { - throw new InvalidCommandArgument("Must be less " + maxLen + " characters long"); + throw new InvalidCommandArgument(MessageKeys.MUST_BE_MAX_LENGTH, "{max}", String.valueOf(maxLen)); } } @@ -142,7 +141,7 @@ public class CommandContexts > { Enum match = ACFUtil.simpleMatch(enumCls, first); if (match == null) { List names = ACFUtil.enumNames(enumCls); - throw new InvalidCommandArgument("Please specify one of: " + ACFUtil.join(names)); + throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, "{valid}", ACFUtil.join(names)); } return match; }); diff --git a/core/src/main/java/co/aikar/commands/CommandExecutionContext.java b/core/src/main/java/co/aikar/commands/CommandExecutionContext.java index 4e6d4863..06ae90d1 100644 --- a/core/src/main/java/co/aikar/commands/CommandExecutionContext.java +++ b/core/src/main/java/co/aikar/commands/CommandExecutionContext.java @@ -37,16 +37,16 @@ import java.util.List; import java.util.Map; @SuppressWarnings({"WeakerAccess", "unused"}) -public class CommandExecutionContext { +public class CommandExecutionContext { private final RegisteredCommand cmd; private final Parameter param; - protected final CommandIssuer issuer; + protected final I issuer; private final List args; private final int index; private final Map passedArgs; private final Map flags; - CommandExecutionContext(RegisteredCommand cmd, Parameter param, CommandIssuer sender, List args, + CommandExecutionContext(RegisteredCommand cmd, Parameter param, I sender, List args, int index, Map passedArgs) { this.cmd = cmd; this.param = param; @@ -157,7 +157,7 @@ public class CommandExecutionContext { return this.param; } - public CommandIssuer getIssuer() { + public I getIssuer() { return this.issuer; } diff --git a/core/src/main/java/co/aikar/commands/CommandIssuer.java b/core/src/main/java/co/aikar/commands/CommandIssuer.java index 5c4a5d03..738ba950 100644 --- a/core/src/main/java/co/aikar/commands/CommandIssuer.java +++ b/core/src/main/java/co/aikar/commands/CommandIssuer.java @@ -56,6 +56,27 @@ public interface CommandIssuer { */ boolean hasPermission(String permission); + default void sendError(MessageKeyProvider key, String... replacements) { + sendMessage(MessageType.ERROR, key.getMessageKey(), replacements); + } + default void sendSyntax(MessageKeyProvider key, String... replacements) { + sendMessage(MessageType.SYNTAX, key.getMessageKey(), replacements); + } + default void sendInfo(MessageKeyProvider key, String... replacements) { + sendMessage(MessageType.INFO, key.getMessageKey(), replacements); + } + default void sendError(MessageKey key, String... replacements) { + sendMessage(MessageType.ERROR, key, replacements); + } + default void sendSyntax(MessageKey key, String... replacements) { + sendMessage(MessageType.SYNTAX, key, replacements); + } + default void sendInfo(MessageKey key, String... replacements) { + sendMessage(MessageType.INFO, key, replacements); + } + default void sendMessage(MessageType type, MessageKeyProvider key, String... replacements) { + sendMessage(type, key.getMessageKey(), replacements); + } default void sendMessage(MessageType type, MessageKey key, String... replacements) { getManager().sendMessage(this, type, key, replacements); } diff --git a/core/src/main/java/co/aikar/commands/CommandManager.java b/core/src/main/java/co/aikar/commands/CommandManager.java index 4379465f..3ec465e2 100644 --- a/core/src/main/java/co/aikar/commands/CommandManager.java +++ b/core/src/main/java/co/aikar/commands/CommandManager.java @@ -27,7 +27,6 @@ import co.aikar.locales.MessageKey; import java.lang.reflect.Method; import java.lang.reflect.Parameter; -import java.util.EnumMap; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.List; @@ -151,6 +150,9 @@ abstract class CommandManager { return result; } + protected void sendMessage(Object issuerArg, MessageType type, MessageKeyProvider key, String... replacements) { + sendMessage(issuerArg, type, key.getMessageKey(), replacements); + } protected 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); @@ -161,7 +163,9 @@ abstract class CommandManager { if (formatter != null) { message = formatter.format(message); } - issuer.sendMessageInternal(message); + for (String msg : ACFPatterns.NEWLINE.split(message)) { + issuer.sendMessageInternal(msg); + } } diff --git a/core/src/main/java/co/aikar/commands/InvalidCommandArgument.java b/core/src/main/java/co/aikar/commands/InvalidCommandArgument.java index 41711633..43d2f3ca 100644 --- a/core/src/main/java/co/aikar/commands/InvalidCommandArgument.java +++ b/core/src/main/java/co/aikar/commands/InvalidCommandArgument.java @@ -23,19 +23,52 @@ package co.aikar.commands; +import co.aikar.locales.MessageKey; + public class InvalidCommandArgument extends Exception { - public boolean showSyntax = true; + final boolean showSyntax; + final MessageKey key; + final String[] replacements; + public InvalidCommandArgument() { - this(null); + this((String) null, true); } public InvalidCommandArgument(boolean showSyntax) { this(null, showSyntax); } - public InvalidCommandArgument(String message) { - this(message, true); + public InvalidCommandArgument(MessageKeyProvider key, String... replacements) { + this(key.getMessageKey(), replacements); } + public InvalidCommandArgument(MessageKey key, String... replacements) { + this(key, true, replacements); + } + public InvalidCommandArgument(MessageKeyProvider key, boolean showSyntax, String... replacements) { + this(key.getMessageKey(), showSyntax, replacements); + } + public InvalidCommandArgument(MessageKey key, boolean showSyntax, String... replacements) { + super(key.getKey(), null, false, false); + this.showSyntax = showSyntax; + this.key = key; + this.replacements = replacements; + } + + /** + * Please move to a MessageKey + * @deprecated + */ + @Deprecated + public InvalidCommandArgument(String message) { + this(message, true); + } + /** + * Please move to a MessageKey + * @deprecated + */ + @Deprecated public InvalidCommandArgument(String message, boolean showSyntax) { super(message, null, false, false); this.showSyntax = showSyntax; + this.replacements = null; + this.key = null; } } diff --git a/core/src/main/java/co/aikar/commands/MessageKeyProvider.java b/core/src/main/java/co/aikar/commands/MessageKeyProvider.java new file mode 100644 index 00000000..3b88cc9a --- /dev/null +++ b/core/src/main/java/co/aikar/commands/MessageKeyProvider.java @@ -0,0 +1,30 @@ +/* + * 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 cdd2b34d..64716ada 100644 --- a/core/src/main/java/co/aikar/commands/MessageKeys.java +++ b/core/src/main/java/co/aikar/commands/MessageKeys.java @@ -25,13 +25,26 @@ package co.aikar.commands; import co.aikar.locales.MessageKey; +/** + * Enum Name = MessageKey in lowercase + */ @SuppressWarnings("WeakerAccess") -public class MessageKeys { - public static final MessageKey PERMISSION_DENIED = MessageKey.of("permission_denied"); - public static final MessageKey ERROR_GENERIC_LOGGED = MessageKey.of("error_generic_logged"); - public static final MessageKey UNKNOWN_COMMAND = MessageKey.of("unknown_command"); - public static final MessageKey INVALID_SYNTAX = MessageKey.of("invalid_syntax"); - public static final MessageKey ERROR_PREFIX = MessageKey.of("error_prefix"); - public static final MessageKey ERROR_PERFORMING_COMMAND = MessageKey.of("error_performing_command"); - public static final MessageKey INFO_MESSAGE = MessageKey.of("info_message"); +public enum MessageKeys implements MessageKeyProvider { + PERMISSION_DENIED, + ERROR_GENERIC_LOGGED, + UNKNOWN_COMMAND, + INVALID_SYNTAX, + ERROR_PREFIX, + ERROR_PERFORMING_COMMAND, + INFO_MESSAGE, + PLEASE_SPECIFY_ONE_OF, + MUST_BE_A_NUMBER, + MUST_BE_MIN_LENGTH, + MUST_BE_MAX_LENGTH, + NOT_ALLOWED_ON_CONSOLE, COULD_NOT_FIND_PLAYER; + + private final MessageKey key = MessageKey.of(this.name().toLowerCase()); + public MessageKey getMessageKey() { + return key; + } } diff --git a/core/src/main/java/co/aikar/commands/RegisteredCommand.java b/core/src/main/java/co/aikar/commands/RegisteredCommand.java index 48a10043..c3e6772a 100644 --- a/core/src/main/java/co/aikar/commands/RegisteredCommand.java +++ b/core/src/main/java/co/aikar/commands/RegisteredCommand.java @@ -47,7 +47,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -public class RegisteredCommand > { +public class RegisteredCommand > { final BaseCommand scope; public final String command; private final Method method; @@ -153,10 +153,13 @@ public class RegisteredCommand > { +public interface ContextResolver > { T getContext(C c) throws InvalidCommandArgument; } diff --git a/core/src/main/java/co/aikar/commands/contexts/IssuerAwareContextResolver.java b/core/src/main/java/co/aikar/commands/contexts/IssuerAwareContextResolver.java index 9be13e2a..b157b28b 100644 --- a/core/src/main/java/co/aikar/commands/contexts/IssuerAwareContextResolver.java +++ b/core/src/main/java/co/aikar/commands/contexts/IssuerAwareContextResolver.java @@ -24,6 +24,7 @@ package co.aikar.commands.contexts; import co.aikar.commands.CommandExecutionContext; +import co.aikar.commands.CommandIssuer; -public interface IssuerAwareContextResolver> extends ContextResolver {} +public interface IssuerAwareContextResolver> extends ContextResolver {} diff --git a/core/src/main/java/co/aikar/commands/contexts/IssuerOnlyContextResolver.java b/core/src/main/java/co/aikar/commands/contexts/IssuerOnlyContextResolver.java index 32450e92..b99c9d1b 100644 --- a/core/src/main/java/co/aikar/commands/contexts/IssuerOnlyContextResolver.java +++ b/core/src/main/java/co/aikar/commands/contexts/IssuerOnlyContextResolver.java @@ -24,10 +24,11 @@ package co.aikar.commands.contexts; import co.aikar.commands.CommandExecutionContext; +import co.aikar.commands.CommandIssuer; /** * A context resolver that will never consume input, and only resolves using the context of the issuer of the command * @param * @param */ -public interface IssuerOnlyContextResolver> extends ContextResolver {} +public interface IssuerOnlyContextResolver> extends ContextResolver {} diff --git a/core/src/main/java/co/aikar/commands/contexts/SenderAwareContextResolver.java b/core/src/main/java/co/aikar/commands/contexts/SenderAwareContextResolver.java index 4daefe00..fa7a7730 100644 --- a/core/src/main/java/co/aikar/commands/contexts/SenderAwareContextResolver.java +++ b/core/src/main/java/co/aikar/commands/contexts/SenderAwareContextResolver.java @@ -24,6 +24,7 @@ package co.aikar.commands.contexts; import co.aikar.commands.CommandExecutionContext; +import co.aikar.commands.CommandIssuer; /** * Wrapper for IssuerAwareContextResolver @@ -32,4 +33,4 @@ import co.aikar.commands.CommandExecutionContext; * @see IssuerAwareContextResolver */ @Deprecated -public interface SenderAwareContextResolver> extends IssuerAwareContextResolver {} +public interface SenderAwareContextResolver> extends IssuerAwareContextResolver {} diff --git a/core/src/main/resources/acf-core_en.properties b/core/src/main/resources/acf-core_en.properties deleted file mode 100644 index 755c9474..00000000 --- a/core/src/main/resources/acf-core_en.properties +++ /dev/null @@ -1,7 +0,0 @@ -permission_denied = I'm sorry, but you do not have permission to perform this command. -error_generic_logged = An error occured. This problem has been logged. Sorry for the inconvienence. -unknown_command = Unknown Command, please type /help -invalid_syntax = Usage: {command} {syntax} -error_prefix = Error: {message} -error_performing_command = I'm sorry, but there was an error performing this command. -info_message = {message} diff --git a/example/src/main/java/co/aikar/acfexample/SomeObject.java b/example/src/main/java/co/aikar/acfexample/SomeObject.java index 2077309c..b4cb1f53 100644 --- a/example/src/main/java/co/aikar/acfexample/SomeObject.java +++ b/example/src/main/java/co/aikar/acfexample/SomeObject.java @@ -25,6 +25,7 @@ package co.aikar.acfexample; import co.aikar.commands.BukkitCommandExecutionContext; import co.aikar.commands.InvalidCommandArgument; +import co.aikar.commands.MessageKeys; import co.aikar.commands.contexts.ContextResolver; public abstract class SomeObject { @@ -41,9 +42,6 @@ public abstract class SomeObject { public static ContextResolver getContextResolver() { return (c) -> { String first = c.popFirstArg(); - if (first == null) { - throw new InvalidCommandArgument("Must supply a number"); - } if ("1".equals(first)) { return new Test1(); } else if ("2".equals(first)) { @@ -52,7 +50,7 @@ public abstract class SomeObject { try { return new TestOther(Integer.parseInt(first)); } catch (NumberFormatException ignored) { - throw new InvalidCommandArgument("Must be a valid number"); + throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); } } }; diff --git a/languages/core/acf-core_en.properties b/languages/core/acf-core_en.properties new file mode 100644 index 00000000..8bac7ade --- /dev/null +++ b/languages/core/acf-core_en.properties @@ -0,0 +1,35 @@ +# 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. +# + +permission_denied = I'm sorry, but you do not have permission to perform this command. +error_generic_logged = An error occured. This problem has been logged. Sorry for the inconvienence. +unknown_command = Unknown Command, please type /help +invalid_syntax = Usage: {command} {syntax} +error_prefix = Error: {message} +error_performing_command = I'm sorry, but there was an error performing this command. +info_message = {message} +please_specify_one_of = Error: Please specify one of ({valid}). +must_be_a_number = Error: Must be a number +must_be_min_length = Error: Must be at least {min} characters long. +must_be_max_length = Error: Must be less than {max} characters long. +not_allowed_on_console = Error: Console may not execute this command. +could_not_find_player = Error: Could not find a player by the name: {search} diff --git a/languages/minecraft/acf-minecraft_en.properties b/languages/minecraft/acf-minecraft_en.properties new file mode 100644 index 00000000..ef7535b4 --- /dev/null +++ b/languages/minecraft/acf-minecraft_en.properties @@ -0,0 +1,32 @@ +# +# 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. +# + +invalid_world = Error: That world does not exists. +you_must_be_holding_item = Error: You must be holding an item in your main hand. +player_is_vanished_confirm = \ + Warning: {vanished} is vanished. Do not blow their cover!\n\ + To confirm your action, add :confirm to the end of their name.\n\ + Ex: {vanished}:confirm +username_too_short = Error: Username too short, must be at least three characters. +is_not_a_valid_name = Error: {name} is not a valid username. +multiple_players_matched = Error: Multiple players matched {search}, please be more specific. diff --git a/sponge/pom.xml b/sponge/pom.xml index bf96924d..828d8460 100644 --- a/sponge/pom.xml +++ b/sponge/pom.xml @@ -60,4 +60,11 @@ provided + + + + ${project.basedir}/../languages/minecraft/ + + + diff --git a/sponge/src/main/java/co/aikar/commands/SpongeCommandExecutionContext.java b/sponge/src/main/java/co/aikar/commands/SpongeCommandExecutionContext.java index a9570ce1..700e6996 100644 --- a/sponge/src/main/java/co/aikar/commands/SpongeCommandExecutionContext.java +++ b/sponge/src/main/java/co/aikar/commands/SpongeCommandExecutionContext.java @@ -29,9 +29,9 @@ import java.lang.reflect.Parameter; import java.util.List; import java.util.Map; -public class SpongeCommandExecutionContext extends CommandExecutionContext { +public class SpongeCommandExecutionContext extends CommandExecutionContext { - SpongeCommandExecutionContext(RegisteredCommand cmd, Parameter param, CommandIssuer sender, List args, + SpongeCommandExecutionContext(RegisteredCommand cmd, Parameter param, SpongeCommandIssuer sender, List args, int index, Map passedArgs) { super(cmd, param, sender, args, index, passedArgs); } diff --git a/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java b/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java index 2d902f8a..41e83d6e 100644 --- a/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java +++ b/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java @@ -36,6 +36,7 @@ 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; @SuppressWarnings("WeakerAccess") @@ -49,6 +50,7 @@ public class SpongeCommandManager extends CommandManager { public SpongeCommandManager(PluginContainer plugin) { this.plugin = plugin; + this.locales.addMessageBundle("acf-minecraft", Locale.ENGLISH); this.commandTiming = Timings.of(plugin, "Commands"); this.formatters.put(MessageType.ERROR, new SpongeMessageFormatter(TextColors.RED, TextColors.YELLOW, TextColors.RED)); @@ -117,7 +119,7 @@ public class SpongeCommandManager extends CommandManager { @Override public R createCommandContext(RegisteredCommand command, Parameter parameter, CommandIssuer sender, List args, int i, Map passedArgs) { //noinspection unchecked - return (R) new SpongeCommandExecutionContext(command, parameter, sender, args, i, passedArgs); + return (R) new SpongeCommandExecutionContext(command, parameter, (SpongeCommandIssuer) sender, args, i, passedArgs); } @Override