mirror of https://github.com/Minestom/Minestom.git
151 lines
5.6 KiB
Java
151 lines
5.6 KiB
Java
package net.minestom.server.network.packet.server.play;
|
|
|
|
import net.minestom.server.command.builder.arguments.Argument;
|
|
import net.minestom.server.network.ConnectionState;
|
|
import net.minestom.server.network.NetworkBuffer;
|
|
import net.minestom.server.network.packet.server.ServerPacket;
|
|
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
|
import net.minestom.server.registry.StaticProtocolObject;
|
|
import net.minestom.server.utils.PacketUtils;
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
import java.util.List;
|
|
import java.util.function.Function;
|
|
|
|
import static net.minestom.server.network.NetworkBuffer.*;
|
|
|
|
public record DeclareCommandsPacket(@NotNull List<Node> nodes,
|
|
int rootIndex) implements ServerPacket {
|
|
public DeclareCommandsPacket {
|
|
nodes = List.copyOf(nodes);
|
|
}
|
|
|
|
public DeclareCommandsPacket(@NotNull NetworkBuffer reader) {
|
|
this(reader.readCollection(r -> {
|
|
Node node = new Node();
|
|
node.read(r);
|
|
return node;
|
|
}), reader.read(VAR_INT));
|
|
}
|
|
|
|
@Override
|
|
public void write(@NotNull NetworkBuffer writer) {
|
|
writer.writeCollection(nodes);
|
|
writer.write(VAR_INT, rootIndex);
|
|
}
|
|
|
|
@Override
|
|
public int getId(@NotNull ConnectionState state) {
|
|
return switch (state) {
|
|
case PLAY -> ServerPacketIdentifier.DECLARE_COMMANDS;
|
|
default -> PacketUtils.invalidPacketState(getClass(), state, ConnectionState.PLAY);
|
|
};
|
|
}
|
|
|
|
public static final class Node implements NetworkBuffer.Writer {
|
|
public byte flags;
|
|
public int[] children = new int[0];
|
|
public int redirectedNode; // Only if flags & 0x08
|
|
public String name = ""; // Only for literal and argument
|
|
public String parser; // Only for argument
|
|
public byte[] properties; // Only for argument
|
|
public String suggestionsType = ""; // Only if flags 0x10
|
|
|
|
@Override
|
|
public void write(@NotNull NetworkBuffer writer) {
|
|
writer.write(BYTE, flags);
|
|
|
|
if (children != null && children.length > 262114) {
|
|
throw new RuntimeException("Children length " + children.length + " is bigger than the maximum allowed " + 262114);
|
|
}
|
|
writer.write(VAR_INT_ARRAY, children);
|
|
|
|
if ((flags & 0x08) != 0) {
|
|
writer.write(VAR_INT, redirectedNode);
|
|
}
|
|
|
|
if (isLiteral() || isArgument()) {
|
|
writer.write(STRING, name);
|
|
}
|
|
|
|
if (isArgument()) {
|
|
final int parserId = Argument.CONTAINER.toId(parser);
|
|
writer.write(VAR_INT, parserId);
|
|
if (properties != null) {
|
|
writer.write(RAW_BYTES, properties);
|
|
}
|
|
}
|
|
|
|
if ((flags & 0x10) != 0) {
|
|
writer.write(STRING, suggestionsType);
|
|
}
|
|
}
|
|
|
|
public void read(@NotNull NetworkBuffer reader) {
|
|
flags = reader.read(BYTE);
|
|
children = reader.read(VAR_INT_ARRAY);
|
|
if ((flags & 0x08) != 0) {
|
|
redirectedNode = reader.read(VAR_INT);
|
|
}
|
|
|
|
if (isLiteral() || isArgument()) {
|
|
name = reader.read(STRING);
|
|
}
|
|
|
|
if (isArgument()) {
|
|
final StaticProtocolObject object = Argument.CONTAINER.getId(reader.read(VAR_INT));
|
|
parser = object.name();
|
|
properties = getProperties(reader, parser);
|
|
}
|
|
|
|
if ((flags & 0x10) != 0) {
|
|
suggestionsType = reader.read(STRING);
|
|
}
|
|
}
|
|
|
|
private byte[] getProperties(@NotNull NetworkBuffer reader, String parser) {
|
|
final Function<Function<NetworkBuffer, ?>, byte[]> minMaxExtractor = (via) -> reader.extractBytes((extractor) -> {
|
|
byte flags = extractor.read(BYTE);
|
|
if ((flags & 0x01) == 0x01) {
|
|
via.apply(extractor); // min
|
|
}
|
|
if ((flags & 0x02) == 0x02) {
|
|
via.apply(extractor); // max
|
|
}
|
|
});
|
|
return switch (parser) {
|
|
case "brigadier:double" -> minMaxExtractor.apply(b -> b.read(DOUBLE));
|
|
case "brigadier:integer" -> minMaxExtractor.apply(b -> b.read(INT));
|
|
case "brigadier:float" -> minMaxExtractor.apply(b -> b.read(FLOAT));
|
|
case "brigadier:long" -> minMaxExtractor.apply(b -> b.read(LONG));
|
|
case "brigadier:string" -> reader.extractBytes(b -> b.read(VAR_INT));
|
|
case "minecraft:entity", "minecraft:score_holder" -> reader.extractBytes(b -> b.read(BYTE));
|
|
case "minecraft:range" ->
|
|
reader.extractBytes(b -> b.read(BOOLEAN)); // https://wiki.vg/Command_Data#minecraft:range, looks fishy
|
|
case "minecraft:resource_or_tag", "minecraft:registry" -> reader.extractBytes(b -> b.read(STRING));
|
|
default -> new byte[0]; // unknown
|
|
};
|
|
}
|
|
|
|
private boolean isLiteral() {
|
|
return (flags & 0b1) != 0;
|
|
}
|
|
|
|
private boolean isArgument() {
|
|
return (flags & 0b10) != 0;
|
|
}
|
|
}
|
|
|
|
public static byte getFlag(@NotNull NodeType type, boolean executable, boolean redirect, boolean suggestionType) {
|
|
byte result = (byte) type.ordinal();
|
|
if (executable) result |= 0x04;
|
|
if (redirect) result |= 0x08;
|
|
if (suggestionType) result |= 0x10;
|
|
return result;
|
|
}
|
|
|
|
public enum NodeType {
|
|
ROOT, LITERAL, ARGUMENT, NONE;
|
|
}
|
|
}
|