diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommand.java b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommand.java index d6ff9718e..6e9c087bb 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommand.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommand.java @@ -1,19 +1,27 @@ package com.velocitypowered.proxy.command; +import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.velocitypowered.api.command.Command; import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.permission.Tristate; +import com.velocitypowered.api.plugin.PluginContainer; +import com.velocitypowered.api.plugin.PluginDescription; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.util.ProxyVersion; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; +import java.util.stream.Stream; +import net.kyori.text.Components; import net.kyori.text.TextComponent; import net.kyori.text.event.ClickEvent; +import net.kyori.text.event.HoverEvent; +import net.kyori.text.event.HoverEvent.Action; import net.kyori.text.format.TextColor; import net.kyori.text.format.TextDecoration; import org.checkerframework.checker.nullness.qual.NonNull; @@ -25,6 +33,7 @@ public class VelocityCommand implements Command { public VelocityCommand(ProxyServer server) { this.subcommands = ImmutableMap.builder() .put("version", new Info(server)) + .put("plugins", new Plugins(server)) .build(); } @@ -132,4 +141,75 @@ public class VelocityCommand implements Command { return source.getPermissionValue("velocity.command.info") != Tristate.FALSE; } } + + private static class Plugins implements Command { + + private final ProxyServer server; + + private Plugins(ProxyServer server) { + this.server = server; + } + + @Override + public void execute(CommandSource source, String @NonNull [] args) { + if (args.length != 0) { + source.sendMessage(TextComponent.of("/velocity plugins", TextColor.RED)); + return; + } + + List plugins = ImmutableList.copyOf(server.getPluginManager().getPlugins()); + int pluginCount = plugins.size(); + + if (pluginCount == 0) { + source.sendMessage(TextComponent.of("No plugins installed.", TextColor.YELLOW)); + return; + } + + TextComponent.Builder output = TextComponent.builder("Plugins: ") + .color(TextColor.YELLOW); + for (int i = 0; i < pluginCount; i++) { + PluginContainer plugin = plugins.get(i); + output.append(componentForPlugin(plugin.getDescription())); + if (i + 1 < pluginCount) { + output.append(TextComponent.of(", ")); + } + } + + source.sendMessage(output.build()); + } + + private TextComponent componentForPlugin(PluginDescription description) { + TextComponent pluginSelf = TextComponent.of(description.getId(), TextColor.GRAY); + String pluginInfo = description.getName().orElse(description.getId()) + + description.getVersion().map(v -> " " + v).orElse(""); + + TextComponent.Builder hoverText = TextComponent.builder(pluginInfo); + + description.getUrl().ifPresent(url -> { + hoverText.append(Components.newline()); + hoverText.append(TextComponent.of("Website: " + url)); + }); + if (!description.getAuthors().isEmpty()) { + hoverText.append(Components.newline()); + if (description.getAuthors().size() == 1) { + hoverText.append(TextComponent.of("Author: " + description.getAuthors().get(0))); + } else { + hoverText.append(TextComponent.of("Author: " + Joiner.on(", ") + .join(description.getAuthors()))); + } + } + description.getDescription().ifPresent(pdesc -> { + hoverText.append(Components.newline()); + hoverText.append(Components.newline()); + hoverText.append(TextComponent.of(pdesc)); + }); + + return pluginSelf.hoverEvent(new HoverEvent(Action.SHOW_TEXT, hoverText.build())); + } + + @Override + public boolean hasPermission(CommandSource source, String @NonNull [] args) { + return source.getPermissionValue("velocity.command.plugins") == Tristate.TRUE; + } + } }