mirror of
https://github.com/aikar/commands.git
synced 2026-05-31 06:11:55 +00:00
Added Velocity support (#182)
This PR adds support for the upcoming proxy Velocity. https://www.velocitypowered.org/ A few note worthy issues: - Velocity does not provide a static method for its ProxyServer instance, so the instance has to be passed in by the plugin with `new VelocityCommandManager(proxy, this)` - Velocity does not provide a way to get the Plugin logger with the provided Plugin or PluginContainer, so it must be fetched using `Logger logger = LoggerFactory.getLogger(plugin.getClass());` UNTESTED - Velocity uses an annotation to signify the main class, meaning it can't be passed around like the Bukkit and Bungeecord JavaPlugin and Plugin. An Object has to be passed in which the PluginContainer is extracted from it using the Proxy's PluginManager `proxy.getPluginManager().getPlugin(plugin.getClass().getAnnotation(Plugin.class).id()).get();` Any and all feedback is welcomed and appreciated. *This implementation is essentially a copy/paste/rename. All code belongs to the original author, except the `ACFVelocityUtil#matchPlayer` which was originally written by md_5 and modified to use Velocity classes.*
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>acf-parent</artifactId>
|
||||
<groupId>co.aikar</groupId>
|
||||
<version>0.5.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>acf-velocity</artifactId>
|
||||
<version><!--VERSION-->0.5.0-SNAPSHOT<!--VERSION--></version>
|
||||
|
||||
<name>ACF (Velocity)</name>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>velocity-repo</id>
|
||||
<url>https://repo.velocitypowered.com/snapshots/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>co.aikar</groupId>
|
||||
<artifactId>acf-core</artifactId>
|
||||
<version><!--VERSION-->0.5.0-SNAPSHOT<!--VERSION--></version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.velocitypowered</groupId>
|
||||
<artifactId>velocity-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${project.basedir}/../languages/minecraft/</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,45 @@
|
||||
package co.aikar.commands;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.connection.DisconnectEvent;
|
||||
import com.velocitypowered.api.event.connection.PostLoginEvent;
|
||||
import com.velocitypowered.api.event.player.PlayerSettingsChangedEvent;
|
||||
import com.velocitypowered.api.plugin.PluginContainer;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
|
||||
public class ACFVelocityListener {
|
||||
|
||||
private final VelocityCommandManager manager;
|
||||
private final PluginContainer plugin;
|
||||
private final ProxyServer proxy;
|
||||
|
||||
public ACFVelocityListener(VelocityCommandManager manager, PluginContainer plugin, ProxyServer proxy) {
|
||||
this.manager = manager;
|
||||
this.plugin = plugin;
|
||||
this.proxy = proxy;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onPlayerJoin(PostLoginEvent loginEvent) {
|
||||
Player player = loginEvent.getPlayer();
|
||||
|
||||
// the client settings are sent after a successful login
|
||||
Runnable task = () -> manager.readLocale(player);
|
||||
proxy.getScheduler().buildTask(plugin, task).delay(1, TimeUnit.SECONDS).schedule();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onDisconnect(DisconnectEvent disconnectEvent) {
|
||||
// cleanup
|
||||
Player player = disconnectEvent.getPlayer();
|
||||
manager.issuersLocale.remove(player.getUniqueId());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onSettingsChange(PlayerSettingsChangedEvent settingsEvent) {
|
||||
manager.setIssuerLocale(settingsEvent.getPlayer(), settingsEvent.getPlayer().getPlayerSettings().getLocale());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package co.aikar.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.serializer.ComponentSerializers;
|
||||
|
||||
public class ACFVelocityUtil {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static TextComponent color(String message) {
|
||||
return ComponentSerializers.LEGACY.deserialize(message);
|
||||
}
|
||||
|
||||
public static Player findPlayerSmart(ProxyServer server, CommandIssuer issuer, String search) {
|
||||
CommandSource requester = issuer.getIssuer();
|
||||
String name = ACFUtil.replace(search, ":confirm", "");
|
||||
if (name.length() < 3) {
|
||||
issuer.sendError(MinecraftMessageKeys.USERNAME_TOO_SHORT);
|
||||
return null;
|
||||
}
|
||||
if (!isValidName(name)) {
|
||||
issuer.sendError(MinecraftMessageKeys.IS_NOT_A_VALID_NAME, "{name}", name);
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Player> matches = new ArrayList<>(matchPlayer(server, name));
|
||||
|
||||
if (matches.size() > 1) {
|
||||
String allMatches = matches.stream().map(Player::getUsername).collect(Collectors.joining(", "));
|
||||
issuer.sendError(MinecraftMessageKeys.MULTIPLE_PLAYERS_MATCH, "{search}", name, "{all}", allMatches);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (matches.isEmpty()) {
|
||||
issuer.sendError(MinecraftMessageKeys.NO_PLAYER_FOUND_SERVER, "{search}", name);
|
||||
return null;
|
||||
}
|
||||
|
||||
return matches.get(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Original code written by md_5
|
||||
*
|
||||
* Modified to work with Velocity by Crypnotic
|
||||
*/
|
||||
private static Collection<Player> matchPlayer(ProxyServer server, final String partialName) {
|
||||
// A better error message might be nice. This just mimics the previous output
|
||||
if (partialName == null) {
|
||||
throw new NullPointerException("partialName");
|
||||
}
|
||||
|
||||
Optional<Player> exactMatch = server.getPlayer(partialName);
|
||||
if (exactMatch != null) {
|
||||
return Collections.singleton(exactMatch.get());
|
||||
}
|
||||
|
||||
return server.getAllPlayers().stream()
|
||||
.filter(player -> player.getUsername().regionMatches(true, 0, partialName, 0, partialName.length()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static boolean isValidName(String name) {
|
||||
return name != null && !name.isEmpty() && ACFPatterns.VALID_NAME_PATTERN.matcher(name).matches();
|
||||
}
|
||||
|
||||
public static <T> T validate(T object, String message, Object... values) {
|
||||
if (object == null) {
|
||||
throw new NullPointerException(String.format(message, values));
|
||||
}
|
||||
return object;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package co.aikar.commands;
|
||||
|
||||
import co.aikar.locales.MessageKey;
|
||||
import co.aikar.locales.MessageKeyProvider;
|
||||
|
||||
public enum MinecraftMessageKeys implements MessageKeyProvider {
|
||||
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());
|
||||
public MessageKey getMessageKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
@@ -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 com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
|
||||
public class VelocityCommandCompletionContext extends CommandCompletionContext<VelocityCommandIssuer> {
|
||||
|
||||
VelocityCommandCompletionContext(RegisteredCommand command, VelocityCommandIssuer issuer, String input, String config, String[] args) {
|
||||
super(command, issuer, input, config, args);
|
||||
}
|
||||
|
||||
public CommandSource getSender() {
|
||||
return this.getIssuer().getIssuer();
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.issuer.getPlayer();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
|
||||
import co.aikar.commands.apachecommonslang.ApacheCommonsLangUtil;
|
||||
import net.kyori.text.format.TextColor;
|
||||
import net.kyori.text.format.TextDecoration;
|
||||
import net.kyori.text.format.TextFormat;
|
||||
|
||||
public class VelocityCommandCompletions extends CommandCompletions<VelocityCommandCompletionContext> {
|
||||
|
||||
public VelocityCommandCompletions(ProxyServer server, CommandManager manager) {
|
||||
super(manager);
|
||||
registerAsyncCompletion("chatcolors", c -> {
|
||||
Stream<TextFormat> colors = Stream.of(TextColor.values());
|
||||
if (!c.hasConfig("colorsonly")) {
|
||||
colors = Stream.concat(colors, Stream.of(TextDecoration.values()));
|
||||
}
|
||||
String filter = c.getConfig("filter");
|
||||
if (filter != null) {
|
||||
Set<String> filters = Arrays.stream(ACFPatterns.COLON.split(filter)).map(ACFUtil::simplifyString)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
colors = colors.filter(color -> filters.contains(ACFUtil.simplifyString(color.toString())));
|
||||
}
|
||||
|
||||
return colors.map(color -> ACFUtil.simplifyString(color.toString())).collect(Collectors.toList());
|
||||
});
|
||||
registerCompletion("players", c -> {
|
||||
CommandSource sender = c.getSender();
|
||||
ACFVelocityUtil.validate(sender, "Sender cannot be null");
|
||||
String input = c.getInput();
|
||||
|
||||
ArrayList<String> matchedPlayers = new ArrayList<>();
|
||||
for (Player player : server.getAllPlayers()) {
|
||||
String name = player.getUsername();
|
||||
if (ApacheCommonsLangUtil.startsWithIgnoreCase(name, input)) {
|
||||
matchedPlayers.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
matchedPlayers.sort(String.CASE_INSENSITIVE_ORDER);
|
||||
return matchedPlayers;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
|
||||
import co.aikar.commands.annotation.Optional;
|
||||
import co.aikar.commands.contexts.OnlinePlayer;
|
||||
import net.kyori.text.format.TextColor;
|
||||
import net.kyori.text.format.TextDecoration;
|
||||
import net.kyori.text.format.TextFormat;
|
||||
|
||||
public class VelocityCommandContexts extends CommandContexts<VelocityCommandExecutionContext> {
|
||||
|
||||
VelocityCommandContexts(ProxyServer server, CommandManager manager) {
|
||||
super(manager);
|
||||
registerContext(OnlinePlayer.class, (c) -> {
|
||||
Player proxiedPlayer = ACFVelocityUtil.findPlayerSmart(server, c.getIssuer(), c.popFirstArg());
|
||||
if (proxiedPlayer == null) {
|
||||
if (c.hasAnnotation(Optional.class)) {
|
||||
return null;
|
||||
}
|
||||
throw new InvalidCommandArgument(false);
|
||||
}
|
||||
return new OnlinePlayer(proxiedPlayer);
|
||||
});
|
||||
registerIssuerAwareContext(CommandSource.class, VelocityCommandExecutionContext::getSender);
|
||||
registerIssuerAwareContext(Player.class, (c) -> {
|
||||
Player proxiedPlayer = c.getSender() instanceof Player ? (Player) c.getSender() : null;
|
||||
if (proxiedPlayer == null && !c.hasAnnotation(Optional.class)) {
|
||||
throw new InvalidCommandArgument(MessageKeys.NOT_ALLOWED_ON_CONSOLE, false);
|
||||
}
|
||||
return proxiedPlayer;
|
||||
});
|
||||
|
||||
registerContext(TextFormat.class, c -> {
|
||||
String first = c.popFirstArg();
|
||||
Stream<TextFormat> colors = Stream.of(TextColor.values());
|
||||
if (!c.hasFlag("colorsonly")) {
|
||||
colors = Stream.concat(colors, Stream.of(TextDecoration.values()));
|
||||
}
|
||||
String filter = c.getFlagValue("filter", (String) null);
|
||||
if (filter != null) {
|
||||
filter = ACFUtil.simplifyString(filter);
|
||||
String finalFilter = filter;
|
||||
colors = colors.filter(color -> finalFilter.equals(ACFUtil.simplifyString(color.toString())));
|
||||
}
|
||||
|
||||
TextColor match = ACFUtil.simpleMatch(TextColor.class, first);
|
||||
if (match == null) {
|
||||
String valid = colors.map(color -> "<c2>" + ACFUtil.simplifyString(color.toString()) + "</c2>")
|
||||
.collect(Collectors.joining("<c1>,</c1> "));
|
||||
|
||||
throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, "{valid}", valid);
|
||||
}
|
||||
return match;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package co.aikar.commands;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
|
||||
public class VelocityCommandExecutionContext extends CommandExecutionContext<VelocityCommandExecutionContext, VelocityCommandIssuer> {
|
||||
|
||||
VelocityCommandExecutionContext(RegisteredCommand cmd, CommandParameter param, VelocityCommandIssuer sender, List<String> args, int index, Map<String, Object> passedArgs) {
|
||||
super(cmd, param, sender, args, index, passedArgs);
|
||||
}
|
||||
|
||||
public CommandSource getSender() {
|
||||
return this.issuer.getIssuer();
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.issuer.getPlayer();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
|
||||
public class VelocityCommandIssuer implements CommandIssuer {
|
||||
private final VelocityCommandManager manager;
|
||||
private final CommandSource source;
|
||||
|
||||
VelocityCommandIssuer(VelocityCommandManager manager, CommandSource source) {
|
||||
this.manager = manager;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CommandSource getIssuer() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return isPlayer() ? (Player) source : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandManager getManager() {
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayer() {
|
||||
return source instanceof Player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull UUID getUniqueId() {
|
||||
if (isPlayer()) {
|
||||
return ((Player) source).getUniqueId();
|
||||
}
|
||||
|
||||
// TODO: Find a better solution for this
|
||||
//generate a unique id based of the name (like for the console command sender)
|
||||
return UUID.randomUUID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessageInternal(String message) {
|
||||
source.sendMessage(ACFVelocityUtil.color(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String name) {
|
||||
return source.hasPermission(name);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
VelocityCommandIssuer that = (VelocityCommandIssuer) o;
|
||||
return Objects.equals(source, that.source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(source);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.plugin.Plugin;
|
||||
import com.velocitypowered.api.plugin.PluginContainer;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
|
||||
import co.aikar.commands.apachecommonslang.ApacheCommonsExceptionUtil;
|
||||
import net.kyori.text.format.TextColor;
|
||||
|
||||
public class VelocityCommandManager extends
|
||||
CommandManager<CommandSource, VelocityCommandIssuer, TextColor, VelocityMessageFormatter, VelocityCommandExecutionContext, VelocityConditionContext> {
|
||||
|
||||
protected final ProxyServer proxy;
|
||||
protected final PluginContainer plugin;
|
||||
protected Map<String, VelocityRootCommand> registeredCommands = new HashMap<>();
|
||||
protected VelocityCommandContexts contexts;
|
||||
protected VelocityCommandCompletions completions;
|
||||
protected VelocityLocales locales;
|
||||
|
||||
public VelocityCommandManager(ProxyServer proxy, Object plugin) {
|
||||
this.proxy = proxy;
|
||||
this.plugin = proxy.getPluginManager().getPlugin(plugin.getClass().getAnnotation(Plugin.class).id()).get();
|
||||
this.formatters.put(MessageType.ERROR, defaultFormatter = new VelocityMessageFormatter(TextColor.RED, TextColor.YELLOW, TextColor.RED));
|
||||
this.formatters.put(MessageType.SYNTAX, new VelocityMessageFormatter(TextColor.YELLOW, TextColor.GREEN, TextColor.WHITE));
|
||||
this.formatters.put(MessageType.INFO, new VelocityMessageFormatter(TextColor.BLUE, TextColor.DARK_GREEN, TextColor.GREEN));
|
||||
this.formatters.put(MessageType.HELP, new VelocityMessageFormatter(TextColor.AQUA, TextColor.GREEN, TextColor.YELLOW));
|
||||
|
||||
getLocales();
|
||||
|
||||
proxy.getEventManager().register(plugin, new ACFVelocityListener(this, this.plugin, proxy));
|
||||
|
||||
registerDependency(plugin.getClass(), plugin);
|
||||
registerDependency(Plugin.class, plugin);
|
||||
registerDependency(ProxyServer.class, proxy);
|
||||
}
|
||||
|
||||
public ProxyServer getProxy() {
|
||||
return this.proxy;
|
||||
}
|
||||
|
||||
public PluginContainer getPlugin() {
|
||||
return this.plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized CommandContexts<VelocityCommandExecutionContext> getCommandContexts() {
|
||||
if (this.contexts == null) {
|
||||
this.contexts = new VelocityCommandContexts(proxy, this);
|
||||
}
|
||||
return contexts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized CommandCompletions<VelocityCommandCompletionContext> getCommandCompletions() {
|
||||
if (this.completions == null) {
|
||||
this.completions = new VelocityCommandCompletions(proxy, this);
|
||||
}
|
||||
return completions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityLocales getLocales() {
|
||||
if (this.locales == null) {
|
||||
this.locales = new VelocityLocales(this);
|
||||
this.locales.loadLanguages();
|
||||
}
|
||||
return locales;
|
||||
}
|
||||
|
||||
public void readLocale(Player player) {
|
||||
if (!player.isActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//This can be null if we didn't received a settings packet
|
||||
Locale locale = player.getPlayerSettings().getLocale();
|
||||
if (locale != null) {
|
||||
setIssuerLocale(player, player.getPlayerSettings().getLocale());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommand(BaseCommand command) {
|
||||
command.onRegister(this);
|
||||
for (Map.Entry<String, RootCommand> entry : command.registeredCommands.entrySet()) {
|
||||
String commandName = entry.getKey().toLowerCase();
|
||||
VelocityRootCommand velocityCommand = (VelocityRootCommand) entry.getValue();
|
||||
if (!velocityCommand.isRegistered) {
|
||||
proxy.getCommandManager().register(velocityCommand, commandName);
|
||||
}
|
||||
velocityCommand.isRegistered = true;
|
||||
registeredCommands.put(commandName, velocityCommand);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterCommand(BaseCommand command) {
|
||||
for (Map.Entry<String, RootCommand> entry : command.registeredCommands.entrySet()) {
|
||||
String commandName = entry.getKey().toLowerCase();
|
||||
VelocityRootCommand velocityCommand = (VelocityRootCommand) entry.getValue();
|
||||
velocityCommand.getSubCommands().values().removeAll(command.subCommands.values());
|
||||
if (velocityCommand.getSubCommands().isEmpty() && velocityCommand.isRegistered) {
|
||||
unregisterCommand(velocityCommand);
|
||||
velocityCommand.isRegistered = false;
|
||||
registeredCommands.remove(commandName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterCommand(VelocityRootCommand command) {
|
||||
proxy.getCommandManager().unregister(command.getCommandName());
|
||||
}
|
||||
|
||||
public void unregisterCommands() {
|
||||
for (Map.Entry<String, VelocityRootCommand> entry : registeredCommands.entrySet()) {
|
||||
unregisterCommand(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRegisteredCommands() {
|
||||
return !registeredCommands.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommandIssuer(Class<?> aClass) {
|
||||
return CommandSource.class.isAssignableFrom(aClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityCommandIssuer getCommandIssuer(Object issuer) {
|
||||
if (!(issuer instanceof CommandSource)) {
|
||||
throw new IllegalArgumentException(issuer.getClass().getName() + " is not a Command Issuer.");
|
||||
}
|
||||
return new VelocityCommandIssuer(this, (CommandSource) issuer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RootCommand createRootCommand(String cmd) {
|
||||
return new VelocityRootCommand(this, cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<RootCommand> getRegisteredRootCommands() {
|
||||
return Collections.unmodifiableCollection(registeredCommands.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityCommandExecutionContext createCommandContext(RegisteredCommand command, CommandParameter parameter, CommandIssuer sender, List<String> args, int i, Map<String, Object> passedArgs) {
|
||||
return new VelocityCommandExecutionContext(command, parameter, (VelocityCommandIssuer) sender, args, i, passedArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandCompletionContext createCompletionContext(RegisteredCommand command, CommandIssuer sender, String input, String config, String[] args) {
|
||||
return new VelocityCommandCompletionContext(command, (VelocityCommandIssuer) sender, input, config, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisteredCommand createRegisteredCommand(BaseCommand command, String cmdName, Method method, String prefSubCommand) {
|
||||
return new RegisteredCommand(command, cmdName, method, prefSubCommand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityConditionContext createConditionContext(CommandIssuer issuer, String config) {
|
||||
return new VelocityConditionContext((VelocityCommandIssuer) issuer, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(LogLevel level, String message, Throwable throwable) {
|
||||
// TODO: Find better solution
|
||||
Logger logger = LoggerFactory.getLogger(plugin.getClass());
|
||||
if (level == LogLevel.INFO) {
|
||||
logger.info(LogLevel.LOG_PREFIX + message);
|
||||
} else {
|
||||
logger.warn(LogLevel.LOG_PREFIX + message);
|
||||
}
|
||||
|
||||
if (throwable != null) {
|
||||
for (String line : ACFPatterns.NEWLINE.split(ApacheCommonsExceptionUtil.getFullStackTrace(throwable))) {
|
||||
if (level == LogLevel.INFO) {
|
||||
logger.info(LogLevel.LOG_PREFIX + line);
|
||||
} else {
|
||||
logger.warn(LogLevel.LOG_PREFIX + line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getCommandPrefix(CommandIssuer issuer) {
|
||||
return issuer.isPlayer() ? "/" : "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package co.aikar.commands;
|
||||
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
|
||||
public class VelocityConditionContext extends ConditionContext <VelocityCommandIssuer> {
|
||||
VelocityConditionContext(VelocityCommandIssuer issuer, String config) {
|
||||
super(issuer, config);
|
||||
}
|
||||
|
||||
|
||||
public CommandSource getSender() {
|
||||
return getIssuer().getIssuer();
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return getIssuer().getPlayer();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package co.aikar.commands;
|
||||
|
||||
public class VelocityLocales extends Locales {
|
||||
private final VelocityCommandManager manager;
|
||||
|
||||
public VelocityLocales(VelocityCommandManager manager) {
|
||||
super(manager);
|
||||
|
||||
this.manager = manager;
|
||||
this.addBundleClassLoader(this.manager.getPlugin().getClass().getClassLoader());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadLanguages() {
|
||||
super.loadLanguages();
|
||||
String pluginName = "acf-" + manager.plugin.getDescription().getName().get();
|
||||
addMessageBundles("acf-minecraft", pluginName, pluginName.toLowerCase());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package co.aikar.commands;
|
||||
|
||||
import net.kyori.text.format.TextColor;
|
||||
import net.kyori.text.serializer.ComponentSerializers;
|
||||
|
||||
public class VelocityMessageFormatter extends MessageFormatter<TextColor> {
|
||||
|
||||
public VelocityMessageFormatter(TextColor... colors) {
|
||||
super(colors);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
String format(TextColor color, String message) {
|
||||
return ComponentSerializers.LEGACY.serialize(ComponentSerializers.LEGACY.deserialize(message).color(color));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
import com.velocitypowered.api.command.Command;
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
|
||||
public class VelocityRootCommand implements Command, RootCommand {
|
||||
|
||||
private final VelocityCommandManager manager;
|
||||
private final String name;
|
||||
private BaseCommand defCommand;
|
||||
private SetMultimap<String, RegisteredCommand> subCommands = HashMultimap.create();
|
||||
private List<BaseCommand> children = new ArrayList<>();
|
||||
boolean isRegistered = false;
|
||||
|
||||
VelocityRootCommand(VelocityCommandManager manager, String name) {
|
||||
this.manager = manager;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChild(BaseCommand command) {
|
||||
if (this.defCommand == null || !command.subCommands.get(BaseCommand.DEFAULT).isEmpty()) {
|
||||
this.defCommand = command;
|
||||
|
||||
}
|
||||
this.addChildShared(this.children, this.subCommands, command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandManager getManager() {
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SetMultimap<String, RegisteredCommand> getSubCommands() {
|
||||
return subCommands;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BaseCommand> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSource source, String[] args) {
|
||||
execute(manager.getCommandIssuer(source), getCommandName(), args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> suggest(CommandSource source, String[] args) {
|
||||
return getTabCompletions(manager.getCommandIssuer(source), getCommandName(), args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseCommand getDefCommand() {
|
||||
return defCommand;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.contexts;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
|
||||
public class OnlinePlayer {
|
||||
|
||||
public final Player player;
|
||||
|
||||
public OnlinePlayer(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public Player getPlayer(){
|
||||
return 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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user