cn.nukkit.network.protocol.AvailableCommandsPacket Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of powernukkit Show documentation
Show all versions of powernukkit Show documentation
A Minecraft Bedrock Edition server software implementation made in Java from scratch which supports all new features.
package cn.nukkit.network.protocol;
import cn.nukkit.api.PowerNukkitDifference;
import cn.nukkit.command.data.*;
import cn.nukkit.utils.BinaryStream;
import lombok.ToString;
import java.util.*;
import java.util.function.ObjIntConsumer;
import static cn.nukkit.utils.Utils.dynamic;
/**
* @author MagicDroidX (Nukkit Project)
*/
@PowerNukkitDifference(since = "1.4.0.0-PN", info = "Made the arg type constants dynamic because they can change in Minecraft updates")
@ToString
public class AvailableCommandsPacket extends DataPacket {
public static final byte NETWORK_ID = ProtocolInfo.AVAILABLE_COMMANDS_PACKET;
private static final ObjIntConsumer WRITE_BYTE = (s, v) -> s.putByte((byte) v);
private static final ObjIntConsumer WRITE_SHORT = BinaryStream::putLShort;
private static final ObjIntConsumer WRITE_INT = BinaryStream::putLInt;
public static final int ARG_FLAG_VALID = 0x100000;
public static final int ARG_FLAG_ENUM = 0x200000;
public static final int ARG_FLAG_POSTFIX = 0x1000000;
public static final int ARG_FLAG_SOFT_ENUM = 0x4000000;
public static final int ARG_TYPE_INT = dynamic(1);
public static final int ARG_TYPE_FLOAT = dynamic(3);
public static final int ARG_TYPE_VALUE = dynamic(4);
public static final int ARG_TYPE_WILDCARD_INT = dynamic(5);
public static final int ARG_TYPE_OPERATOR = dynamic(6);
public static final int ARG_TYPE_TARGET = dynamic(7);
public static final int ARG_TYPE_WILDCARD_TARGET = dynamic(8);
public static final int ARG_TYPE_FILE_PATH = dynamic(16);
public static final int ARG_TYPE_STRING = dynamic(32);
public static final int ARG_TYPE_BLOCK_POSITION = dynamic(40);
public static final int ARG_TYPE_POSITION = dynamic(41);
public static final int ARG_TYPE_MESSAGE = dynamic(44);
public static final int ARG_TYPE_RAWTEXT = dynamic(46);
public static final int ARG_TYPE_JSON = dynamic(50);
public static final int ARG_TYPE_COMMAND = dynamic(63);
public Map commands;
public final Map> softEnums = new HashMap<>();
@Override
public byte pid() {
return NETWORK_ID;
}
@Override
public void decode() {
}
@Override
public void encode() {
this.reset();
LinkedHashSet enumValuesSet = new LinkedHashSet<>();
LinkedHashSet postFixesSet = new LinkedHashSet<>();
LinkedHashSet enumsSet = new LinkedHashSet<>();
commands.forEach((name, data) -> {
CommandData cmdData = data.versions.get(0);
if (cmdData.aliases != null) {
enumsSet.add(cmdData.aliases);
enumValuesSet.addAll(cmdData.aliases.getValues());
}
for (CommandOverload overload : cmdData.overloads.values()) {
for (CommandParameter parameter : overload.input.parameters) {
if (parameter.enumData != null) {
enumsSet.add(parameter.enumData);
enumValuesSet.addAll(parameter.enumData.getValues());
}
if (parameter.postFix != null) {
postFixesSet.add(parameter.postFix);
}
}
}
});
List enumValues = new ArrayList<>(enumValuesSet);
List enums = new ArrayList<>(enumsSet);
List postFixes = new ArrayList<>(postFixesSet);
this.putUnsignedVarInt(enumValues.size());
enumValues.forEach(this::putString);
this.putUnsignedVarInt(postFixes.size());
postFixes.forEach(this::putString);
ObjIntConsumer indexWriter;
if (enumValues.size() < 256) {
indexWriter = WRITE_BYTE;
} else if (enumValues.size() < 65536) {
indexWriter = WRITE_SHORT;
} else {
indexWriter = WRITE_INT;
}
this.putUnsignedVarInt(enums.size());
enums.forEach((cmdEnum) -> {
putString(cmdEnum.getName());
List values = cmdEnum.getValues();
putUnsignedVarInt(values.size());
for (String val : values) {
int i = enumValues.indexOf(val);
if (i < 0) {
throw new IllegalStateException("Enum value '" + val + "' not found");
}
indexWriter.accept(this, i);
}
});
putUnsignedVarInt(commands.size());
commands.forEach((name, cmdData) -> {
CommandData data = cmdData.versions.get(0);
putString(name);
putString(data.description);
putByte((byte) data.flags);
putByte((byte) data.permission);
putLInt(data.aliases == null ? -1 : enums.indexOf(data.aliases));
putUnsignedVarInt(data.overloads.size());
for (CommandOverload overload : data.overloads.values()) {
putUnsignedVarInt(overload.input.parameters.length);
for (CommandParameter parameter : overload.input.parameters) {
putString(parameter.name);
int type = 0;
if (parameter.postFix != null) {
int i = postFixes.indexOf(parameter.postFix);
if (i < 0) {
throw new IllegalStateException("Postfix '" + parameter.postFix + "' isn't in postfix array");
}
type = ARG_FLAG_POSTFIX | i;
} else {
type |= ARG_FLAG_VALID;
if (parameter.enumData != null) {
type |= ARG_FLAG_ENUM | enums.indexOf(parameter.enumData);
} else {
type |= parameter.type.getId();
}
}
putLInt(type);
putBoolean(parameter.optional);
putByte(parameter.options); // TODO: 19/03/2019 Bit flags. Only first bit is used for GameRules.
}
}
});
this.putUnsignedVarInt(softEnums.size());
softEnums.forEach((name, values) -> {
this.putString(name);
this.putUnsignedVarInt(values.size());
values.forEach(this::putString);
});
this.putUnsignedVarInt(0);
}
}