diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index a44334815..c5e4f014e 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -10,19 +10,22 @@
-
-
-
+
+
+
+
+
+
@@ -37,6 +40,7 @@
+
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
index 6557e517a..c0c073901 100644
--- a/.idea/encodings.xml
+++ b/.idea/encodings.xml
@@ -22,8 +22,9 @@
-
+
+
diff --git a/pom.xml b/pom.xml
index d1a11023a..02ff79dab 100644
--- a/pom.xml
+++ b/pom.xml
@@ -204,6 +204,7 @@
paperbungeesponge
+ sponge10jdavelocity
diff --git a/sponge10/pom.xml b/sponge10/pom.xml
new file mode 100644
index 000000000..3bf2e4fed
--- /dev/null
+++ b/sponge10/pom.xml
@@ -0,0 +1,80 @@
+
+
+
+
+ 4.0.0
+
+
+ co.aikar
+ acf-parent
+ 0.5.1-SNAPSHOT
+ ../pom.xml
+
+
+ acf-sponge10
+ 0.5.1-SNAPSHOT
+
+ ACF (Sponge 10)
+
+
+
+ spongepowered
+ https://repo.spongepowered.org/maven/
+
+
+
+
+
+ co.aikar
+ acf-core
+ 0.5.1-SNAPSHOT
+ compile
+
+
+ org.spongepowered
+ spongeapi
+ 10.1.0-SNAPSHOT
+ provided
+
+
+
+
+
+ ${project.basedir}/../languages/minecraft/
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 8
+
+
+
+
+
diff --git a/sponge10/src/main/java/co/aikar/commands/ACFSpongeUtil.java b/sponge10/src/main/java/co/aikar/commands/ACFSpongeUtil.java
new file mode 100644
index 000000000..43fbf5098
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/ACFSpongeUtil.java
@@ -0,0 +1,96 @@
+package co.aikar.commands;
+
+import org.jetbrains.annotations.Nullable;
+import org.spongepowered.api.Sponge;
+import org.spongepowered.api.entity.living.player.Player;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@SuppressWarnings("WeakerAccess")
+public class ACFSpongeUtil {
+ public static Player findPlayerSmart(CommandIssuer issuer, String search) {
+ SpongeCommandSource requester = issuer.getIssuer();
+ if (search == null) {
+ return null;
+ }
+ String name = ACFUtil.replace(search, ":confirm", "");
+
+ List matches = matchPlayer(name);
+ List confirmList = new ArrayList<>();
+ findMatches(search, requester, matches, confirmList);
+
+
+ if (matches.size() > 1 || confirmList.size() > 1) {
+ String allMatches = matches.stream().map(Player::name).collect(Collectors.joining(", "));
+ issuer.sendError(MinecraftMessageKeys.MULTIPLE_PLAYERS_MATCH,
+ "{search}", name, "{all}", allMatches);
+ return null;
+ }
+
+ if (matches.isEmpty()) {
+ if (!issuer.getManager().isValidName(name)) {
+ issuer.sendError(MinecraftMessageKeys.IS_NOT_A_VALID_NAME, "{name}", name);
+ return null;
+ }
+ Player player = ACFUtil.getFirstElement(confirmList);
+ if (player == null) {
+ issuer.sendError(MinecraftMessageKeys.NO_PLAYER_FOUND_SERVER, "{search}", name);
+ return null;
+ } else {
+
+ issuer.sendInfo(MinecraftMessageKeys.PLAYER_IS_VANISHED_CONFIRM, "{vanished}", player.name());
+ return null;
+ }
+ }
+
+ return matches.get(0);
+ }
+
+ private static void findMatches(String search, SpongeCommandSource requester, List matches, List confirmList) {
+ // Remove vanished players from smart matching.
+ Iterator iter = matches.iterator();
+ //noinspection Duplicates
+ while (iter.hasNext()) {
+ Player player = iter.next();
+ if (requester instanceof Player && !((Player) requester).canSee(player)) {
+ if (requester.hasPermission("acf.seevanish")) {
+ if (!search.endsWith(":confirm")) {
+ confirmList.add(player);
+ iter.remove();
+ }
+ } else {
+ iter.remove();
+ }
+ }
+ }
+ }
+
+ public static List matchPlayer(String partialName) {
+ List matchedPlayers = new ArrayList<>();
+
+ for (Player iterPlayer : Sponge.server().onlinePlayers()) {
+ String iterPlayerName = iterPlayer.name();
+
+ if (partialName.equalsIgnoreCase(iterPlayerName)) {
+ // Exact match
+ matchedPlayers.clear();
+ matchedPlayers.add(iterPlayer);
+ break;
+ }
+ if (iterPlayerName.toLowerCase(java.util.Locale.ENGLISH).contains(partialName.toLowerCase(java.util.Locale.ENGLISH))) {
+ // Partial match
+ matchedPlayers.add(iterPlayer);
+ }
+ }
+
+ return matchedPlayers;
+ }
+
+ public static boolean isValidName(@Nullable String name) {
+ return name != null && !name.isEmpty() && ACFPatterns.VALID_NAME_PATTERN.matcher(name).matches();
+ }
+
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/MinecraftMessageKeys.java b/sponge10/src/main/java/co/aikar/commands/MinecraftMessageKeys.java
new file mode 100644
index 000000000..a28add753
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/MinecraftMessageKeys.java
@@ -0,0 +1,46 @@
+/*
+ * 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 co.aikar.locales.MessageKeyProvider;
+
+import java.util.Locale;
+
+public enum MinecraftMessageKeys implements MessageKeyProvider {
+ INVALID_WORLD,
+ YOU_MUST_BE_HOLDING_ITEM,
+ PLAYER_IS_VANISHED_CONFIRM,
+ USERNAME_TOO_SHORT,
+ IS_NOT_A_VALID_NAME,
+ MULTIPLE_PLAYERS_MATCH,
+ NO_PLAYER_FOUND_SERVER,
+ NO_PLAYER_FOUND
+ ;
+
+ private final MessageKey key = MessageKey.of("acf-minecraft." + this.name().toLowerCase(Locale.ENGLISH));
+ public MessageKey getMessageKey() {
+ return key;
+ }
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/SpongeCommandCompletionContext.java b/sponge10/src/main/java/co/aikar/commands/SpongeCommandCompletionContext.java
new file mode 100644
index 000000000..d728b053c
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/SpongeCommandCompletionContext.java
@@ -0,0 +1,42 @@
+/*
+ * 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.spongepowered.api.entity.living.player.Player;
+
+@SuppressWarnings("WeakerAccess")
+public class SpongeCommandCompletionContext extends CommandCompletionContext {
+
+ SpongeCommandCompletionContext(final RegisteredCommand command, final SpongeCommandIssuer issuer, final String input, final String config, final String[] args) {
+ super(command, issuer, input, config, args);
+ }
+
+ public SpongeCommandSource getSource() {
+ return this.issuer.getIssuer();
+ }
+
+ public Player getPlayer() {
+ return this.issuer.getPlayer();
+ }
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/SpongeCommandCompletions.java b/sponge10/src/main/java/co/aikar/commands/SpongeCommandCompletions.java
new file mode 100644
index 000000000..ac757bb3e
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/SpongeCommandCompletions.java
@@ -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.
+ */
+
+package co.aikar.commands;
+
+@SuppressWarnings("WeakerAccess")
+public class SpongeCommandCompletions extends CommandCompletions {
+
+ public SpongeCommandCompletions(final SpongeCommandManager manager) {
+ super(manager);
+ }
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/SpongeCommandContexts.java b/sponge10/src/main/java/co/aikar/commands/SpongeCommandContexts.java
new file mode 100644
index 000000000..062c33a4e
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/SpongeCommandContexts.java
@@ -0,0 +1,225 @@
+/*
+ * 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.commands.contexts.CommandResultSupplier;
+import co.aikar.commands.sponge.contexts.OnlinePlayer;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.format.TextColor;
+import net.kyori.adventure.text.format.TextDecoration;
+import org.jetbrains.annotations.Contract;
+import org.spongepowered.api.ResourceKey;
+import org.spongepowered.api.Sponge;
+import org.spongepowered.api.command.CommandCause;
+import org.spongepowered.api.entity.living.player.Player;
+import org.spongepowered.api.entity.living.player.User;
+import org.spongepowered.api.entity.living.player.server.ServerPlayer;
+import org.spongepowered.api.user.UserManager;
+import org.spongepowered.api.world.World;
+import org.spongepowered.api.world.server.ServerWorld;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+@SuppressWarnings("WeakerAccess")
+public class SpongeCommandContexts extends CommandContexts {
+
+ public SpongeCommandContexts(final SpongeCommandManager manager) {
+ super(manager);
+
+ registerIssuerOnlyContext(CommandResultSupplier.class, c -> new CommandResultSupplier());
+ registerContext(OnlinePlayer.class, c -> getOnlinePlayer(c.getIssuer(), c.popFirstArg(), false));
+ registerContext(co.aikar.commands.contexts.OnlinePlayer.class, c -> {
+ OnlinePlayer onlinePlayer = getOnlinePlayer(c.getIssuer(), c.popFirstArg(), false);
+ return new co.aikar.commands.contexts.OnlinePlayer(onlinePlayer.getPlayer());
+ });
+ registerContext(User.class, c -> {
+ String name = c.popFirstArg();
+ UserManager userNamanger = Sponge.server().userManager();
+ CompletableFuture> optionalUser = userNamanger.load(name);
+ // Fetch the player's profile
+ CompletableFuture completableFuture = optionalUser.thenCompose(user -> {
+ if (user.isPresent()) {
+ return CompletableFuture.completedFuture(user.get());
+ } else {
+ throw new InvalidCommandArgument(MinecraftMessageKeys.NO_PLAYER_FOUND, false, "{search}", name);
+ }
+ });
+
+ try {
+ return completableFuture.get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ registerContext(TextColor.class, c -> {
+ String arg = c.getFirstArg().toLowerCase();
+ TextColor color = NamedTextColor.NAMES.value(arg);
+ if (color == null) {
+ color = arg.startsWith("#") ? TextColor.fromHexString(arg) : TextColor.fromHexString("#" + arg);
+ if (color == null) {
+ throw new InvalidCommandArgument("Unknown TextColor syntax");
+ }
+
+ NamedTextColor closest = NamedTextColor.nearestTo(color);
+ if (color.compareTo(closest) == 0) {
+ color = closest;
+ }
+ }
+
+ String filter = c.getFlagValue("filter", (String) null);
+ if (filter != null) {
+ Set colors = Arrays.stream(
+ ACFPatterns.COLON.split(filter))
+ .map(NamedTextColor.NAMES::value)
+ .collect(Collectors.toSet());
+ if (!(color instanceof NamedTextColor) || !colors.contains(color)) {
+ throw new InvalidCommandArgument("Not a valid color");
+ }
+ }
+
+ return color;
+ });
+
+ registerContext(TextDecoration.class, c -> {
+ String first = c.popFirstArg().toLowerCase(Locale.ROOT);
+ TextDecoration decoration = TextDecoration.NAMES.value(first);
+
+ if (decoration == null) {
+ throw new InvalidCommandArgument("Unknown TextDecoration syntax");
+ }
+
+ String filter = c.getFlagValue("filter", (String) null);
+ if (filter != null) {
+ Set textDecorations = Arrays.stream(
+ ACFPatterns.COLON.split(filter))
+ .map(TextDecoration.NAMES::value)
+ .collect(Collectors.toSet());
+ if (!textDecorations.contains(decoration)) {
+ throw new InvalidCommandArgument("Not a valid TextDecoration");
+ }
+ }
+
+ return decoration;
+ });
+
+ registerIssuerAwareContext(CommandCause.class, SpongeCommandExecutionContext::getSource);
+ registerIssuerAwareContext(SpongeCommandSource.class, SpongeCommandExecutionContext::getSource);
+ registerIssuerAwareContext(ServerPlayer.class, (c) -> {
+ ServerPlayer serverPlayer = c.getIssuer().getServerPlayer();
+ if (serverPlayer == null && !c.isOptional()) {
+ throw new InvalidCommandArgument(MessageKeys.NOT_ALLOWED_ON_CONSOLE, false);
+ }
+
+ return serverPlayer;
+ });
+ registerIssuerAwareContext(Player.class, (c) -> {
+ Player player = c.getIssuer().getPlayer();
+ if (player == null && !c.isOptional()) {
+ 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(MinecraftMessageKeys.YOU_MUST_BE_HOLDING_ITEM, false);
+ }*/
+ return player;
+ });
+ registerContext(OnlinePlayer[].class, (c) -> {
+ SpongeCommandIssuer issuer = c.getIssuer();
+ final String search = c.popFirstArg();
+ boolean allowMissing = c.hasFlag("allowmissing");
+ Set players = new HashSet<>();
+ Pattern split = ACFPatterns.COMMA;
+ String splitter = c.getFlagValue("splitter", (String) null);
+ if (splitter != null) {
+ split = Pattern.compile(Pattern.quote(splitter));
+ }
+ for (String lookup : split.split(search)) {
+ OnlinePlayer player = getOnlinePlayer(issuer, lookup, allowMissing);
+ if (player != null) {
+ players.add(player);
+ }
+ }
+ if (players.isEmpty() && !c.hasFlag("allowempty")) {
+ issuer.sendError(MinecraftMessageKeys.NO_PLAYER_FOUND_SERVER,
+ "{search}", search);
+
+ throw new InvalidCommandArgument(false);
+ }
+ return players.toArray(new OnlinePlayer[players.size()]);
+ });
+ registerIssuerAwareContext(World.class, (c) -> {
+ String firstArg = c.getFirstArg();
+
+ if (firstArg == null) {
+ if (c.isOptional()) {
+ return null;
+ } else {
+ throw new InvalidCommandArgument(MinecraftMessageKeys.INVALID_WORLD);
+ }
+ }
+
+ ResourceKey worldKey = ResourceKey.of("minecraft", firstArg);
+ Optional serverWorld = Sponge.server().worldManager().world(worldKey);
+
+ Optional world = Optional.empty();
+ if (serverWorld.isPresent()) {
+ world = Optional.of( serverWorld.get() );
+ }
+
+ if (world.isPresent()) {
+ c.popFirstArg();
+ } else {
+ if (c.getSource() instanceof Player) {
+ world = java.util.Optional.of(((Player) c.getSource()).world());
+ }
+
+ if (!world.isPresent()) {
+ throw new InvalidCommandArgument(MinecraftMessageKeys.INVALID_WORLD);
+ }
+ }
+ return world.get();
+ });
+ }
+
+ @Contract("_,_,false -> !null")
+ OnlinePlayer getOnlinePlayer(SpongeCommandIssuer issuer, String lookup, boolean allowMissing) throws InvalidCommandArgument {
+ Player player = ACFSpongeUtil.findPlayerSmart(issuer, lookup);
+ if (player == null) {
+ if (allowMissing) {
+ return null;
+ }
+ throw new InvalidCommandArgument(false);
+ }
+ return new OnlinePlayer(player);
+ }
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/SpongeCommandExecutionContext.java b/sponge10/src/main/java/co/aikar/commands/SpongeCommandExecutionContext.java
new file mode 100644
index 000000000..b3e97f1ca
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/SpongeCommandExecutionContext.java
@@ -0,0 +1,45 @@
+/*
+ * 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.spongepowered.api.entity.living.player.Player;
+
+import java.util.List;
+import java.util.Map;
+
+public class SpongeCommandExecutionContext extends CommandExecutionContext {
+
+ SpongeCommandExecutionContext(RegisteredCommand cmd, CommandParameter param, SpongeCommandIssuer sender, List args,
+ int index, Map passedArgs) {
+ super(cmd, param, sender, args, index, passedArgs);
+ }
+
+ public SpongeCommandSource getSource() {
+ return this.issuer.getIssuer();
+ }
+
+ public Player getPlayer() {
+ return this.issuer.getPlayer();
+ }
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/SpongeCommandIssuer.java b/sponge10/src/main/java/co/aikar/commands/SpongeCommandIssuer.java
new file mode 100644
index 000000000..b57f16491
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/SpongeCommandIssuer.java
@@ -0,0 +1,107 @@
+/*
+ * 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 net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
+import org.jetbrains.annotations.NotNull;
+import org.spongepowered.api.entity.living.player.Player;
+import org.spongepowered.api.entity.living.player.server.ServerPlayer;
+import org.spongepowered.api.util.Identifiable;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+import java.util.UUID;
+
+public class SpongeCommandIssuer implements CommandIssuer {
+
+ private final SpongeCommandManager manager;
+ private final SpongeCommandSource source;
+
+ SpongeCommandIssuer(SpongeCommandManager manager, final SpongeCommandSource source) {
+ this.manager = manager;
+ this.source = source;
+ }
+
+ @Override
+ public boolean isPlayer() {
+ return this.source instanceof Player;
+ }
+
+ public boolean isServerPlayer() {
+ return this.source instanceof ServerPlayer;
+ }
+
+ @Override
+ public SpongeCommandSource getIssuer() {
+ return this.source;
+ }
+
+ @Override
+ public @NotNull UUID getUniqueId() {
+ if (this.source instanceof Identifiable) {
+ return ((Identifiable) source).uniqueId();
+ }
+
+ //generate a unique id based of the name (like for the console command sender)
+ return UUID.nameUUIDFromBytes(source.identifier().getBytes(StandardCharsets.UTF_8));
+ }
+
+ public Player getPlayer() {
+ return isPlayer() ? (Player) source : null;
+ }
+
+ public ServerPlayer getServerPlayer() {
+ return isServerPlayer() ? (ServerPlayer) source : null;
+ }
+
+ @Override
+ public CommandManager getManager() {
+ return manager;
+ }
+
+ @Override
+ public void sendMessageInternal(String message) {
+ try {
+ source.audience().sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(message));
+ } catch (Exception ignored) {}
+ }
+
+ @Override
+ public boolean hasPermission(final String permission) {
+ return this.source.hasPermission(permission);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ SpongeCommandIssuer that = (SpongeCommandIssuer) o;
+ return Objects.equals(source, that.source);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(source);
+ }
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/SpongeCommandManager.java b/sponge10/src/main/java/co/aikar/commands/SpongeCommandManager.java
new file mode 100644
index 000000000..333ed9181
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/SpongeCommandManager.java
@@ -0,0 +1,227 @@
+/*
+ * 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.commands.apachecommonslang.ApacheCommonsExceptionUtil;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.format.TextColor;
+import org.apache.logging.log4j.Logger;
+import org.spongepowered.api.Sponge;
+import org.spongepowered.api.command.Command;
+import org.spongepowered.api.command.CommandCause;
+import org.spongepowered.plugin.PluginContainer;
+
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+@SuppressWarnings("WeakerAccess")
+public class SpongeCommandManager extends CommandManager<
+ SpongeCommandSource,
+ SpongeCommandIssuer,
+ TextColor,
+ SpongeMessageFormatter,
+ SpongeCommandExecutionContext,
+ SpongeConditionContext
+ > {
+
+ protected final PluginContainer plugin;
+ protected Map registeredCommands = new HashMap<>();
+ protected SpongeCommandContexts contexts;
+ protected SpongeCommandCompletions completions;
+ protected SpongeLocales locales;
+
+ public SpongeCommandManager(PluginContainer plugin) {
+ this.plugin = plugin;
+ String pluginName = "acf-" + plugin.metadata().name();
+ getLocales().addMessageBundles("acf-minecraft", pluginName, pluginName.toLowerCase(Locale.ENGLISH));
+
+ this.formatters.put(MessageType.ERROR, defaultFormatter = new SpongeMessageFormatter(NamedTextColor.RED, NamedTextColor.YELLOW, NamedTextColor.RED));
+ this.formatters.put(MessageType.SYNTAX, new SpongeMessageFormatter(NamedTextColor.YELLOW, NamedTextColor.GREEN, NamedTextColor.WHITE));
+ this.formatters.put(MessageType.INFO, new SpongeMessageFormatter(NamedTextColor.BLUE, NamedTextColor.DARK_GREEN, NamedTextColor.GREEN));
+ this.formatters.put(MessageType.HELP, new SpongeMessageFormatter(NamedTextColor.AQUA, NamedTextColor.GREEN, NamedTextColor.YELLOW));
+ getLocales(); // auto load locales
+
+ this.validNamePredicate = ACFSpongeUtil::isValidName;
+
+ //TODO more default dependencies for sponge
+ registerDependency(plugin.getClass(), plugin);
+ }
+
+ public PluginContainer getPlugin() {
+ return plugin;
+ }
+
+ @Override
+ public boolean isCommandIssuer(Class> type) {
+ return CommandCause.class.isAssignableFrom(type);
+ }
+
+ @Override
+ public synchronized CommandContexts getCommandContexts() {
+ if (this.contexts == null) {
+ this.contexts = new SpongeCommandContexts(this);
+ }
+ return contexts;
+ }
+
+ @Override
+ public synchronized CommandCompletions getCommandCompletions() {
+ if (this.completions == null) {
+ this.completions = new SpongeCommandCompletions(this);
+ }
+ 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();
+ }
+
+ @Override
+ public void registerCommand(BaseCommand command) {
+ command.onRegister(this);
+
+ for (Map.Entry entry : command.registeredCommands.entrySet()) {
+ String commandName = entry.getKey().toLowerCase(Locale.ENGLISH);
+ SpongeRootCommand spongeCommand = (SpongeRootCommand) entry.getValue();
+ if (!spongeCommand.isRegistered) {
+ Sponge.server().commandManager().registrar(Command.Raw.class).get()
+ .register(plugin, spongeCommand, commandName);
+ }
+ spongeCommand.isRegistered = true;
+ registeredCommands.put(commandName, spongeCommand);
+ }
+ }
+
+ @Override
+ public RootCommand createRootCommand(String cmd) {
+ return new SpongeRootCommand(this, cmd);
+ }
+
+ @Override
+ public Collection getRegisteredRootCommands() {
+ return Collections.unmodifiableCollection(registeredCommands.values());
+ }
+
+ @Override
+ public SpongeCommandIssuer getCommandIssuer(Object issuer) {
+ if (issuer instanceof SpongeCommandSource) {
+ return new SpongeCommandIssuer(this, (SpongeCommandSource) issuer);
+ }
+
+ if (issuer instanceof CommandCause) {
+ return new SpongeCommandIssuer(this, new SpongeCommandSource((CommandCause) issuer));
+ }
+
+ throw new IllegalArgumentException(issuer.getClass().getName() + " is not a Command Issuer.");
+ }
+
+ @Override
+ public SpongeCommandExecutionContext createCommandContext(RegisteredCommand command, CommandParameter parameter, CommandIssuer sender, List args, int i, Map passedArgs) {
+ return new SpongeCommandExecutionContext(command, parameter, (SpongeCommandIssuer) sender, args, i, passedArgs);
+ }
+
+ @Override
+ public CommandCompletionContext createCompletionContext(RegisteredCommand command, CommandIssuer sender, String input, String config, String[] args) {
+ return new SpongeCommandCompletionContext(command, (SpongeCommandIssuer) sender, input, config, args);
+ }
+
+ @Override
+ public RegisteredCommand createRegisteredCommand(BaseCommand command, String cmdName, Method method, String prefSubCommand) {
+ return new SpongeRegisteredCommand(command, cmdName, method, prefSubCommand);
+ }
+
+ @Override
+ public void log(final LogLevel level, final String message, final Throwable throwable) {
+ Logger logger = this.plugin.logger();
+ switch(level) {
+ case INFO:
+ logger.info(LogLevel.LOG_PREFIX + message);
+ if (throwable != null) {
+ for (String line : ACFPatterns.NEWLINE.split(ApacheCommonsExceptionUtil.getFullStackTrace(throwable))) {
+ logger.info(LogLevel.LOG_PREFIX + line);
+ }
+ }
+ return;
+ case ERROR:
+ logger.error(LogLevel.LOG_PREFIX + message);
+ if (throwable != null) {
+ for (String line : ACFPatterns.NEWLINE.split(ApacheCommonsExceptionUtil.getFullStackTrace(throwable))) {
+ logger.error(LogLevel.LOG_PREFIX + line);
+ }
+ }
+ }
+ }
+
+ @Override
+ CommandOperationContext createCommandOperationContext(BaseCommand command, CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) {
+ return new SpongeCommandOperationContext(
+ this,
+ issuer,
+ command,
+ commandLabel,
+ args,
+ isAsync
+ );
+ }
+
+ @Override
+ public SpongeConditionContext createConditionContext(CommandIssuer issuer, String config) {
+ return new SpongeConditionContext((SpongeCommandIssuer) issuer, config);
+ }
+
+ @Override
+ public Locale getIssuerLocale(CommandIssuer issuer) {
+ if (usingPerIssuerLocale() && issuer != null) {
+ SpongeCommandIssuer spongeIssuer = (SpongeCommandIssuer) issuer;
+ return spongeIssuer.getIssuer().locale();
+ }
+
+ return getLocales().getDefaultLocale();
+ }
+
+ @Override
+ public Locale setIssuerLocale(SpongeCommandSource issuer, Locale locale) {
+ throw new UnsupportedOperationException("You can't set a locale as they are resolved at command execution.");
+ }
+
+ @Override
+ public String getCommandPrefix(CommandIssuer issuer) {
+ return issuer.isPlayer() ? "/" : "";
+ }
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/SpongeCommandOperationContext.java b/sponge10/src/main/java/co/aikar/commands/SpongeCommandOperationContext.java
new file mode 100644
index 000000000..aefe6848a
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/SpongeCommandOperationContext.java
@@ -0,0 +1,18 @@
+package co.aikar.commands;
+
+import org.spongepowered.api.command.CommandResult;
+
+public class SpongeCommandOperationContext extends CommandOperationContext {
+ private CommandResult result = CommandResult.success();
+ SpongeCommandOperationContext(CommandManager manager, CommandIssuer issuer, BaseCommand command, String commandLabel, String[] args, boolean isAsync) {
+ super(manager, issuer, command, commandLabel, args, isAsync);
+ }
+
+ public CommandResult getResult() {
+ return result;
+ }
+
+ public void setResult(CommandResult result) {
+ this.result = result;
+ }
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/SpongeCommandSource.java b/sponge10/src/main/java/co/aikar/commands/SpongeCommandSource.java
new file mode 100644
index 000000000..de62c90d1
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/SpongeCommandSource.java
@@ -0,0 +1,96 @@
+package co.aikar.commands;
+
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.identity.Identified;
+import net.kyori.adventure.identity.Identity;
+import net.kyori.adventure.text.Component;
+import org.spongepowered.api.block.BlockSnapshot;
+import org.spongepowered.api.command.CommandCause;
+import org.spongepowered.api.command.parameter.CommandContext;
+import org.spongepowered.api.event.Cause;
+import org.spongepowered.api.service.permission.Subject;
+import org.spongepowered.api.util.locale.LocaleSource;
+import org.spongepowered.api.util.locale.Locales;
+import org.spongepowered.api.world.server.ServerLocation;
+import org.spongepowered.math.vector.Vector3d;
+
+import java.util.Locale;
+import java.util.Optional;
+
+public class SpongeCommandSource implements LocaleSource, CommandCause {
+ private CommandCause commandCause;
+ private LocaleSource localeSource;
+
+ public SpongeCommandSource(CommandContext commandContext) {
+ commandCause = commandContext.cause();
+ Subject subject = commandContext.subject();
+ if (subject instanceof LocaleSource) {
+ localeSource = (LocaleSource) subject;
+ } else {
+ localeSource = null;
+ }
+ }
+
+ public SpongeCommandSource(T obj) {
+ if (obj instanceof CommandCause) {
+ commandCause = (CommandCause) obj;
+ }
+
+ if (obj instanceof LocaleSource) {
+ localeSource = (LocaleSource) obj;
+ }
+ }
+
+ @Override
+ public Locale locale() {
+ if (localeSource == null) {
+ return Locales.DEFAULT;
+ }
+ return localeSource.locale();
+ }
+
+ @Override
+ public Cause cause() {
+ return commandCause.cause();
+ }
+
+ @Override
+ public Subject subject() {
+ return commandCause.subject();
+ }
+
+ @Override
+ public Audience audience() {
+ return commandCause.audience();
+ }
+
+ @Override
+ public Optional location() {
+ return commandCause.location();
+ }
+
+ @Override
+ public Optional rotation() {
+ return commandCause.rotation();
+ }
+
+ @Override
+ public Optional targetBlock() {
+ return commandCause.targetBlock();
+ }
+
+ @Override
+ public void sendMessage(Component message) {
+ commandCause.sendMessage(message);
+ }
+
+ @Override
+ public void sendMessage(Identified source, Component message) {
+ commandCause.sendMessage(source, message);
+ }
+
+ @Override
+ public void sendMessage(Identity source, Component message) {
+ commandCause.sendMessage(source, message);
+ }
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/SpongeConditionContext.java b/sponge10/src/main/java/co/aikar/commands/SpongeConditionContext.java
new file mode 100644
index 000000000..7548625a6
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/SpongeConditionContext.java
@@ -0,0 +1,18 @@
+package co.aikar.commands;
+
+import org.spongepowered.api.entity.living.player.Player;
+
+public class SpongeConditionContext extends ConditionContext {
+ SpongeConditionContext(SpongeCommandIssuer issuer, String config) {
+ super(issuer, config);
+ }
+
+
+ public SpongeCommandSource getSource() {
+ return getIssuer().getIssuer();
+ }
+
+ public Player getPlayer() {
+ return getIssuer().getPlayer();
+ }
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/SpongeLocales.java b/sponge10/src/main/java/co/aikar/commands/SpongeLocales.java
new file mode 100644
index 000000000..030cddddd
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/SpongeLocales.java
@@ -0,0 +1,20 @@
+package co.aikar.commands;
+
+import java.util.Locale;
+
+public class SpongeLocales extends Locales{
+ private final SpongeCommandManager manager;
+
+ public SpongeLocales(SpongeCommandManager manager) {
+ super(manager);
+ this.manager = manager;
+ this.addBundleClassLoader(this.manager.getPlugin().getClass().getClassLoader());
+ }
+
+ @Override
+ public void loadLanguages() {
+ super.loadLanguages();
+ String pluginName = "acf-" + manager.plugin.metadata().name();
+ addMessageBundles("acf-minecraft", pluginName, pluginName.toLowerCase(Locale.ENGLISH));
+ }
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/SpongeMessageFormatter.java b/sponge10/src/main/java/co/aikar/commands/SpongeMessageFormatter.java
new file mode 100644
index 000000000..0bf4baa90
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/SpongeMessageFormatter.java
@@ -0,0 +1,16 @@
+package co.aikar.commands;
+
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.TextColor;
+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
+
+public class SpongeMessageFormatter extends MessageFormatter {
+
+ public SpongeMessageFormatter(TextColor... colors) {
+ super(colors);
+ }
+
+ public String format(TextColor color, String message) {
+ return LegacyComponentSerializer.legacyAmpersand().serialize(Component.text(message).color(color));
+ }
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/SpongeRegisteredCommand.java b/sponge10/src/main/java/co/aikar/commands/SpongeRegisteredCommand.java
new file mode 100644
index 000000000..b054af314
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/SpongeRegisteredCommand.java
@@ -0,0 +1,33 @@
+/*
+ * 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.lang.reflect.Method;
+
+public class SpongeRegisteredCommand extends RegisteredCommand {
+ SpongeRegisteredCommand(BaseCommand scope, String command, Method method, String prefSubCommand) {
+ super(scope, command, method, prefSubCommand);
+ }
+
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/SpongeRootCommand.java b/sponge10/src/main/java/co/aikar/commands/SpongeRootCommand.java
new file mode 100644
index 000000000..7a6302b24
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/SpongeRootCommand.java
@@ -0,0 +1,165 @@
+/*
+ * 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.HashMultimap;
+import com.google.common.collect.SetMultimap;
+import net.kyori.adventure.text.Component;
+import org.spongepowered.api.command.Command;
+import org.spongepowered.api.command.CommandCause;
+import org.spongepowered.api.command.CommandCompletion;
+import org.spongepowered.api.command.CommandResult;
+import org.spongepowered.api.command.exception.CommandException;
+import org.spongepowered.api.command.parameter.ArgumentReader;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static net.kyori.adventure.text.Component.text;
+
+public class SpongeRootCommand implements Command.Raw, RootCommand {
+
+ private final SpongeCommandManager manager;
+ private final String name;
+ private BaseCommand defCommand;
+ private SetMultimap subCommands = HashMultimap.create();
+ private List children = new ArrayList<>();
+ boolean isRegistered = false;
+
+ SpongeRootCommand(SpongeCommandManager manager, String name) {
+ this.manager = manager;
+ this.name = name;
+ }
+
+ @Override
+ public String getCommandName() {
+ return name;
+ }
+
+ private CommandResult executeSponge(CommandIssuer sender, String commandLabel, String[] args) {
+ BaseCommand cmd = execute(sender, commandLabel, args);
+ SpongeCommandOperationContext lastContext = (SpongeCommandOperationContext) cmd.getLastCommandOperationContext();
+ return lastContext != null ? lastContext.getResult() : CommandResult.success();
+ }
+
+ public void addChild(BaseCommand command) {
+ if (this.defCommand == null || !command.subCommands.get(BaseCommand.DEFAULT).isEmpty()) {
+ this.defCommand = command;
+ }
+ addChildShared(this.children, this.subCommands, command);
+ }
+
+ @Override
+ public BaseCommand getDefCommand() {
+ return defCommand;
+ }
+
+ @Override
+ public CommandManager getManager() {
+ return manager;
+ }
+
+ @Override
+ public SetMultimap getSubCommands() {
+ return subCommands;
+ }
+
+ @Override
+ public List getChildren() {
+ return children;
+ }
+
+ @Override
+ public CommandResult process(CommandCause cause, ArgumentReader.Mutable arguments) throws CommandException {
+ String[] args = argToStrlist(arguments);
+ return this.executeSponge(manager.getCommandIssuer(cause), this.name, args);
+ }
+
+ @Override
+ public List complete(CommandCause cause, ArgumentReader.Mutable arguments) throws CommandException {
+ String[] args = argToStrlist(arguments);
+ return getTabCompletions(manager.getCommandIssuer(cause), this.name, args).stream().map(it -> new CommandCompletion() {
+ @Override
+ public String completion() {
+ return it;
+ }
+
+ @Override
+ public Optional tooltip() {
+ return Optional.empty();
+ }
+ }).collect(Collectors.toList());
+ }
+
+ @Override
+ public List getTabCompletions(CommandIssuer sender, String alias, String[] args, boolean commandsOnly, boolean isAsync) {
+ Set completions = new HashSet<>();
+ getChildren().forEach(child -> {
+ if (!commandsOnly) {
+ completions.addAll(child.tabComplete(sender, this, args, isAsync));
+ }
+ completions.addAll(child.getCommandsForCompletion(sender, args));
+ });
+
+ return completions.stream()
+ .filter(it -> Arrays
+ .stream(args)
+ .noneMatch(it::equals))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public boolean canExecute(CommandCause cause) {
+ return this.hasAnyPermission(manager.getCommandIssuer(cause));
+ }
+
+ @Override
+ public Optional shortDescription(CommandCause cause) {
+ String description = getDescription();
+ return description != null ? Optional.of(text(description)) : Optional.empty();
+ }
+
+ @Override
+ public Optional extendedDescription(CommandCause cause) {
+ return Optional.empty();
+ }
+
+ @Override
+ public Component usage(CommandCause cause) {
+ String usage = getUsage();
+ return usage != null ? text(usage) : text("");
+ }
+
+ private String[] argToStrlist(ArgumentReader.Mutable arguments) {
+ return Arrays.stream(arguments.input().split(" "))
+ .filter(string -> (!string.isEmpty()))
+ .toArray(String[]::new);
+ }
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/contexts/CommandResultSupplier.java b/sponge10/src/main/java/co/aikar/commands/contexts/CommandResultSupplier.java
new file mode 100644
index 000000000..30b155e76
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/contexts/CommandResultSupplier.java
@@ -0,0 +1,19 @@
+package co.aikar.commands.contexts;
+
+import co.aikar.commands.CommandManager;
+import co.aikar.commands.SpongeCommandOperationContext;
+import org.spongepowered.api.command.CommandResult;
+
+import java.util.function.Consumer;
+
+public class CommandResultSupplier implements Consumer {
+
+ public CommandResultSupplier() {
+ }
+
+ @Override
+ public void accept(CommandResult commandResult) {
+ SpongeCommandOperationContext context = (SpongeCommandOperationContext) CommandManager.getCurrentCommandOperationContext();
+ context.setResult(commandResult);
+ }
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/contexts/OnlinePlayer.java b/sponge10/src/main/java/co/aikar/commands/contexts/OnlinePlayer.java
new file mode 100644
index 000000000..f36053984
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/contexts/OnlinePlayer.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016-2019 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.contexts;
+
+import org.spongepowered.api.entity.living.player.Player;
+
+/**
+ * @deprecated Use {@link co.aikar.commands.sponge.contexts.OnlinePlayer instead}
+ */
+@Deprecated
+public class OnlinePlayer extends co.aikar.commands.sponge.contexts.OnlinePlayer {
+ public OnlinePlayer(Player player) {
+ super(player);
+ }
+}
diff --git a/sponge10/src/main/java/co/aikar/commands/sponge/contexts/OnlinePlayer.java b/sponge10/src/main/java/co/aikar/commands/sponge/contexts/OnlinePlayer.java
new file mode 100644
index 000000000..7cb5ee497
--- /dev/null
+++ b/sponge10/src/main/java/co/aikar/commands/sponge/contexts/OnlinePlayer.java
@@ -0,0 +1,58 @@
+/*
+ * 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.sponge.contexts;
+
+import org.spongepowered.api.entity.living.player.Player;
+
+import java.util.Objects;
+
+public class OnlinePlayer {
+ public final Player player;
+
+ public OnlinePlayer(Player player) {
+ this.player = player;
+ }
+
+ public Player getPlayer() {
+ return this.player;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ OnlinePlayer that = (OnlinePlayer) o;
+ return Objects.equals(player, that.player);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(player);
+ }
+
+ @Override
+ public String toString() {
+ return "OnlinePlayer{player=" + player + '}';
+ }
+}