Allow ask_server tab complete for CommandProcessor

This commit is contained in:
Felix Cravic 2020-08-04 04:21:11 +02:00
parent 47d956c538
commit baccc36ed7
9 changed files with 133 additions and 58 deletions

View File

@ -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);

View File

@ -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"};
}
}

View File

@ -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) {

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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, "");

View File

@ -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)
}

View File

@ -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;
}
}