mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-01 05:58:00 +01:00
Allow ask_server tab complete for CommandProcessor
This commit is contained in:
parent
47d956c538
commit
baccc36ed7
@ -7,9 +7,7 @@ import net.minestom.server.advancements.FrameType;
|
||||
import net.minestom.server.benchmark.BenchmarkManager;
|
||||
import net.minestom.server.benchmark.ThreadResult;
|
||||
import net.minestom.server.chat.ChatColor;
|
||||
import net.minestom.server.chat.ChatHoverEvent;
|
||||
import net.minestom.server.chat.ColoredText;
|
||||
import net.minestom.server.chat.RichMessage;
|
||||
import net.minestom.server.entity.*;
|
||||
import net.minestom.server.entity.damage.DamageType;
|
||||
import net.minestom.server.event.entity.EntityAttackEvent;
|
||||
@ -335,12 +333,6 @@ public class PlayerInit {
|
||||
WorldBorder worldBorder = instance.getWorldBorder();
|
||||
worldBorder.setDiameter(30);
|
||||
|
||||
RichMessage richMessage = RichMessage.of(ColoredText.of(ChatColor.RED + "test item"));
|
||||
richMessage.setHoverEvent(ChatHoverEvent.showEntity(player));
|
||||
richMessage.setInsertion("Test Insert");
|
||||
System.out.println(richMessage.toString());
|
||||
player.sendMessage(richMessage);
|
||||
|
||||
//EntityBoat entityBoat = new EntityBoat(player.getPosition());
|
||||
//entityBoat.setInstance(player.getInstance());
|
||||
//entityBoat.addPassenger(player);
|
||||
|
@ -10,8 +10,6 @@ import net.minestom.server.command.CommandSender;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.item.Material;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class SimpleCommand implements CommandProcessor {
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
@ -20,7 +18,7 @@ public class SimpleCommand implements CommandProcessor {
|
||||
|
||||
@Override
|
||||
public String[] getAliases() {
|
||||
return new String[0];
|
||||
return new String[]{"alias"};
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -66,8 +64,8 @@ public class SimpleCommand implements CommandProcessor {
|
||||
final Notification notification = new Notification(ColoredText.of(ChatColor.BRIGHT_GREEN + "Welcome to Minestom!"),
|
||||
FrameType.TASK, Material.APPLE);
|
||||
|
||||
NotificationCenter.send(notification, Arrays.asList(player));
|
||||
NotificationCenter.send(notification, Arrays.asList(player));
|
||||
NotificationCenter.send(notification, player);
|
||||
NotificationCenter.send(notification, player);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -76,4 +74,9 @@ public class SimpleCommand implements CommandProcessor {
|
||||
public boolean hasAccess(Player player) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] onWrite(String text) {
|
||||
return new String[]{"Complete1", "Complete2"};
|
||||
}
|
||||
}
|
||||
|
@ -27,8 +27,9 @@ import java.util.function.Consumer;
|
||||
|
||||
public class CommandManager {
|
||||
|
||||
public static final String COMMAND_PREFIX = "/";
|
||||
|
||||
private boolean running;
|
||||
private String commandPrefix = "/";
|
||||
|
||||
private ConsoleSender consoleSender = new ConsoleSender();
|
||||
|
||||
@ -43,9 +44,9 @@ public class CommandManager {
|
||||
while (running) {
|
||||
if (scanner.hasNext()) {
|
||||
String command = scanner.nextLine();
|
||||
if (!command.startsWith(commandPrefix))
|
||||
if (!command.startsWith(COMMAND_PREFIX))
|
||||
continue;
|
||||
command = command.replaceFirst(commandPrefix, "");
|
||||
command = command.replaceFirst(COMMAND_PREFIX, "");
|
||||
execute(consoleSender, command);
|
||||
}
|
||||
}
|
||||
@ -79,6 +80,23 @@ public class CommandManager {
|
||||
*/
|
||||
public void register(CommandProcessor commandProcessor) {
|
||||
this.commandProcessorMap.put(commandProcessor.getCommandName().toLowerCase(), commandProcessor);
|
||||
// Register aliases
|
||||
final String[] aliases = commandProcessor.getAliases();
|
||||
if (aliases != null && aliases.length > 0) {
|
||||
for (String alias : aliases) {
|
||||
this.commandProcessorMap.put(alias.toLowerCase(), commandProcessor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the command register by {@link #register(CommandProcessor)}
|
||||
*
|
||||
* @param commandName the command name
|
||||
* @return the command associated with the name, null if not any
|
||||
*/
|
||||
public CommandProcessor getCommandProcessor(String commandName) {
|
||||
return commandProcessorMap.get(commandName.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,7 +104,7 @@ public class CommandManager {
|
||||
*
|
||||
* @param sender the sender of the command
|
||||
* @param command the raw command string (without the command prefix)
|
||||
* @return
|
||||
* @return true if the command hadn't been cancelled and has been successful
|
||||
*/
|
||||
public boolean execute(CommandSender sender, String command) {
|
||||
Check.notNull(sender, "Source cannot be null");
|
||||
@ -124,26 +142,6 @@ public class CommandManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current command prefix (what should always be before the command name, ie: '/')
|
||||
*
|
||||
* @return the command prefix
|
||||
*/
|
||||
public String getCommandPrefix() {
|
||||
return commandPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the command prefix
|
||||
* <p>
|
||||
* This field can be changed half-way, but the client auto-completion still expect the '/' char
|
||||
*
|
||||
* @param commandPrefix the new command prefix
|
||||
*/
|
||||
public void setCommandPrefix(String commandPrefix) {
|
||||
this.commandPrefix = commandPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the console sender (which is used as a {@link CommandSender})
|
||||
*
|
||||
@ -219,12 +217,23 @@ public class CommandManager {
|
||||
}
|
||||
|
||||
for (String simpleCommand : simpleCommands) {
|
||||
// TODO server suggestion
|
||||
// Server suggestion (ask_server)
|
||||
{
|
||||
DeclareCommandsPacket.Node tabNode = new DeclareCommandsPacket.Node();
|
||||
tabNode.flags = getFlag(NodeType.ARGUMENT, true, true, true);
|
||||
tabNode.name = "tab_completion";
|
||||
tabNode.parser = "brigadier:string";
|
||||
tabNode.properties = packetWriter -> packetWriter.writeVarInt(2); // Greedy phrase
|
||||
tabNode.children = new int[0];
|
||||
tabNode.suggestionsType = "minecraft:ask_server";
|
||||
|
||||
nodes.add(tabNode);
|
||||
}
|
||||
|
||||
DeclareCommandsPacket.Node literalNode = new DeclareCommandsPacket.Node();
|
||||
literalNode.flags = getFlag(NodeType.LITERAL, true, false, false);
|
||||
literalNode.name = simpleCommand;
|
||||
literalNode.children = new int[0];
|
||||
//literalNode.suggestionsType = "minecraft:ask_server";
|
||||
literalNode.children = new int[]{nodes.size() - 1};
|
||||
|
||||
rootChildren.add(nodes.size());
|
||||
nodes.add(literalNode);
|
||||
@ -272,7 +281,7 @@ public class CommandManager {
|
||||
final boolean isLast = i == arguments.length - 1;
|
||||
|
||||
|
||||
List<DeclareCommandsPacket.Node> argumentNodes = toNodes(argument, isLast);
|
||||
final List<DeclareCommandsPacket.Node> argumentNodes = toNodes(argument, isLast);
|
||||
for (DeclareCommandsPacket.Node node : argumentNodes) {
|
||||
final int childId = nodes.size();
|
||||
|
||||
@ -501,11 +510,11 @@ public class CommandManager {
|
||||
byte result = (byte) type.mask;
|
||||
|
||||
if (executable) {
|
||||
result |= 0x4;
|
||||
result |= 0x04;
|
||||
}
|
||||
|
||||
if (redirect) {
|
||||
result |= 0x8;
|
||||
result |= 0x08;
|
||||
}
|
||||
|
||||
if (suggestionType) {
|
||||
|
@ -43,4 +43,14 @@ public interface CommandProcessor {
|
||||
* @return true if the player has access to the command, false otherwise
|
||||
*/
|
||||
boolean hasAccess(Player player);
|
||||
|
||||
/**
|
||||
* Allow for tab auto completion, this is called everytime the player press a key in the chat
|
||||
*
|
||||
* @param text the whole player text
|
||||
* @return the array containing all the suggestion for the current arg (split " ")
|
||||
*/
|
||||
default String[] onWrite(String text) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityDamageEvent entityDamageEvent = new EntityDamageEvent(type, value, this);
|
||||
EntityDamageEvent entityDamageEvent = new EntityDamageEvent(this, type, value);
|
||||
callCancellableEvent(EntityDamageEvent.class, entityDamageEvent, () -> {
|
||||
float damage = entityDamageEvent.getDamage();
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.minestom.server.event.entity;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.LivingEntity;
|
||||
import net.minestom.server.entity.damage.DamageType;
|
||||
import net.minestom.server.event.CancellableEvent;
|
||||
@ -10,17 +9,28 @@ import net.minestom.server.event.CancellableEvent;
|
||||
*/
|
||||
public class EntityDamageEvent extends CancellableEvent {
|
||||
|
||||
private DamageType damageType;
|
||||
private final LivingEntity entity;
|
||||
private final DamageType damageType;
|
||||
private float damage;
|
||||
private LivingEntity entity;
|
||||
|
||||
public EntityDamageEvent(DamageType damageType, float damage, LivingEntity entity) {
|
||||
public EntityDamageEvent(LivingEntity entity, DamageType damageType, float damage) {
|
||||
this.entity = entity;
|
||||
this.damageType = damageType;
|
||||
this.damage = damage;
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the damaged entity
|
||||
*
|
||||
* @return the damaged entity
|
||||
*/
|
||||
public LivingEntity getEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the damage type
|
||||
*
|
||||
* @return the damage type
|
||||
*/
|
||||
public DamageType getDamageType() {
|
||||
@ -28,6 +38,8 @@ public class EntityDamageEvent extends CancellableEvent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the damage amount
|
||||
*
|
||||
* @return the damage amount
|
||||
*/
|
||||
public float getDamage() {
|
||||
@ -35,13 +47,11 @@ public class EntityDamageEvent extends CancellableEvent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the damage amount
|
||||
*
|
||||
* @param damage the new damage amount
|
||||
*/
|
||||
public void setDamage(float damage) {
|
||||
this.damage = damage;
|
||||
}
|
||||
|
||||
public LivingEntity getEntity() {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ public class ChatMessageListener {
|
||||
public static void listener(ClientChatMessagePacket packet, Player player) {
|
||||
String message = packet.message;
|
||||
|
||||
String cmdPrefix = COMMAND_MANAGER.getCommandPrefix();
|
||||
final String cmdPrefix = CommandManager.COMMAND_PREFIX;
|
||||
if (message.startsWith(cmdPrefix)) {
|
||||
// The message is a command
|
||||
message = message.replaceFirst(cmdPrefix, "");
|
||||
|
@ -1,13 +1,63 @@
|
||||
package net.minestom.server.listener;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.command.CommandManager;
|
||||
import net.minestom.server.command.CommandProcessor;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.network.packet.client.play.ClientTabCompletePacket;
|
||||
import net.minestom.server.network.packet.server.play.TabCompletePacket;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class TabCompleteListener {
|
||||
|
||||
private static final CommandManager COMMAND_MANAGER = MinecraftServer.getCommandManager();
|
||||
|
||||
public static void listener(ClientTabCompletePacket packet, Player player) {
|
||||
// TODO when is it called?
|
||||
System.out.println("text: " + packet.text);
|
||||
final String text = packet.text;
|
||||
|
||||
final String[] split = packet.text.split(Pattern.quote(" "));
|
||||
|
||||
final String commandName = split[0].replaceFirst(CommandManager.COMMAND_PREFIX, "");
|
||||
|
||||
// Tab complete for CommandProcessor
|
||||
final CommandProcessor commandProcessor = COMMAND_MANAGER.getCommandProcessor(commandName);
|
||||
if (commandProcessor != null) {
|
||||
final boolean endSpace = text.endsWith(" ");
|
||||
|
||||
int start;
|
||||
|
||||
if (endSpace) {
|
||||
start = text.length();
|
||||
} else {
|
||||
final String lastArg = split[split.length - 1];
|
||||
start = text.indexOf(lastArg);
|
||||
}
|
||||
|
||||
final String[] matches = commandProcessor.onWrite(text);
|
||||
|
||||
if (matches != null && matches.length > 0) {
|
||||
TabCompletePacket tabCompletePacket = new TabCompletePacket();
|
||||
tabCompletePacket.transactionId = packet.transactionId;
|
||||
tabCompletePacket.start = start;
|
||||
tabCompletePacket.length = 20;
|
||||
|
||||
TabCompletePacket.Match[] matchesArray = new TabCompletePacket.Match[matches.length];
|
||||
for (int i = 0; i < matchesArray.length; i++) {
|
||||
TabCompletePacket.Match match = new TabCompletePacket.Match();
|
||||
match.match = matches[i];
|
||||
matchesArray[i] = match;
|
||||
}
|
||||
|
||||
tabCompletePacket.matches = matchesArray;
|
||||
|
||||
player.getPlayerConnection().sendPacket(tabCompletePacket);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO tab complete for Command (TabArgument)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.network.packet.server.play;
|
||||
|
||||
import net.minestom.server.chat.ColoredText;
|
||||
import net.minestom.server.network.packet.PacketWriter;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
@ -22,7 +23,7 @@ public class TabCompletePacket implements ServerPacket {
|
||||
writer.writeSizedString(match.match);
|
||||
writer.writeBoolean(match.hasTooltip);
|
||||
if (match.hasTooltip)
|
||||
writer.writeSizedString(match.tooltip);
|
||||
writer.writeSizedString(match.tooltip.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +35,7 @@ public class TabCompletePacket implements ServerPacket {
|
||||
public static class Match {
|
||||
public String match;
|
||||
public boolean hasTooltip;
|
||||
public String tooltip; // Chat
|
||||
public ColoredText tooltip;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user