diff --git a/bukkit/src/main/java/co/aikar/commands/BukkitCommandIssuer.java b/bukkit/src/main/java/co/aikar/commands/BukkitCommandIssuer.java
index 6af02580..5e153183 100644
--- a/bukkit/src/main/java/co/aikar/commands/BukkitCommandIssuer.java
+++ b/bukkit/src/main/java/co/aikar/commands/BukkitCommandIssuer.java
@@ -23,6 +23,7 @@
package co.aikar.commands;
+import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -45,8 +46,15 @@ public class BukkitCommandIssuer implements CommandIssuer {
}
@Override
- public void sendMessage(String message) {
- sender.sendMessage(ACFBukkitUtil.color(message));
+ public void sendMessage(MessageType type, String message) {
+ switch (type) {
+ case ERROR:
+ case SYNTAX:
+ sender.sendMessage(ChatColor.RED + ACFBukkitUtil.color(message));
+ break;
+ default:
+ sender.sendMessage(ChatColor.YELLOW + ACFBukkitUtil.color(message));
+ }
}
@Override
diff --git a/bungee/src/main/java/co/aikar/commands/BungeeCommandIssuer.java b/bungee/src/main/java/co/aikar/commands/BungeeCommandIssuer.java
index 4d9dcb8d..1f7bd33f 100644
--- a/bungee/src/main/java/co/aikar/commands/BungeeCommandIssuer.java
+++ b/bungee/src/main/java/co/aikar/commands/BungeeCommandIssuer.java
@@ -23,6 +23,7 @@
package co.aikar.commands;
+import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.ProxiedPlayer;
@@ -46,8 +47,15 @@ public class BungeeCommandIssuer implements CommandIssuer{
}
@Override
- public void sendMessage(String message) {
- sender.sendMessage(new TextComponent(ACFBungeeUtil.color(message)));
+ public void sendMessage(MessageType type, String message) {
+ switch (type) {
+ case ERROR:
+ case SYNTAX:
+ sender.sendMessage(new TextComponent(ChatColor.RED + ACFBungeeUtil.color(message)));
+ break;
+ default:
+ sender.sendMessage(new TextComponent(ChatColor.YELLOW + ACFBungeeUtil.color(message)));
+ }
}
@Override
diff --git a/core/acf-core.iml b/core/acf-core.iml
index 6dbf4a62..143048f3 100644
--- a/core/acf-core.iml
+++ b/core/acf-core.iml
@@ -17,6 +17,6 @@
-
+
\ No newline at end of file
diff --git a/core/pom.xml b/core/pom.xml
index 18696a9e..0c241d05 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -46,6 +46,11 @@
15.0
provided
+
+ org.jetbrains
+ annotations
+ 15.0
+
diff --git a/core/src/main/java/co/aikar/commands/BaseCommand.java b/core/src/main/java/co/aikar/commands/BaseCommand.java
index 6dc081cd..fa7e32d0 100644
--- a/core/src/main/java/co/aikar/commands/BaseCommand.java
+++ b/core/src/main/java/co/aikar/commands/BaseCommand.java
@@ -315,7 +315,7 @@ public abstract class BaseCommand {
public void execute(CommandIssuer issuer, String commandLabel, String[] args) {
if (!this.hasPermission(issuer)) {
- issuer.sendMessage(permissionMessage);
+ issuer.sendMessage(MessageType.ERROR, permissionMessage);
return;
}
commandLabel = commandLabel.toLowerCase();
@@ -393,7 +393,7 @@ public abstract class BaseCommand {
List sargs = Lists.newArrayList(args);
cmd.invoke(issuer, sargs);
} else {
- issuer.sendMessage(cmd.scope.permissionMessage);
+ issuer.sendMessage(MessageType.ERROR, cmd.scope.permissionMessage);
}
}
@@ -489,7 +489,7 @@ public abstract class BaseCommand {
help(manager.getCommandIssuer(issuer), args);
}
public void help(CommandIssuer issuer, String[] args) {
- issuer.sendMessage("&cUnknown Command, please type &f/help");
+ issuer.sendMessage(MessageType.ERROR, "&cUnknown Command, please type &f/help");
}
public void doHelp(Object issuer, String... args) {
doHelp(manager.getCommandIssuer(issuer), args);
@@ -499,7 +499,7 @@ public abstract class BaseCommand {
}
public void showSyntax(CommandIssuer issuer, RegisteredCommand> cmd) {
- issuer.sendMessage("&cUsage: /" + cmd.command + " " + cmd.syntaxText);
+ issuer.sendMessage(MessageType.SYNTAX, "&cUsage: /" + cmd.command + " " + cmd.syntaxText);
}
public boolean hasPermission(Object issuer) {
diff --git a/core/src/main/java/co/aikar/commands/CommandContexts.java b/core/src/main/java/co/aikar/commands/CommandContexts.java
index 1c390510..8f34b2a5 100644
--- a/core/src/main/java/co/aikar/commands/CommandContexts.java
+++ b/core/src/main/java/co/aikar/commands/CommandContexts.java
@@ -38,7 +38,7 @@ import java.util.Map;
@SuppressWarnings("WeakerAccess")
public class CommandContexts > {
protected final Map, ContextResolver, R>> contextMap = Maps.newHashMap();
- private final CommandManager manager;
+ protected final CommandManager manager;
CommandContexts(CommandManager manager) {
this.manager = manager;
diff --git a/core/src/main/java/co/aikar/commands/CommandIssuer.java b/core/src/main/java/co/aikar/commands/CommandIssuer.java
index cc15d3d7..646b85d4 100644
--- a/core/src/main/java/co/aikar/commands/CommandIssuer.java
+++ b/core/src/main/java/co/aikar/commands/CommandIssuer.java
@@ -41,7 +41,9 @@ public interface CommandIssuer {
* Send the Command Issuer a message
* @param message
*/
- void sendMessage(String message);
+ default void sendMessage(String message) {
+ sendMessage(MessageType.ERROR, message);
+ }
/**
* Has permission node
@@ -49,4 +51,6 @@ public interface CommandIssuer {
* @return
*/
boolean hasPermission(String permission);
+
+ void sendMessage(MessageType type, String message);
}
diff --git a/core/src/main/java/co/aikar/commands/CommandManager.java b/core/src/main/java/co/aikar/commands/CommandManager.java
index 29a09f97..fd527b6d 100644
--- a/core/src/main/java/co/aikar/commands/CommandManager.java
+++ b/core/src/main/java/co/aikar/commands/CommandManager.java
@@ -27,6 +27,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")
@@ -34,6 +35,7 @@ abstract class CommandManager {
protected Map rootCommands = new HashMap<>();
protected CommandReplacements replacements = new CommandReplacements(this);
+ protected Locales locales = new Locales(this);
protected ExceptionHandler defaultExceptionHandler = null;
/**
@@ -48,6 +50,28 @@ abstract class CommandManager {
*/
public abstract CommandCompletions> getCommandCompletions();
+ /**
+ * Registers a command with ACF
+ *
+ * @param command The command to register
+ * @return boolean
+ */
+ public abstract void registerCommand(BaseCommand command);
+ public abstract boolean hasRegisteredCommands();
+ public abstract boolean isCommandIssuer(Class> type);
+
+ public abstract CommandIssuer getCommandIssuer(Object issuer);
+
+ public abstract RootCommand createRootCommand(String cmd);
+
+ 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);
+
+ public abstract void log(final LogLevel level, final String message);
+
+ public abstract void log(final LogLevel level, final String message, final Throwable throwable);
+
/**
* Lets you add custom string replacements that can be applied to annotation values,
* to reduce duplication/repetition of common values such as permission nodes and command prefixes.
@@ -62,37 +86,25 @@ abstract class CommandManager {
}
/**
- * Registers a command with ACF
- *
- * @param command The command to register
- * @return boolean
+ * Returns a Locales Manager to add and modify language tables for your commands.
+ * @return
*/
- public abstract void registerCommand(BaseCommand command);
- public abstract boolean hasRegisteredCommands();
- public abstract boolean isCommandIssuer(Class> type);
+ Locales getLocales() {
+ return locales;
+ }
public boolean hasPermission(CommandIssuer issuer, String permission) {
return permission == null || permission.isEmpty() || issuer.hasPermission(permission);
}
- public abstract CommandIssuer getCommandIssuer(Object issuer);
-
- public abstract RootCommand createRootCommand(String cmd);
-
public synchronized RootCommand obtainRootCommand(String cmd) {
return rootCommands.computeIfAbsent(cmd.toLowerCase(), this::createRootCommand);
}
- 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);
-
public RegisteredCommand createRegisteredCommand(BaseCommand command, String cmdName, Method method, String prefSubCommand) {
return new RegisteredCommand(command, cmdName, method, prefSubCommand);
}
- public abstract void log(final LogLevel level, final String message);
- public abstract void log(final LogLevel level, final String message, final Throwable throwable);
/**
* Sets the default {@link ExceptionHandler} that is called when an exception occurs while executing a command, if the command doesn't have it's own exception handler registered.
@@ -121,4 +133,19 @@ abstract class CommandManager {
}
return result;
}
+
+ protected void sendMessage(Object issuerArg, MessageType type, MessageKey key, String... replacements) {
+ CommandIssuer issuer = issuerArg instanceof CommandIssuer ? (CommandIssuer) issuerArg : getCommandIssuer(issuerArg);
+ Locale locale = getIssuerLocale(issuer);
+ String message = getLocales().getMessage(locale, key);
+ if (replacements.length > 0) {
+ message = ACFUtil.replaceStrings(message, replacements);
+ }
+ // TODO: Colors?
+ issuer.sendMessage(type, message);
+ }
+
+ public Locale getIssuerLocale(CommandIssuer issuer) {
+ return getLocales().getDefaultLocale();
+ }
}
diff --git a/core/src/main/java/co/aikar/commands/LanguageTable.java b/core/src/main/java/co/aikar/commands/LanguageTable.java
new file mode 100644
index 00000000..6166f4b6
--- /dev/null
+++ b/core/src/main/java/co/aikar/commands/LanguageTable.java
@@ -0,0 +1,52 @@
+/*
+ * 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 com.google.common.collect.Maps;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Locale;
+import java.util.Map;
+
+class LanguageTable {
+
+ private final Locale locale;
+ private final Map messages = Maps.newHashMap();
+
+ LanguageTable(Locale locale) {
+ this.locale = locale;
+ }
+
+ public String addMessage(MessageKey key, String message) {
+ return messages.put(key, message);
+ }
+
+ public String getMessage(MessageKey key) {
+ return messages.get(key);
+ }
+
+ public void addMessages(@NotNull Map messages) {
+ this.messages.putAll(messages);
+ }
+}
diff --git a/core/src/main/java/co/aikar/commands/Locales.java b/core/src/main/java/co/aikar/commands/Locales.java
new file mode 100644
index 00000000..0d6ee7bb
--- /dev/null
+++ b/core/src/main/java/co/aikar/commands/Locales.java
@@ -0,0 +1,97 @@
+/*
+ * 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 com.google.common.collect.Maps;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * This isn't public yet, still WIP - API will break
+ * @deprecated
+ */
+@SuppressWarnings("WeakerAccess")
+@Deprecated
+public class Locales {
+
+ private Locale defaultLocale = Locale.ENGLISH;
+ private final CommandManager manager;
+ private final Map tables = Maps.newHashMap();
+
+ Locales(CommandManager manager) {
+ this.manager = manager;
+ this.initializeSystemMessages();
+ }
+
+ private void initializeSystemMessages() {
+ LanguageTable table = getTable(Locale.ENGLISH);
+ //table.addMessage(MessageKey.FOO, "bar");
+ }
+
+ /**
+ * Changes the default locale to use if the specified language key is missing for the desired locale
+ * @param locale
+ * @return Previous default locale
+ */
+ public Locale setDefaultLocale(Locale locale) {
+ Locale prev = this.defaultLocale;
+ this.defaultLocale = locale;
+ return prev;
+ }
+
+ public Locale getDefaultLocale() {
+ return defaultLocale;
+ }
+
+ public void addMessages(Locale locale, @NotNull Map messages) {
+ getTable(locale).addMessages(messages);
+ }
+
+ public String addMessage(Locale locale, MessageKey key, String message) {
+ return getTable(locale).addMessage(key, message);
+ }
+
+ public String getMessage(Locale locale, MessageKey key) {
+ String message = getTable(locale).getMessage(key);
+ if (message == null && !Objects.equals(locale, defaultLocale)) {
+ message = getTable(defaultLocale).getMessage(key);
+ }
+ if (message == null && !Objects.equals(Locale.ENGLISH, defaultLocale) && !Objects.equals(Locale.ENGLISH, locale)) {
+ message = getTable(Locale.ENGLISH).getMessage(key);
+ }
+ if (message == null) {
+ manager.log(LogLevel.ERROR, "Missing Language Key: " + key);
+ message = "";
+ }
+ return message;
+ }
+
+ public LanguageTable getTable(Locale locale) {
+ return tables.computeIfAbsent(locale, (l) -> new LanguageTable(locale));
+ }
+
+}
diff --git a/core/src/main/java/co/aikar/commands/MessageKey.java b/core/src/main/java/co/aikar/commands/MessageKey.java
new file mode 100644
index 00000000..84df0719
--- /dev/null
+++ b/core/src/main/java/co/aikar/commands/MessageKey.java
@@ -0,0 +1,56 @@
+/*
+ * 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 java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class MessageKey {
+ private static final AtomicInteger counter = new AtomicInteger();
+ private static final Map keyMap = new ConcurrentHashMap<>();
+ private final int id = counter.getAndIncrement();
+ private final String key;
+
+ private MessageKey(String key) {
+ this.key = key;
+ }
+
+ public static MessageKey of(String key) {
+ return keyMap.computeIfAbsent(key.toLowerCase(), MessageKey::new);
+ }
+
+ public int hashCode() {
+ return id;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return (this == o);
+ }
+
+ public String getKey() {
+ return key;
+ }
+}
diff --git a/core/src/main/java/co/aikar/commands/MessageType.java b/core/src/main/java/co/aikar/commands/MessageType.java
new file mode 100644
index 00000000..490f4878
--- /dev/null
+++ b/core/src/main/java/co/aikar/commands/MessageType.java
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+public enum MessageType {
+ INFO, SYNTAX, ERROR
+}
diff --git a/core/src/main/java/co/aikar/commands/RegisteredCommand.java b/core/src/main/java/co/aikar/commands/RegisteredCommand.java
index 2b4e69de..bfeaff70 100644
--- a/core/src/main/java/co/aikar/commands/RegisteredCommand.java
+++ b/core/src/main/java/co/aikar/commands/RegisteredCommand.java
@@ -154,7 +154,7 @@ public class RegisteredCommand {
- sender.sendMessage("An error occured. This problem has been logged. Sorry for the inconvienence.");
+ sender.sendMessage(MessageType.ERROR, "An error occured. This problem has been logged. Sorry for the inconvienence.");
return true; // mark as handeled, default message will not be send to sender
}));
commandManager.registerCommand(new SomeCommand_ExtraSubs());
diff --git a/sponge/src/main/java/co/aikar/commands/SpongeCommandIssuer.java b/sponge/src/main/java/co/aikar/commands/SpongeCommandIssuer.java
index e1eb467c..ca8b9b38 100644
--- a/sponge/src/main/java/co/aikar/commands/SpongeCommandIssuer.java
+++ b/sponge/src/main/java/co/aikar/commands/SpongeCommandIssuer.java
@@ -25,6 +25,9 @@ package co.aikar.commands;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.entity.living.player.Player;
+import org.spongepowered.api.text.Text;
+import org.spongepowered.api.text.format.TextColor;
+import org.spongepowered.api.text.format.TextColors;
import org.spongepowered.api.text.serializer.TextSerializers;
public class SpongeCommandIssuer implements CommandIssuer {
@@ -47,8 +50,15 @@ public class SpongeCommandIssuer implements CommandIssuer {
}
@Override
- public void sendMessage(final String message) {
- this.source.sendMessage(TextSerializers.FORMATTING_CODE.deserialize(message));
+ public void sendMessage(MessageType type, String message) {
+ switch (type) {
+ case ERROR:
+ case SYNTAX:
+ this.source.sendMessage(Text.of(TextColors.RED, TextSerializers.LEGACY_FORMATTING_CODE.stripCodes(message)));
+ break;
+ default:
+ this.source.sendMessage(Text.of(TextColors.YELLOW, TextSerializers.LEGACY_FORMATTING_CODE.stripCodes(message)));
+ }
}
@Override