mirror of
https://github.com/PaperMC/Paper.git
synced 2025-05-18 21:20:24 -07:00
Replace old version command with brigadier equivalent (#12502)
--------- Co-authored-by: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
This commit is contained in:
parent
6f73e62ecd
commit
ce0fa4c438
@ -21,12 +21,24 @@ public interface VersionFetcher {
|
||||
/**
|
||||
* Gets the version message to cache and show to command senders.
|
||||
*
|
||||
* <p>NOTE: This is run in a new thread separate from that of the command processing thread</p>
|
||||
* @return the message to show when requesting a version
|
||||
* @apiNote This method may involve a web request which will block the executing thread
|
||||
*/
|
||||
Component getVersionMessage();
|
||||
|
||||
/**
|
||||
* Gets the version message to cache and show to command senders.
|
||||
*
|
||||
* @param serverVersion the current version of the server (will match {@link Bukkit#getVersion()})
|
||||
* @return the message to show when requesting a version
|
||||
* @apiNote This method may involve a web request which will block the current thread
|
||||
* @see #getVersionMessage()
|
||||
* @deprecated {@code serverVersion} is not required
|
||||
*/
|
||||
Component getVersionMessage(String serverVersion);
|
||||
@Deprecated
|
||||
default Component getVersionMessage(String serverVersion) {
|
||||
return getVersionMessage();
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
class DummyVersionFetcher implements VersionFetcher {
|
||||
@ -37,7 +49,7 @@ public interface VersionFetcher {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getVersionMessage(final String serverVersion) {
|
||||
public Component getVersionMessage() {
|
||||
Bukkit.getLogger().warning("Version provider has not been set, cannot check for updates!");
|
||||
Bukkit.getLogger().info("Override the default implementation of org.bukkit.UnsafeValues#getVersionFetcher()");
|
||||
new Throwable().printStackTrace();
|
||||
|
@ -5,7 +5,6 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -14,32 +13,26 @@ import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.defaults.BukkitCommand;
|
||||
import org.bukkit.command.defaults.HelpCommand;
|
||||
import org.bukkit.command.defaults.PluginsCommand;
|
||||
import org.bukkit.command.defaults.ReloadCommand;
|
||||
import org.bukkit.command.defaults.VersionCommand;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.StringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class SimpleCommandMap implements CommandMap {
|
||||
protected final Map<String, Command> knownCommands; // Paper
|
||||
protected final Map<String, Command> knownCommands;
|
||||
private final Server server;
|
||||
|
||||
// Paper start
|
||||
@org.jetbrains.annotations.ApiStatus.Internal
|
||||
public SimpleCommandMap(@NotNull final Server server, Map<String, Command> backing) {
|
||||
this.knownCommands = backing;
|
||||
// Paper end
|
||||
this.server = server;
|
||||
setDefaultCommands();
|
||||
}
|
||||
|
||||
private void setDefaultCommands() {
|
||||
register("bukkit", new VersionCommand("version"));
|
||||
register("bukkit", new ReloadCommand("reload"));
|
||||
//register("bukkit", new PluginsCommand("plugins")); // Paper
|
||||
register("bukkit", new co.aikar.timings.TimingsCommand("timings")); // Paper
|
||||
register("bukkit", new co.aikar.timings.TimingsCommand("timings"));
|
||||
}
|
||||
|
||||
public void setFallbackCommands() {
|
||||
|
@ -32,6 +32,7 @@ import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
public class VersionCommand extends BukkitCommand {
|
||||
private VersionFetcher versionFetcher; // Paper - version command 2.0
|
||||
private VersionFetcher getVersionFetcher() { // lazy load because unsafe isn't available at command registration
|
||||
|
@ -43,7 +43,7 @@ public class PaperVersionFetcher implements VersionFetcher {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getVersionMessage(final String serverVersion) {
|
||||
public Component getVersionMessage() {
|
||||
final Component updateMessage;
|
||||
final ServerBuildInfo build = ServerBuildInfo.buildInfo();
|
||||
if (build.buildNumber().isEmpty() && build.gitCommit().isEmpty()) {
|
||||
|
@ -1,7 +1,15 @@
|
||||
package io.papermc.paper.command;
|
||||
|
||||
import io.papermc.paper.FeatureHooks;
|
||||
import io.papermc.paper.command.subcommands.*;
|
||||
import io.papermc.paper.command.subcommands.DumpItemCommand;
|
||||
import io.papermc.paper.command.subcommands.DumpListenersCommand;
|
||||
import io.papermc.paper.command.subcommands.DumpPluginsCommand;
|
||||
import io.papermc.paper.command.subcommands.EntityCommand;
|
||||
import io.papermc.paper.command.subcommands.HeapDumpCommand;
|
||||
import io.papermc.paper.command.subcommands.MobcapsCommand;
|
||||
import io.papermc.paper.command.subcommands.ReloadCommand;
|
||||
import io.papermc.paper.command.subcommands.SyncLoadInfoCommand;
|
||||
import io.papermc.paper.command.subcommands.VersionCommand;
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -33,13 +33,14 @@ public final class PaperCommands {
|
||||
}
|
||||
|
||||
public static void registerCommands() {
|
||||
// Paper commands go here
|
||||
// Paper commands go here
|
||||
registerInternalCommand(PaperVersionCommand.create(), "bukkit", PaperVersionCommand.DESCRIPTION, List.of("ver", "about"), Set.of());
|
||||
}
|
||||
|
||||
private static void registerInternalCommand(final LiteralCommandNode<CommandSourceStack> node, final String description, final List<String> aliases, final Set<CommandRegistrationFlag> flags) {
|
||||
private static void registerInternalCommand(final LiteralCommandNode<CommandSourceStack> node, final String namespace, final String description, final List<String> aliases, final Set<CommandRegistrationFlag> flags) {
|
||||
io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.registerWithFlagsInternal(
|
||||
null,
|
||||
"paper",
|
||||
namespace,
|
||||
"Paper",
|
||||
node,
|
||||
description,
|
||||
|
@ -0,0 +1,184 @@
|
||||
package io.papermc.paper.command;
|
||||
|
||||
import com.destroystokyo.paper.PaperVersionFetcher;
|
||||
import com.destroystokyo.paper.util.VersionFetcher;
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import io.papermc.paper.command.brigadier.CommandSourceStack;
|
||||
import io.papermc.paper.command.brigadier.Commands;
|
||||
import io.papermc.paper.plugin.configuration.PluginMeta;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.util.StringUtil;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
public class PaperVersionCommand {
|
||||
public static final String DESCRIPTION = "Gets the version of this server including any plugins in use";
|
||||
|
||||
private static final Component NOT_RUNNING = Component.text()
|
||||
.append(Component.text("This server is not running any plugin by that name."))
|
||||
.appendNewline()
|
||||
.append(Component.text("Use /plugins to get a list of plugins.").clickEvent(ClickEvent.suggestCommand("/plugins")))
|
||||
.build();
|
||||
private static final JoinConfiguration PLAYER_JOIN_CONFIGURATION = JoinConfiguration.separators(
|
||||
Component.text(", ", NamedTextColor.WHITE),
|
||||
Component.text(", and ", NamedTextColor.WHITE)
|
||||
);
|
||||
private static final Component FAILED_TO_FETCH = Component.text("Could not fetch version information!", NamedTextColor.RED);
|
||||
private static final Component FETCHING = Component.text("Checking version, please wait...", NamedTextColor.WHITE, TextDecoration.ITALIC);
|
||||
|
||||
private final VersionFetcher versionFetcher = new PaperVersionFetcher();
|
||||
private CompletableFuture<ComputedVersion> computedVersion = CompletableFuture.completedFuture(new ComputedVersion(Component.empty(), -1)); // Precompute-- someday move that stuff out of bukkit
|
||||
|
||||
public static LiteralCommandNode<CommandSourceStack> create() {
|
||||
final PaperVersionCommand command = new PaperVersionCommand();
|
||||
|
||||
return Commands.literal("version")
|
||||
.requires(source -> source.getSender().hasPermission("bukkit.command.version"))
|
||||
.then(Commands.argument("plugin", StringArgumentType.word())
|
||||
.suggests(command::suggestPlugins)
|
||||
.executes(command::pluginVersion))
|
||||
.executes(command::serverVersion)
|
||||
.build();
|
||||
}
|
||||
|
||||
private int pluginVersion(final CommandContext<CommandSourceStack> context) {
|
||||
final CommandSender sender = context.getSource().getSender();
|
||||
final String pluginName = context.getArgument("plugin", String.class).toLowerCase(Locale.ROOT);
|
||||
|
||||
Plugin plugin = Bukkit.getPluginManager().getPlugin(pluginName);
|
||||
if (plugin == null) {
|
||||
plugin = Arrays.stream(Bukkit.getPluginManager().getPlugins())
|
||||
.filter(checkPlugin -> checkPlugin.getName().toLowerCase(Locale.ROOT).contains(pluginName))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
if (plugin != null) {
|
||||
this.sendPluginInfo(plugin, sender);
|
||||
} else {
|
||||
sender.sendMessage(NOT_RUNNING);
|
||||
}
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
private CompletableFuture<Suggestions> suggestPlugins(final CommandContext<CommandSourceStack> context, final SuggestionsBuilder builder) {
|
||||
for (final Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
|
||||
final String name = plugin.getName();
|
||||
if (StringUtil.startsWithIgnoreCase(name, builder.getRemainingLowerCase())) {
|
||||
builder.suggest(name);
|
||||
}
|
||||
}
|
||||
|
||||
return CompletableFuture.completedFuture(builder.build());
|
||||
}
|
||||
|
||||
private void sendPluginInfo(final Plugin plugin, final CommandSender sender) {
|
||||
final PluginMeta meta = plugin.getPluginMeta();
|
||||
|
||||
final TextComponent.Builder builder = Component.text()
|
||||
.append(Component.text(meta.getName()))
|
||||
.append(Component.text(" version "))
|
||||
.append(Component.text(meta.getVersion(), NamedTextColor.GREEN)
|
||||
.hoverEvent(Component.translatable("chat.copy.click"))
|
||||
.clickEvent(ClickEvent.copyToClipboard(meta.getVersion()))
|
||||
);
|
||||
|
||||
if (meta.getDescription() != null) {
|
||||
builder
|
||||
.appendNewline()
|
||||
.append(Component.text(meta.getDescription()));
|
||||
}
|
||||
|
||||
if (meta.getWebsite() != null) {
|
||||
Component websiteComponent = Component.text(meta.getWebsite(), NamedTextColor.GREEN).clickEvent(ClickEvent.openUrl(meta.getWebsite()));
|
||||
builder.appendNewline().append(Component.text("Website: ").append(websiteComponent));
|
||||
}
|
||||
|
||||
if (!meta.getAuthors().isEmpty()) {
|
||||
String prefix = meta.getAuthors().size() == 1 ? "Author: " : "Authors: ";
|
||||
builder.appendNewline().append(Component.text(prefix).append(formatNameList(meta.getAuthors())));
|
||||
}
|
||||
|
||||
if (!meta.getContributors().isEmpty()) {
|
||||
builder.appendNewline().append(Component.text("Contributors: ").append(formatNameList(meta.getContributors())));
|
||||
}
|
||||
sender.sendMessage(builder.build());
|
||||
}
|
||||
|
||||
private static Component formatNameList(final List<String> names) {
|
||||
return Component.join(PLAYER_JOIN_CONFIGURATION, names.stream().map(Component::text).toList()).color(NamedTextColor.GREEN);
|
||||
}
|
||||
|
||||
private int serverVersion(CommandContext<CommandSourceStack> context) {
|
||||
sendVersion(context.getSource().getSender());
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
private void sendVersion(final CommandSender sender) {
|
||||
final CompletableFuture<ComputedVersion> version = getVersionOrFetch();
|
||||
if (!version.isDone()) {
|
||||
sender.sendMessage(FETCHING);
|
||||
}
|
||||
|
||||
version.whenComplete((computedVersion, throwable) -> {
|
||||
if (computedVersion != null) {
|
||||
sender.sendMessage(computedVersion.message);
|
||||
} else if (throwable != null) {
|
||||
sender.sendMessage(FAILED_TO_FETCH);
|
||||
MinecraftServer.LOGGER.warn("Could not fetch version information!", throwable);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private CompletableFuture<ComputedVersion> getVersionOrFetch() {
|
||||
if (!this.computedVersion.isDone()) {
|
||||
return this.computedVersion;
|
||||
}
|
||||
|
||||
if (this.computedVersion.isCompletedExceptionally() || System.currentTimeMillis() - this.computedVersion.resultNow().computedTime() > this.versionFetcher.getCacheTime()) {
|
||||
this.computedVersion = this.fetchVersionMessage();
|
||||
}
|
||||
|
||||
return this.computedVersion;
|
||||
}
|
||||
|
||||
private CompletableFuture<ComputedVersion> fetchVersionMessage() {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
final Component message = Component.textOfChildren(
|
||||
Component.text(Bukkit.getVersionMessage(), NamedTextColor.WHITE),
|
||||
Component.newline(),
|
||||
this.versionFetcher.getVersionMessage()
|
||||
);
|
||||
|
||||
return new ComputedVersion(
|
||||
message.hoverEvent(Component.translatable("chat.copy.click", NamedTextColor.WHITE))
|
||||
.clickEvent(ClickEvent.copyToClipboard(PlainTextComponentSerializer.plainText().serialize(message))),
|
||||
System.currentTimeMillis()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
record ComputedVersion(Component message, long computedTime) {
|
||||
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user