Bungee lib
This commit is contained in:
parent
c66321f3d3
commit
1d72fea8c1
27
Bungee/.classpath
Normal file
27
Bungee/.classpath
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="optional" value="true"/>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="optional" value="true"/>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
<attribute name="test" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="output" path="target/classes"/>
|
||||||
|
</classpath>
|
1
Bungee/.gitignore
vendored
Normal file
1
Bungee/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target/
|
23
Bungee/.project
Normal file
23
Bungee/.project
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>pandalib-bungee</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
3
Bungee/.settings/org.eclipse.core.resources.prefs
Normal file
3
Bungee/.settings/org.eclipse.core.resources.prefs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding//src/main/java=UTF-8
|
||||||
|
encoding/<project>=UTF-8
|
8
Bungee/.settings/org.eclipse.jdt.core.prefs
Normal file
8
Bungee/.settings/org.eclipse.jdt.core.prefs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=11
|
||||||
|
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.release=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.source=11
|
4
Bungee/.settings/org.eclipse.m2e.core.prefs
Normal file
4
Bungee/.settings/org.eclipse.m2e.core.prefs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
activeProfiles=
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
resolveWorkspaceProjects=true
|
||||||
|
version=1
|
43
Bungee/pom.xml
Normal file
43
Bungee/pom.xml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>fr.pandacube.lib</groupId>
|
||||||
|
<artifactId>pandalib-parent</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>pandalib-bungee</artifactId>
|
||||||
|
|
||||||
|
<name>PandaLib-Bungee</name>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>papermc</id>
|
||||||
|
<url>https://papermc.io/repo/repository/maven-public/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>fr.pandacube.lib</groupId>
|
||||||
|
<artifactId>pandalib-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
BungeeCord
|
||||||
|
-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>fr.pandacube.bungeecord</groupId>
|
||||||
|
<artifactId>bungeecord-proxy</artifactId>
|
||||||
|
<version>${bungeecord.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,210 @@
|
|||||||
|
package fr.pandacube.lib.bungee.commands;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.arguments.ArgumentType;
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import com.mojang.brigadier.context.ParsedCommandNode;
|
||||||
|
import com.mojang.brigadier.context.StringRange;
|
||||||
|
import com.mojang.brigadier.suggestion.Suggestion;
|
||||||
|
import com.mojang.brigadier.suggestion.SuggestionProvider;
|
||||||
|
import com.mojang.brigadier.suggestion.Suggestions;
|
||||||
|
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||||
|
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||||
|
|
||||||
|
import fr.pandacube.lib.core.chat.ChatStatic;
|
||||||
|
import fr.pandacube.lib.core.commands.SuggestionsSupplier;
|
||||||
|
import fr.pandacube.lib.core.util.Log;
|
||||||
|
import fr.pandacube.lib.core.util.ReflexionUtil;
|
||||||
|
import net.md_5.bungee.BungeeCord;
|
||||||
|
import net.md_5.bungee.api.CommandSender;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.md_5.bungee.api.plugin.Command;
|
||||||
|
import net.md_5.bungee.api.plugin.TabExecutor;
|
||||||
|
import net.md_5.bungee.command.ConsoleCommandSender;
|
||||||
|
|
||||||
|
public abstract class BrigadierCommand extends ChatStatic {
|
||||||
|
|
||||||
|
private LiteralCommandNode<CommandSender> commandNode;
|
||||||
|
|
||||||
|
protected BrigadierDispatcher dispatcher;
|
||||||
|
|
||||||
|
public BrigadierCommand() {
|
||||||
|
if (BrigadierDispatcher.getInstance() == null) {
|
||||||
|
throw new IllegalStateException("BrigadierDispatcher is not yet initialized.");
|
||||||
|
}
|
||||||
|
dispatcher = BrigadierDispatcher.getInstance();
|
||||||
|
|
||||||
|
LiteralArgumentBuilder<CommandSender> builder = buildCommand();
|
||||||
|
String[] aliases = getAliases();
|
||||||
|
if (aliases == null)
|
||||||
|
aliases = new String[0];
|
||||||
|
|
||||||
|
commandNode = dispatcher.register(builder);
|
||||||
|
|
||||||
|
// still have to be registered for console
|
||||||
|
BungeeCord.getInstance().getPluginManager().registerCommand(dispatcher.plugin, new CommandRelay(commandNode.getLiteral()));
|
||||||
|
|
||||||
|
for (String alias : aliases) {
|
||||||
|
dispatcher.register(literal(alias)
|
||||||
|
.requires(commandNode.getRequirement())
|
||||||
|
.executes(commandNode.getCommand())
|
||||||
|
.redirect(commandNode)
|
||||||
|
);
|
||||||
|
|
||||||
|
BungeeCord.getInstance().getPluginManager().registerCommand(dispatcher.plugin, new CommandRelay(alias));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CommandRelay extends Command implements TabExecutor {
|
||||||
|
private String alias;
|
||||||
|
public CommandRelay(String alias) {
|
||||||
|
super(alias);
|
||||||
|
this.alias = alias;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, String[] args) {
|
||||||
|
dispatcher.execute(sender, alias + (args.length == 0 ? "" : (" " + String.join(" ", args))));
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Iterable<String> onTabComplete(CommandSender sender, String[] args) {
|
||||||
|
|
||||||
|
String cursor = "/" + alias + " " + String.join(" ", args);
|
||||||
|
|
||||||
|
StringRange supportedRange = StringRange.between(cursor.lastIndexOf(' ') + 1, cursor.length());
|
||||||
|
|
||||||
|
Suggestions suggestions = dispatcher.getSuggestions(sender, cursor.substring(1));
|
||||||
|
if (!suggestions.getRange().equals(supportedRange))
|
||||||
|
return Collections.emptyList();
|
||||||
|
|
||||||
|
return suggestions.getList()
|
||||||
|
.stream()
|
||||||
|
.filter(s -> s.getRange().equals(supportedRange))
|
||||||
|
.map(s -> s.getText())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract LiteralArgumentBuilder<CommandSender> buildCommand();
|
||||||
|
|
||||||
|
protected String[] getAliases() {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static LiteralArgumentBuilder<CommandSender> literal(String name) {
|
||||||
|
return LiteralArgumentBuilder.literal(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> RequiredArgumentBuilder<CommandSender, T> argument(String name, ArgumentType<T> type) {
|
||||||
|
return RequiredArgumentBuilder.argument(name, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Predicate<CommandSender> hasPermission(String permission) {
|
||||||
|
return sender -> sender.hasPermission(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Predicate<CommandSender> isPlayer() {
|
||||||
|
return sender -> isPlayer(sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPlayer(CommandSender sender) {
|
||||||
|
return sender instanceof ProxiedPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Predicate<CommandSender> isConsole() {
|
||||||
|
return sender -> isConsole(sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isConsole(CommandSender sender) {
|
||||||
|
return sender instanceof ConsoleCommandSender;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean isLiteralParsed(CommandContext<CommandSender> context, String literal) {
|
||||||
|
for (ParsedCommandNode<CommandSender> node : context.getNodes()) {
|
||||||
|
if (!(node.getNode() instanceof LiteralCommandNode))
|
||||||
|
continue;
|
||||||
|
if (((LiteralCommandNode<CommandSender>)node.getNode()).getLiteral().equals(literal))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T tryGetArgument(CommandContext<CommandSender> context, String argument, Class<T> type) {
|
||||||
|
return tryGetArgument(context, argument, type, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T tryGetArgument(CommandContext<CommandSender> context, String argument, Class<T> type, T deflt) {
|
||||||
|
try {
|
||||||
|
return context.getArgument(argument, type);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return deflt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected static SuggestionProvider<CommandSender> wrapSuggestions(SuggestionsSupplier<CommandSender> suggestions) {
|
||||||
|
return (context, builder) -> {
|
||||||
|
CommandSender sender = context.getSource();
|
||||||
|
String message = builder.getInput();
|
||||||
|
try {
|
||||||
|
int tokenStartPos = builder.getStart();
|
||||||
|
|
||||||
|
List<String> results = Collections.emptyList();
|
||||||
|
|
||||||
|
int firstSpacePos = message.indexOf(" ");
|
||||||
|
String[] args = (firstSpacePos + 1 > tokenStartPos - 1) ? new String[0]
|
||||||
|
: message.substring(firstSpacePos + 1, tokenStartPos - 1).split(" ", -1);
|
||||||
|
args = Arrays.copyOf(args, args.length + 1);
|
||||||
|
args[args.length - 1] = message.substring(tokenStartPos);
|
||||||
|
|
||||||
|
results = suggestions.getSuggestions(sender, args.length - 1, args[args.length - 1], args);
|
||||||
|
|
||||||
|
for (String s : results) {
|
||||||
|
if (s != null)
|
||||||
|
builder.suggest(s);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Log.severe("Error while tab-completing '" + message + "' for " + sender.getName(), e);
|
||||||
|
}
|
||||||
|
return completableFutureSuggestionsKeepsOriginalOrdering(builder);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static CompletableFuture<Suggestions> completableFutureSuggestionsKeepsOriginalOrdering(SuggestionsBuilder builder) {
|
||||||
|
return CompletableFuture.completedFuture(
|
||||||
|
BrigadierDispatcher.createSuggestionsOriginalOrdering(builder.getInput(), getSuggestionsFromSuggestionsBuilder(builder))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static List<Suggestion> getSuggestionsFromSuggestionsBuilder(SuggestionsBuilder builder) {
|
||||||
|
try {
|
||||||
|
return (List<Suggestion>) ReflexionUtil.getDeclaredFieldValue(SuggestionsBuilder.class, builder, "result");
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,222 @@
|
|||||||
|
package fr.pandacube.lib.bungee.commands;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
|
import com.mojang.brigadier.ParseResults;
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.context.CommandContextBuilder;
|
||||||
|
import com.mojang.brigadier.context.StringRange;
|
||||||
|
import com.mojang.brigadier.context.SuggestionContext;
|
||||||
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
import com.mojang.brigadier.suggestion.Suggestion;
|
||||||
|
import com.mojang.brigadier.suggestion.Suggestions;
|
||||||
|
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||||
|
import com.mojang.brigadier.tree.CommandNode;
|
||||||
|
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||||
|
|
||||||
|
import fr.pandacube.lib.core.chat.Chat;
|
||||||
|
import fr.pandacube.lib.core.util.Log;
|
||||||
|
import net.md_5.bungee.api.CommandSender;
|
||||||
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.md_5.bungee.api.event.ChatEvent;
|
||||||
|
import net.md_5.bungee.api.event.CommandsDeclareEvent;
|
||||||
|
import net.md_5.bungee.api.event.TabCompleteRequestEvent;
|
||||||
|
import net.md_5.bungee.api.plugin.Listener;
|
||||||
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
import net.md_5.bungee.event.EventHandler;
|
||||||
|
|
||||||
|
public class BrigadierDispatcher implements Listener {
|
||||||
|
|
||||||
|
private static BrigadierDispatcher instance = null;
|
||||||
|
|
||||||
|
public static synchronized void init(Plugin plugin) {
|
||||||
|
instance = new BrigadierDispatcher(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized BrigadierDispatcher getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private CommandDispatcher<CommandSender> dispatcher;
|
||||||
|
/* package */ Plugin plugin;
|
||||||
|
|
||||||
|
private BrigadierDispatcher(Plugin pl) {
|
||||||
|
plugin = pl;
|
||||||
|
dispatcher = new CommandDispatcher<>();
|
||||||
|
ProxyServer.getInstance().getPluginManager().registerListener(plugin, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* package */ LiteralCommandNode<CommandSender> register(LiteralArgumentBuilder<CommandSender> node) {
|
||||||
|
return dispatcher.register(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public CommandDispatcher<CommandSender> getDispatcher() {
|
||||||
|
return dispatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onCommandsDeclare(CommandsDeclareEvent event) {
|
||||||
|
dispatcher.getRoot().getChildren().forEach(node -> {
|
||||||
|
event.getRoot().getChildren().remove(event.getRoot().getChild(node.getName())); // may not work in the future
|
||||||
|
event.getRoot().addChild(node);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onTabComplete(TabCompleteRequestEvent event) {
|
||||||
|
if (!event.getCursor().startsWith("/"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
String commandLine = event.getCursor().substring(1);
|
||||||
|
|
||||||
|
String commandName = commandLine.split(" ", -1)[0];
|
||||||
|
|
||||||
|
if (dispatcher.getRoot().getChild(commandName) == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Suggestions suggestions = getSuggestions((ProxiedPlayer) event.getSender(), commandLine);
|
||||||
|
|
||||||
|
// shift suggestion range 1 to the right to consider the /
|
||||||
|
suggestions = new Suggestions(new StringRange(suggestions.getRange().getStart() + 1, suggestions.getRange().getEnd() + 1), suggestions.getList());
|
||||||
|
|
||||||
|
event.setSuggestions(suggestions);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onChat(ChatEvent event) {
|
||||||
|
if (!event.getMessage().startsWith("/"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
String commandLine = event.getMessage().substring(1);
|
||||||
|
|
||||||
|
String commandName = commandLine.split(" ", -1)[0];
|
||||||
|
|
||||||
|
if (dispatcher.getRoot().getChild(commandName) == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
event.setCancelled(true);
|
||||||
|
|
||||||
|
ProxyServer.getInstance().getScheduler().runAsync(plugin, () -> {
|
||||||
|
execute((ProxiedPlayer) event.getSender(), commandLine);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* package */ int execute(CommandSender sender, String commandWithoutSlash) {
|
||||||
|
ParseResults<CommandSender> parsed = dispatcher.parse(commandWithoutSlash, sender);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return dispatcher.execute(parsed);
|
||||||
|
} catch (CommandSyntaxException e) {
|
||||||
|
sender.sendMessage(Chat.failureText("Erreur d’utilisation de la commande : " + e.getMessage()).get());
|
||||||
|
return 0;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
sender.sendMessage(Chat.failureText("Erreur lors de l’exécution de la commande : " + e.getMessage()).get());
|
||||||
|
Log.severe(e);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* package */ Suggestions getSuggestions(CommandSender sender, String buffer) {
|
||||||
|
ParseResults<CommandSender> parsed = dispatcher.parse(buffer, sender);
|
||||||
|
try {
|
||||||
|
CompletableFuture<Suggestions> futureSuggestions = buildSuggestionBrigadier(parsed);
|
||||||
|
return futureSuggestions.join();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
sender.sendMessage(Chat.failureText("Erreur d’exécution des suggestions :\n" + e.getMessage()).get());
|
||||||
|
Log.severe(e);
|
||||||
|
return Suggestions.empty().join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CompletableFuture<Suggestions> buildSuggestionBrigadier(ParseResults<CommandSender> parsed) {
|
||||||
|
int cursor = parsed.getReader().getTotalLength();
|
||||||
|
final CommandContextBuilder<CommandSender> context = parsed.getContext();
|
||||||
|
|
||||||
|
final SuggestionContext<CommandSender> nodeBeforeCursor = context.findSuggestionContext(cursor);
|
||||||
|
final CommandNode<CommandSender> parent = nodeBeforeCursor.parent;
|
||||||
|
final int start = Math.min(nodeBeforeCursor.startPos, cursor);
|
||||||
|
|
||||||
|
final String fullInput = parsed.getReader().getString();
|
||||||
|
final String truncatedInput = fullInput.substring(0, cursor);
|
||||||
|
@SuppressWarnings("unchecked") final CompletableFuture<Suggestions>[] futures = new CompletableFuture[parent.getChildren().size()];
|
||||||
|
int i = 0;
|
||||||
|
for (final CommandNode<CommandSender> node : parent.getChildren()) {
|
||||||
|
CompletableFuture<Suggestions> future = Suggestions.empty();
|
||||||
|
try {
|
||||||
|
future = node.listSuggestions(context.build(truncatedInput), new SuggestionsBuilder(truncatedInput, start));
|
||||||
|
} catch (final CommandSyntaxException ignored) {
|
||||||
|
}
|
||||||
|
futures[i++] = future;
|
||||||
|
}
|
||||||
|
|
||||||
|
final CompletableFuture<Suggestions> result = new CompletableFuture<>();
|
||||||
|
CompletableFuture.allOf(futures).thenRun(() -> {
|
||||||
|
final List<Suggestions> suggestions = new ArrayList<>();
|
||||||
|
for (final CompletableFuture<Suggestions> future : futures) {
|
||||||
|
suggestions.add(future.join());
|
||||||
|
}
|
||||||
|
result.complete(mergeSuggestionsOriginalOrdering(fullInput, suggestions));
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// inspired from com.mojang.brigadier.suggestion.Suggestions#merge, but without the sorting part
|
||||||
|
public static Suggestions mergeSuggestionsOriginalOrdering(String input, Collection<Suggestions> suggestions) {
|
||||||
|
if (suggestions.isEmpty()) {
|
||||||
|
return new Suggestions(StringRange.at(0), new ArrayList<>(0));
|
||||||
|
} else if (suggestions.size() == 1) {
|
||||||
|
return suggestions.iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Suggestion> texts = new ArrayList<>();
|
||||||
|
for (final Suggestions suggestions1 : suggestions) {
|
||||||
|
texts.addAll(suggestions1.getList());
|
||||||
|
}
|
||||||
|
return createSuggestionsOriginalOrdering(input, texts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// inspired from com.mojang.brigadier.suggestion.Suggestions#create, but without the sorting part
|
||||||
|
public static Suggestions createSuggestionsOriginalOrdering(String command, Collection<Suggestion> suggestions) {
|
||||||
|
if (suggestions.isEmpty()) {
|
||||||
|
return new Suggestions(StringRange.at(0), new ArrayList<>(0));
|
||||||
|
}
|
||||||
|
int start = Integer.MAX_VALUE;
|
||||||
|
int end = Integer.MIN_VALUE;
|
||||||
|
for (final Suggestion suggestion : suggestions) {
|
||||||
|
start = Math.min(suggestion.getRange().getStart(), start);
|
||||||
|
end = Math.max(suggestion.getRange().getEnd(), end);
|
||||||
|
}
|
||||||
|
final StringRange range = new StringRange(start, end);
|
||||||
|
final List<Suggestion> texts = new ArrayList<>(suggestions.size());
|
||||||
|
for (final Suggestion suggestion : suggestions) {
|
||||||
|
texts.add(suggestion.expand(command, range));
|
||||||
|
}
|
||||||
|
return new Suggestions(range, texts);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user