refactoring: Packets
This commit is contained in:
@@ -1,100 +0,0 @@
|
||||
package mc.protocol;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import mc.protocol.packets.ClientSidePacket;
|
||||
import mc.protocol.packets.Packet;
|
||||
import mc.protocol.packets.KeepAlivePacket;
|
||||
import mc.protocol.packets.ServerSidePacket;
|
||||
import mc.protocol.packets.client.*;
|
||||
import mc.protocol.packets.server.*;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public enum State {
|
||||
|
||||
HANDSHAKING(-1,
|
||||
// client side
|
||||
Map.of(0x00, HandshakePacket.class)
|
||||
),
|
||||
STATUS(1,
|
||||
// client side
|
||||
Map.of(
|
||||
0x00, StatusServerRequestPacket.class,
|
||||
0x01, KeepAlivePacket.class
|
||||
),
|
||||
// server side
|
||||
Map.of(
|
||||
StatusServerResponse.class, 0x00,
|
||||
KeepAlivePacket.class, 0x01
|
||||
)
|
||||
),
|
||||
LOGIN(2,
|
||||
// server bound
|
||||
Map.of(0x00, LoginStartPacket.class),
|
||||
// client bound
|
||||
Map.of(
|
||||
DisconnectPacket.class, 0x00,
|
||||
LoginSuccessPacket.class, 0x02
|
||||
)
|
||||
),
|
||||
PLAY(3,
|
||||
// server bound
|
||||
Map.of(
|
||||
0x00, TeleportConfirmPacket.class,
|
||||
0x04, ClientSettingsPacket.class,
|
||||
0x09, PluginMessagePacket.class,
|
||||
0x0B, KeepAlivePacket.class,
|
||||
0x0D, PlayerPositionPacket.class,
|
||||
0x0E, CPlayerPositionAndLookPacket.class,
|
||||
0x0F, PlayerLookPacket.class,
|
||||
0x15, EntityActionPacket.class
|
||||
),
|
||||
// client bound
|
||||
Map.of(
|
||||
KeepAlivePacket.class, 0x1F,
|
||||
ChunkDataPacket.class, 0x20,
|
||||
JoinGamePacket.class, 0x23,
|
||||
PlayerAbilitiesPacket.class,0x2C,
|
||||
SPlayerPositionAndLookPacket.class, 0x2F,
|
||||
SpawnPositionPacket.class, 0x46
|
||||
)
|
||||
);
|
||||
|
||||
@Nullable
|
||||
public static State getById(int id) {
|
||||
for (State state : State.values()) {
|
||||
if (state.id == id) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final int id;
|
||||
|
||||
@Getter
|
||||
private final Map<Integer, Class<? extends ClientSidePacket>> clientSidePackets;
|
||||
private final Map<Class<? extends ServerSidePacket>, Integer> serverSidePackets;
|
||||
|
||||
State(int id, Map<Integer, Class<? extends ClientSidePacket>> clientSidePackets) {
|
||||
this.id = id;
|
||||
this.clientSidePackets = clientSidePackets;
|
||||
this.serverSidePackets = Collections.emptyMap();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Class<? extends ClientSidePacket> getClientSidePacketById(int id) {
|
||||
return clientSidePackets == null ? null : clientSidePackets.get(id);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getServerSidePacketId(Class<? extends Packet> clazz) {
|
||||
return serverSidePackets == null ? null : serverSidePackets.get(clazz);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package mc.protocol.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class Location {
|
||||
private double x;
|
||||
private double y;
|
||||
private double z;
|
||||
|
||||
public int getIntX() {
|
||||
return (int) x;
|
||||
}
|
||||
|
||||
public int getIntZ() {
|
||||
return (int) z;
|
||||
}
|
||||
|
||||
public Location toChunkXZ() {
|
||||
return new Location(this.getIntX() >> 4, 0d, this.getIntZ() >> 4);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package mc.protocol.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class Look {
|
||||
private float yaw;
|
||||
private float pitch;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package mc.protocol.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import mc.protocol.model.text.Text;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Accessors(fluent = true)
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class ServerInfo {
|
||||
|
||||
private final Version version = new Version();
|
||||
private final Players players = new Players();
|
||||
|
||||
private Text description;
|
||||
private String favicon;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public static class Version {
|
||||
private String name;
|
||||
private int protocol;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public static class Players {
|
||||
private int max;
|
||||
private int online;
|
||||
private List<SamplePlayer> sample;
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
public static class SamplePlayer {
|
||||
private final String id;
|
||||
private final String name;
|
||||
}
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
package mc.protocol.model.text;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Accessors(fluent = true)
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class Text {
|
||||
|
||||
private TextColor color;
|
||||
private TextStyle style;
|
||||
private String content;
|
||||
private List<Text> children;
|
||||
|
||||
public static Text of(String string) {
|
||||
return new Text(null, null, string, null);
|
||||
}
|
||||
|
||||
public static Text of(TextColor color, String string) {
|
||||
return new Text(color, null, string, null);
|
||||
}
|
||||
|
||||
public static Text of(TextStyle style, String string) {
|
||||
return new Text(null, style, string, null);
|
||||
}
|
||||
|
||||
public static Text of(TextColor color, TextStyle style, String string) {
|
||||
return new Text(color, style, string, null);
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
@NoArgsConstructor
|
||||
@ToString
|
||||
public static class Builder {
|
||||
|
||||
@Getter(onMethod = @__(@Nullable))
|
||||
private StringBuilder contentBuilder;
|
||||
private TextStyle.Builder styleBuilder;
|
||||
private TextColor color;
|
||||
private List<Text> children;
|
||||
|
||||
public Builder append(char content) {
|
||||
if (this.contentBuilder == null) {
|
||||
this.contentBuilder = new StringBuilder();
|
||||
}
|
||||
|
||||
this.contentBuilder.append(content);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder append(String content) {
|
||||
if (this.contentBuilder == null) {
|
||||
this.contentBuilder = new StringBuilder(content);
|
||||
} else {
|
||||
this.contentBuilder.append(content);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder append(Text text) {
|
||||
if (children == null) {
|
||||
children = new ArrayList<>();
|
||||
}
|
||||
|
||||
children.add(text);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder style(TextStyle style) {
|
||||
//@formatter:off
|
||||
if (style.bold() != null) bold(style.bold());
|
||||
if (style.italic() != null) italic(style.italic());
|
||||
if (style.underline() != null) underline(style.underline());
|
||||
if (style.strikethrough() != null) strikethrough(style.strikethrough());
|
||||
if (style.obfuscated() != null) obfuscated(style.obfuscated());
|
||||
//@formatter:on
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder color(TextColor color) {
|
||||
this.color = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder bold(Boolean bold) {
|
||||
if (this.styleBuilder == null) {
|
||||
this.styleBuilder = TextStyle.builder();
|
||||
}
|
||||
|
||||
this.styleBuilder.bold(bold);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder italic(Boolean italic) {
|
||||
if (this.styleBuilder == null) {
|
||||
this.styleBuilder = TextStyle.builder();
|
||||
}
|
||||
|
||||
this.styleBuilder.italic(italic);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder underline(Boolean underline) {
|
||||
if (this.styleBuilder == null) {
|
||||
this.styleBuilder = TextStyle.builder();
|
||||
}
|
||||
|
||||
this.styleBuilder.underline(underline);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder strikethrough(Boolean strikethrough) {
|
||||
if (this.styleBuilder == null) {
|
||||
this.styleBuilder = TextStyle.builder();
|
||||
}
|
||||
|
||||
this.styleBuilder.strikethrough(strikethrough);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder obfuscated(Boolean obfuscated) {
|
||||
if (this.styleBuilder == null) {
|
||||
this.styleBuilder = TextStyle.builder();
|
||||
}
|
||||
|
||||
this.styleBuilder.obfuscated(obfuscated);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Text build() {
|
||||
return new Text(
|
||||
color,
|
||||
styleBuilder == null ? null : styleBuilder.build(),
|
||||
contentBuilder == null ? null : contentBuilder.toString(),
|
||||
children);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package mc.protocol.model.text;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum TextColor {
|
||||
//@formatter:off
|
||||
BLACK ("black", '0'),
|
||||
DARK_BLUE ("dark_blue", '1'),
|
||||
DARK_GREEN ("dark_green", '2'),
|
||||
DARK_AQUA ("dark_aqua", '3'),
|
||||
DARK_RED ("dark_red", '4'),
|
||||
DARK_PUEPLE("dark_purple", '5'),
|
||||
GOLD ("gold", '6'),
|
||||
GRAY ("gray", '7'),
|
||||
DARK_GRAY ("dark_gray", '8'),
|
||||
BLUE ("blue", '9'),
|
||||
GREEN ("green", 'a'),
|
||||
AQUA ("aqua", 'b'),
|
||||
RED ("red", 'c'),
|
||||
PURPLE ("light_purple",'d'),
|
||||
YELLOW ("yellow", 'e'),
|
||||
WHITE ("white", 'f');
|
||||
//@formatter:on
|
||||
|
||||
private final String name;
|
||||
private final char code;
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package mc.protocol.model.text;
|
||||
|
||||
import lombok.*;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Accessors(fluent = true)
|
||||
@Data
|
||||
@SuppressWarnings("java:S1845")
|
||||
public class TextStyle {
|
||||
|
||||
public static final TextStyle BOLD = new TextStyle(true, null, null, null, null);
|
||||
public static final TextStyle ITALIC = new TextStyle(null, true, null, null, null);
|
||||
public static final TextStyle UNDERLINE = new TextStyle(null, null, true, null, null);
|
||||
public static final TextStyle STRIKETHOUGH = new TextStyle(null, null, null, true, null);
|
||||
public static final TextStyle OBFUSCATED = new TextStyle(null, null, null, null, true);
|
||||
|
||||
public static final TextStyle RESET = new TextStyle(false, false, false, false, false);
|
||||
public static final TextStyle NONE = new TextStyle(null, null, null, null, null);
|
||||
|
||||
private Boolean bold;
|
||||
private Boolean italic;
|
||||
private Boolean underline;
|
||||
private Boolean strikethrough;
|
||||
private Boolean obfuscated;
|
||||
|
||||
public static Builder builder() {
|
||||
return new TextStyle.Builder();
|
||||
}
|
||||
|
||||
@NoArgsConstructor
|
||||
@ToString
|
||||
public static class Builder {
|
||||
|
||||
private Boolean bold;
|
||||
private Boolean italic;
|
||||
private Boolean underline;
|
||||
private Boolean strikethrough;
|
||||
private Boolean obfuscated;
|
||||
|
||||
public Builder bold(Boolean bold) {
|
||||
this.bold = bold;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder italic(Boolean italic) {
|
||||
this.italic = italic;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder underline(Boolean underline) {
|
||||
this.underline = underline;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder strikethrough(Boolean strikethrough) {
|
||||
this.strikethrough = strikethrough;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder obfuscated(Boolean obfuscated) {
|
||||
this.obfuscated = obfuscated;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder merge(TextStyle style) {
|
||||
//@formatter:off
|
||||
if (style.bold != null) this.bold = style.bold;
|
||||
if (style.italic != null) this.italic = style.italic;
|
||||
if (style.underline != null) this.underline = style.underline;
|
||||
if (style.strikethrough != null) this.strikethrough = style.strikethrough;
|
||||
if (style.obfuscated != null) this.obfuscated = style.obfuscated;
|
||||
//@formatter:on
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextStyle build() {
|
||||
return new TextStyle(bold, italic, underline, strikethrough, obfuscated);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package mc.protocol.packets;
|
||||
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
|
||||
public abstract class EmptyPacket implements ClientSidePacket, ServerSidePacket {
|
||||
|
||||
@Override
|
||||
public void readSelf(NetByteBuf netByteBuf) {
|
||||
// empty
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSelf(NetByteBuf netByteBuf) {
|
||||
// empty
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivate() {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package mc.protocol.packets;
|
||||
|
||||
import lombok.Data;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
|
||||
/**
|
||||
* Пинг-пакет.
|
||||
*
|
||||
* <p>Эхо-пакет, которым проверяется качество соединения между <b>Клиентом</b> и <b>Сервером</b>.</p>
|
||||
*
|
||||
* <p>По спецификации:</p>
|
||||
* <oi>
|
||||
* <li>если <b>Сервер</b> не ответил <b>Клиенту</b> в течении 20 секунд, <b>Клиент</b> отключается
|
||||
* и выдаёт ошибку <i>"Timed out"</i>.</li>
|
||||
* <li>если <b>Клиент</b> не отвечает <b>Серверу</b> в течении 30 секунд, <b>Сервер</b> отключает <b>Клиента</b>.</li>
|
||||
* </oi>
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |---------|------|------------------------|
|
||||
* | Payload | Long | Любое уникальное число |
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=7368#Keep_Alive">Keep Alive</a>
|
||||
*/
|
||||
@Data
|
||||
public class KeepAlivePacket implements ClientSidePacket, ServerSidePacket {
|
||||
|
||||
private Long payload;
|
||||
|
||||
@Override
|
||||
public void readSelf(NetByteBuf netByteBuf) {
|
||||
payload = netByteBuf.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivate() {
|
||||
this.payload = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSelf(NetByteBuf netByteBuf) {
|
||||
netByteBuf.writeLong(payload);
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package mc.protocol.packets.client;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.model.Location;
|
||||
import mc.protocol.model.Look;
|
||||
import mc.protocol.packets.ClientSidePacket;
|
||||
|
||||
/**
|
||||
* Клиент сообщает о движении и повороте головы Игрока.
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |-----------|---------|------------------------------------------------------------|
|
||||
* | X | Double | Абсолютная позиция по X |
|
||||
* | Y | Double | Абсолютная позиция по Y. |
|
||||
* | | | Имеется ввиду позиция ног. Голова находиться выше на 1.62f |
|
||||
* | Z | Double | Абсолютная позиция по Z |
|
||||
* | Yaw | Float | Абсолютный поворот головы по OX, в градусах |
|
||||
* | Pitch | Float | Абсолютный поворот головы по OY, в градусах |
|
||||
* | On Ground | Boolean | true, если Игрок находится на земле |
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Player_Position_And_Look_.28serverbound.29">Player Position And Look (serverbound)</a>
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
public class CPlayerPositionAndLookPacket implements ClientSidePacket {
|
||||
|
||||
private Location position;
|
||||
private Look look;
|
||||
private boolean onGround;
|
||||
|
||||
@Override
|
||||
public void readSelf(NetByteBuf netByteBuf) {
|
||||
double x = netByteBuf.readDouble();
|
||||
double y = netByteBuf.readDouble();
|
||||
double z = netByteBuf.readDouble();
|
||||
this.position = new Location(x, y, z);
|
||||
|
||||
float yaw = netByteBuf.readFloat();
|
||||
float pitch = netByteBuf.readFloat();
|
||||
this.look = new Look(yaw, pitch);
|
||||
|
||||
this.onGround = netByteBuf.readBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivate() {
|
||||
this.position = null;
|
||||
this.look = null;
|
||||
this.onGround = false;
|
||||
}
|
||||
|
||||
public double getYPositionHead() {
|
||||
return this.position.getY() + 1.62f;
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package mc.protocol.packets.client;
|
||||
|
||||
import lombok.*;
|
||||
import mc.protocol.utils.ChatMode;
|
||||
import mc.protocol.utils.MainHand;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.packets.ClientSidePacket;
|
||||
|
||||
/**
|
||||
* Client settings packet.
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |-------------------- |---------------|---------------------------------------------------|
|
||||
* | Locale | String (16) | например en_gb |
|
||||
* | View Distance | Byte | Дистанция отрисовки со стороны Клиента, в чанках. |
|
||||
* | Chat Mode | VarInt | 0: enabled |
|
||||
* | | | 1: commands only |
|
||||
* | | | 2: hidden |
|
||||
* | | | [1] |
|
||||
* | Chat Colors | Boolean | “Colors” multiplayer setting (???) |
|
||||
* | Displayed Skin Parts | Unsigned Byte | битовая маска отображения скина. См. ниже |
|
||||
* | Main Hand | VarInt | 0: Left |
|
||||
* | | | 1: Right |
|
||||
*
|
||||
* [1] - <a href="https://wiki.vg/index.php?title=Chat&oldid=13165#Processing_chat">Processing chat</a>
|
||||
* </pre>
|
||||
*
|
||||
* <p>Биты "Displayed Skin Parts"</p>
|
||||
* <pre>
|
||||
* Bit 0 (0x01): Плащ (Cape)
|
||||
* Bit 1 (0x02): Рубашка (Jacket)
|
||||
* Bit 2 (0x04): Левый рукав (Left Sleeve)
|
||||
* Bit 3 (0x08): Правый рукав (Right Sleeve)
|
||||
* Bit 4 (0x10): Левая штанина (Left Pants Leg)
|
||||
* Bit 5 (0x20): Правая штанина (Right Pants Leg)
|
||||
* Bit 6 (0x40): Шлем (Hat)
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Client_Settings">Client Settings</a>
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
public class ClientSettingsPacket implements ClientSidePacket {
|
||||
|
||||
private String locale;
|
||||
private int viewDistance;
|
||||
private ChatMode chatMode;
|
||||
private boolean chatColors;
|
||||
@SuppressWarnings("java:S116")
|
||||
private int $displayedSkinPartsBitMask;
|
||||
private MainHand mainHand;
|
||||
|
||||
@Override
|
||||
public void readSelf(NetByteBuf netByteBuf) {
|
||||
this.locale = netByteBuf.readString(16);
|
||||
this.viewDistance = netByteBuf.readByte();
|
||||
this.chatMode = ChatMode.valueById(netByteBuf.readVarInt());
|
||||
this.chatColors = netByteBuf.readBoolean();
|
||||
this.$displayedSkinPartsBitMask = netByteBuf.readUnsignedByte();
|
||||
this.mainHand = MainHand.valueById(netByteBuf.readVarInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivate() {
|
||||
this.locale = null;
|
||||
this.viewDistance = 0;
|
||||
this.chatMode = null;
|
||||
this.chatColors = false;
|
||||
this.$displayedSkinPartsBitMask = 0;
|
||||
this.mainHand = null;
|
||||
}
|
||||
|
||||
public boolean isCapeEnabled() {
|
||||
return ($displayedSkinPartsBitMask & 0x01) > 0;
|
||||
}
|
||||
|
||||
public boolean isJacketEnabled() {
|
||||
return ($displayedSkinPartsBitMask & 0x02) > 0;
|
||||
}
|
||||
|
||||
public boolean isLeftSleeveEnabled() {
|
||||
return ($displayedSkinPartsBitMask & 0x04) > 0;
|
||||
}
|
||||
|
||||
public boolean isRightSleeveEnabled() {
|
||||
return ($displayedSkinPartsBitMask & 0x08) > 0;
|
||||
}
|
||||
|
||||
public boolean isLeftPantsEnabled() {
|
||||
return ($displayedSkinPartsBitMask & 0x10) > 0;
|
||||
}
|
||||
|
||||
public boolean isRightPantsEnabled() {
|
||||
return ($displayedSkinPartsBitMask & 0x20) > 0;
|
||||
}
|
||||
|
||||
public boolean isHatEnabled() {
|
||||
return ($displayedSkinPartsBitMask & 0x40) > 0;
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package mc.protocol.packets.client;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.packets.ClientSidePacket;
|
||||
import mc.protocol.utils.EntityActionAction;
|
||||
|
||||
/**
|
||||
* Entity Action packet.
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |------------|--------|-------------------------------------------|
|
||||
* | Entity ID | VarInt | ID игрока |
|
||||
* | Action ID | VarInt | ID действия |
|
||||
* | Jump Boost | VarInt | Используется только при "Action ID" = 5. |
|
||||
* | | | В этом случае значение будет от 0 до 100. |
|
||||
* | | | В остальных случаях значение 0. |
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Entity_Action" target="_top">Entity Action</a>
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
public class EntityActionPacket implements ClientSidePacket {
|
||||
|
||||
private Integer entityId;
|
||||
private EntityActionAction action;
|
||||
private Integer jumpBoost;
|
||||
|
||||
@Override
|
||||
public void readSelf(NetByteBuf netByteBuf) {
|
||||
this.entityId = netByteBuf.readVarInt();
|
||||
int actionId = netByteBuf.readVarInt();
|
||||
this.jumpBoost = netByteBuf.readVarInt();
|
||||
|
||||
this.action = EntityActionAction.valueOfCode(actionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivate() {
|
||||
this.entityId = null;
|
||||
this.action = null;
|
||||
this.jumpBoost = null;
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package mc.protocol.packets.client;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import mc.protocol.State;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.packets.ClientSidePacket;
|
||||
|
||||
/**
|
||||
* Handshake packet.
|
||||
*
|
||||
* <p>Данный пакет заставляет сервер переключить текущий {@link State}</p>
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |------------------|----------------|----------------------------------------------|
|
||||
* | Protocol version | VarInt | Версия протокола [1] |
|
||||
* | Server address | Stirng | Hostname или IP |
|
||||
* | Server port | Unsigned Short | Порт сервера |
|
||||
* | Next stage | VarInt | ID State на который необходимо переключиться |
|
||||
*
|
||||
* [1] - <a href="https://wiki.vg/Protocol_version_numbers" target="_top">Protocol version numbers</a>
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=7368#Handshake" target="_top">Handshake</a>
|
||||
* @see State
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
public class HandshakePacket implements ClientSidePacket {
|
||||
|
||||
private int protocolVersion;
|
||||
private String host;
|
||||
private int port;
|
||||
private State nextState;
|
||||
|
||||
@Override
|
||||
public void readSelf(NetByteBuf netByteBuf) {
|
||||
protocolVersion = netByteBuf.readVarInt();
|
||||
host = netByteBuf.readString(255);
|
||||
port = netByteBuf.readUnsignedShort();
|
||||
nextState = State.getById(netByteBuf.readVarInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivate() {
|
||||
this.protocolVersion = 0;
|
||||
this.host = null;
|
||||
this.port = 0;
|
||||
this.nextState = null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package mc.protocol.packets.client;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.packets.ClientSidePacket;
|
||||
|
||||
/**
|
||||
* Login start packet.
|
||||
*
|
||||
* <p>Начало авторизации.</p>
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |-------|--------|------------------|
|
||||
* | Name | String | Имя/Логин игрока |
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=7368#Login_Start" target="_top">Login start</a>
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
public class LoginStartPacket implements ClientSidePacket {
|
||||
|
||||
private String name;
|
||||
|
||||
@Override
|
||||
public void readSelf(NetByteBuf netByteBuf) {
|
||||
this.name = netByteBuf.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivate() {
|
||||
this.name = null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package mc.protocol.packets.client;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.model.Look;
|
||||
import mc.protocol.packets.ClientSidePacket;
|
||||
|
||||
/**
|
||||
* Клиент сообщает о повороте головы Игрока.
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |-----------|---------|---------------------------------------------|
|
||||
* | Yaw | Float | Абсолютный поворот головы по OX, в градусах |
|
||||
* | Pitch | Float | Абсолютный поворот головы по OY, в градусах |
|
||||
* | On Ground | Boolean | true, если Игрок находится на земле |
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Player_Look">Player Look</a>
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
public class PlayerLookPacket implements ClientSidePacket {
|
||||
|
||||
private Look look;
|
||||
private boolean onGround;
|
||||
|
||||
@Override
|
||||
public void readSelf(NetByteBuf netByteBuf) {
|
||||
float yaw = netByteBuf.readFloat();
|
||||
float pitch = netByteBuf.readFloat();
|
||||
this.look = new Look(yaw, pitch);
|
||||
|
||||
this.onGround = netByteBuf.readBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivate() {
|
||||
this.look = null;
|
||||
this.onGround = false;
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package mc.protocol.packets.client;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.model.Location;
|
||||
import mc.protocol.packets.ClientSidePacket;
|
||||
|
||||
/**
|
||||
* Клиент сообщает о движении Игрока.
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |-----------|---------|-------------------------------------|
|
||||
* | X | Double | Абсолютная позиция по X |
|
||||
* | Feet Y | Double | Абсолютная позиция ног по Y. |
|
||||
* | | | Голова находиться выше на 1.62f |
|
||||
* | Z | Double | Абсолютная позиция по Z |
|
||||
* | On Ground | Boolean | true, если Игрок находится на земле |
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Player_Position">Player Position</a>
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
public class PlayerPositionPacket implements ClientSidePacket {
|
||||
|
||||
private Location position;
|
||||
private boolean onGround;
|
||||
|
||||
@Override
|
||||
public void readSelf(NetByteBuf netByteBuf) {
|
||||
double x = netByteBuf.readDouble();
|
||||
double y = netByteBuf.readDouble();
|
||||
double z = netByteBuf.readDouble();
|
||||
this.position = new Location(x, y, z);
|
||||
|
||||
this.onGround = netByteBuf.readBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivate() {
|
||||
this.position = null;
|
||||
this.onGround = false;
|
||||
}
|
||||
|
||||
public double getYPositionHead() {
|
||||
return this.position.getY() + 1.62f;
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package mc.protocol.packets.client;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.packets.ClientSidePacket;
|
||||
|
||||
/**
|
||||
* Plugin Message packet.
|
||||
*
|
||||
* <p>Канал связи для модов и плагинов.</p>
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |--------------|-------------|------------------|
|
||||
* | Channel name | String (20) | Название канала |
|
||||
* | Data | Byte array | Любые данные |
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Plugin_Message_.28serverbound.29">Plugin Message (serverbound)</a>
|
||||
* @see <a href="https://wiki.vg/index.php?title=Plugin_channels&oldid=14089">Plugin channels</a>
|
||||
* @see <a href="https://dinnerbone.com/blog/2012/01/13/minecraft-plugin-channels-messaging/">Minecraft Plugin Channels + Messaging</a>
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
public class PluginMessagePacket implements ClientSidePacket {
|
||||
|
||||
private String channelName;
|
||||
private byte[] rawData;
|
||||
|
||||
@Override
|
||||
public void readSelf(NetByteBuf netByteBuf) {
|
||||
this.channelName = netByteBuf.readString(20);
|
||||
this.rawData = new byte[netByteBuf.readableBytes()];
|
||||
netByteBuf.readBytes(this.rawData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivate() {
|
||||
this.channelName = null;
|
||||
this.rawData = null;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package mc.protocol.packets.client;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import mc.protocol.packets.EmptyPacket;
|
||||
|
||||
/**
|
||||
* Status server packet, request.
|
||||
*
|
||||
* <p>Клиент запрашивает получение информации о сервере</p>
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@ToString
|
||||
public class StatusServerRequestPacket extends EmptyPacket {
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package mc.protocol.packets.client;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.packets.ClientSidePacket;
|
||||
import mc.protocol.packets.server.SPlayerPositionAndLookPacket;
|
||||
|
||||
/**
|
||||
* Teleport сonfirm packet.
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |-------------|--------|-----------------------------------------------------------|
|
||||
* | Teleport ID | VarInt | ID, который был выдан пакетом {@link SPlayerPositionAndLookPacket} |
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=7368#Login_Start" target="_top">Login start</a>
|
||||
* @see SPlayerPositionAndLookPacket
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
public class TeleportConfirmPacket implements ClientSidePacket {
|
||||
|
||||
private int teleportId;
|
||||
|
||||
@Override
|
||||
public void readSelf(NetByteBuf netByteBuf) {
|
||||
this.teleportId = netByteBuf.readVarInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivate() {
|
||||
this.teleportId = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
package mc.protocol.packets.server;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import lombok.Data;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.packets.ServerSidePacket;
|
||||
|
||||
/**
|
||||
* Данные чанка.
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |--------------------------|------------- |------------------------------------------------------------------------------------|
|
||||
* | Chunk X | Integer | Координаты чанка (координата блока, делённая на 16, округленная в меньшую сторону) |
|
||||
* | Chunk Z | Integer | Координаты чанка (координата блока, делённая на 16, округленная в меньшую сторону) |
|
||||
* | Is Full chunk | Boolean | См. Chunk Format |
|
||||
* | Available Sections | VarInt | Битовая маска, где каждый бит - это часть чанка (0-15) |
|
||||
* | Size of Data | VarInt | Размер поля "Data" |
|
||||
* | Data | Byte array | Данные чанка. См. Chunk Format |
|
||||
* | Number of block entities | VarInt | Количество элементов в поле "Block entities" |
|
||||
* | Block entities | Array of NBT | Все сущности в чанке |
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Chunk_Data">Chunk Data</a>
|
||||
* @see <a href="https://wiki.vg/index.php?title=Chunk_Format&oldid=14135">Chunk Format</a>
|
||||
*/
|
||||
@Data
|
||||
public class ChunkDataPacket implements ServerSidePacket {
|
||||
|
||||
private static NetByteBuf voidData;
|
||||
|
||||
private int x;
|
||||
private int z;
|
||||
|
||||
@SuppressWarnings("java:S125")
|
||||
@Override
|
||||
public void writeSelf(NetByteBuf netByteBuf) {
|
||||
netByteBuf.writeInt(x);
|
||||
netByteBuf.writeInt(z);
|
||||
/* Временное отключение кода
|
||||
netByteBuf.writeBoolean(true); // Is Full chunk
|
||||
netByteBuf.writeVarInt(0b11111111); // Available Sections
|
||||
|
||||
NetByteBuf data = new NetByteBuf(Unpooled.buffer());
|
||||
// <Data>
|
||||
for (int i = 0; i < 16; i++) {
|
||||
NetByteBuf dataBuff = new NetByteBuf(Unpooled.wrappedBuffer(new byte[4096]));
|
||||
NetByteBuf blockLight = new NetByteBuf(Unpooled.wrappedBuffer(new byte[2048]));
|
||||
NetByteBuf skyLight = new NetByteBuf(Unpooled.wrappedBuffer(new byte[2048]));
|
||||
NetByteBuf biomes = new NetByteBuf(Unpooled.wrappedBuffer(new byte[256]));
|
||||
|
||||
// <Chunk Section>
|
||||
data.writeUnsignedByte(13); // Bits Per Block
|
||||
// <Palette>
|
||||
data.writeUnsignedByte(0); // Palette Length (for direct)
|
||||
// <Palette Data/>
|
||||
// </Palette>
|
||||
data.writeVarInt(dataBuff.readableBytes()); // Data Array Length
|
||||
data.writeBytes(dataBuff); // Data Array
|
||||
data.writeBytes(blockLight); // Block Light
|
||||
data.writeBytes(skyLight); // Sky Light
|
||||
// </Chunk Section>
|
||||
data.writeBytes(biomes); // Biomes
|
||||
}
|
||||
// </Data>
|
||||
|
||||
netByteBuf.writeVarInt(data.readableBytes()); // Size of Data
|
||||
netByteBuf.writeBytes(data); // Data
|
||||
netByteBuf.writeVarInt(0); // Number of block entities
|
||||
// write NBT's
|
||||
*/
|
||||
|
||||
netByteBuf.writeBytes(voidData);
|
||||
|
||||
voidData.resetReaderIndex();
|
||||
voidData.resetWriterIndex();
|
||||
}
|
||||
|
||||
static {
|
||||
voidData = new NetByteBuf(Unpooled.buffer());
|
||||
voidData.writeBoolean(true); // Is Full chunk
|
||||
voidData.writeVarInt(0b11111111); // Available Sections
|
||||
|
||||
NetByteBuf data = new NetByteBuf(Unpooled.buffer());
|
||||
for (int i = 0; i < 16; i++) {
|
||||
NetByteBuf dataBuff = new NetByteBuf(Unpooled.wrappedBuffer(new byte[4096]));
|
||||
NetByteBuf blockLight = new NetByteBuf(Unpooled.wrappedBuffer(new byte[2048]));
|
||||
NetByteBuf skyLight = new NetByteBuf(Unpooled.wrappedBuffer(new byte[2048]));
|
||||
NetByteBuf biomes = new NetByteBuf(Unpooled.wrappedBuffer(new byte[256]));
|
||||
|
||||
data.writeUnsignedByte(13);
|
||||
data.writeUnsignedByte(0);
|
||||
data.writeVarInt(dataBuff.readableBytes());
|
||||
data.writeBytes(dataBuff);
|
||||
data.writeBytes(blockLight);
|
||||
data.writeBytes(skyLight);
|
||||
data.writeBytes(biomes);
|
||||
}
|
||||
|
||||
voidData.writeVarInt(data.readableBytes());
|
||||
voidData.writeBytes(data);
|
||||
voidData.writeVarInt(0);
|
||||
|
||||
voidData.markReaderIndex();
|
||||
voidData.markWriterIndex();
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package mc.protocol.packets.server;
|
||||
|
||||
import lombok.Data;
|
||||
import mc.protocol.State;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.model.text.Text;
|
||||
import mc.protocol.packets.ServerSidePacket;
|
||||
import mc.protocol.serializer.TextSerializer;
|
||||
|
||||
/**
|
||||
* Diconnect packet.
|
||||
*
|
||||
* <p>Отключение клиента сервером с указанием причины.</p>
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |-------------|--------|----------------------------------|
|
||||
* | JSON Reason | String | Причина отключения. Опционально. |
|
||||
* </pre>
|
||||
*
|
||||
* <p>Пример JSON Reason</p>
|
||||
* <pre>
|
||||
* {
|
||||
* "text": "foo"
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=7368#Disconnect_2" target="_top">Disconnect</a>
|
||||
* @see State
|
||||
*/
|
||||
@Data
|
||||
public class DisconnectPacket implements ServerSidePacket {
|
||||
|
||||
/**
|
||||
* Причина отключения.
|
||||
*/
|
||||
private Text reason;
|
||||
|
||||
@Override
|
||||
public void writeSelf(NetByteBuf netByteBuf) {
|
||||
netByteBuf.writeString(TextSerializer.toJsonObject(reason).toString());
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package mc.protocol.packets.server;
|
||||
|
||||
import lombok.Data;
|
||||
import mc.protocol.utils.Difficulty;
|
||||
import mc.protocol.utils.GameMode;
|
||||
import mc.protocol.utils.LevelType;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.packets.ServerSidePacket;
|
||||
|
||||
/**
|
||||
* Join game packet.
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |--------------------|---------------|----------------------------------------------------------------------|
|
||||
* | Entity ID | Integer | ID сущности (игрока) |
|
||||
* | Gamemode | Unsigned Byte | 0: Survival |
|
||||
* | | | 1: Creative |
|
||||
* | | | 2: Adventure |
|
||||
* | | | 3: Spectator |
|
||||
* | | | Bit 3 (0x8) is the hardcore flag. |
|
||||
* | Dimension | Integer | -1: Nether |
|
||||
* | | | 0: Overworld |
|
||||
* | | | 1: End |
|
||||
* | Difficulty | Unsigned Byte | 0: peaceful |
|
||||
* | | | 1: easy |
|
||||
* | | | 2: normal |
|
||||
* | | | 3: hard |
|
||||
* | Max Players | Unsigned Byte | Когда-то использовался клиентом для |
|
||||
* | | | отображения списка игроков. Теперь не используется |
|
||||
* | Level Type | String (16) | Принимает одно из значений: |
|
||||
* | | | default, flat, largeBiomes, amplified, default_1_1 |
|
||||
* | Reduced Debug Info | Boolean | Если true, то Клиент отображает меньше отладочной информации (в F3?) |
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Join_Game">Join Game</a>
|
||||
*/
|
||||
@Data
|
||||
public class JoinGamePacket implements ServerSidePacket {
|
||||
|
||||
private int entityId;
|
||||
private GameMode gameMode;
|
||||
private int dimension;
|
||||
private Difficulty difficulty;
|
||||
private LevelType levelType;
|
||||
private boolean reducedDebugInfo;
|
||||
|
||||
@Override
|
||||
public void writeSelf(NetByteBuf netByteBuf) {
|
||||
netByteBuf.writeInt(entityId);
|
||||
netByteBuf.writeUnsignedByte(gameMode.getId());
|
||||
netByteBuf.writeInt(dimension);
|
||||
netByteBuf.writeUnsignedByte(difficulty.getId());
|
||||
netByteBuf.writeUnsignedByte(0); // Max Players, unused
|
||||
netByteBuf.writeString(levelType.getType());
|
||||
netByteBuf.writeBoolean(reducedDebugInfo);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package mc.protocol.packets.server;
|
||||
|
||||
import lombok.Data;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.packets.ServerSidePacket;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Подтверждение успешного логина.
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |----------|-------------|-------------------------------|
|
||||
* | UUID | String (36) | Уникальный ID игрока |
|
||||
* | Username | String (16) | Имя игрока, выданное сервером |
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Login_Success">Login Success</a>
|
||||
*/
|
||||
@Data
|
||||
public class LoginSuccessPacket implements ServerSidePacket {
|
||||
|
||||
private UUID uuid;
|
||||
private String name;
|
||||
|
||||
@Override
|
||||
public void writeSelf(NetByteBuf netByteBuf) {
|
||||
netByteBuf.writeString(uuid.toString());
|
||||
netByteBuf.writeString(name);
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package mc.protocol.packets.server;
|
||||
|
||||
import lombok.Data;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.packets.ServerSidePacket;
|
||||
|
||||
/**
|
||||
* Характеристики игрока.
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |------------------------------|----------|-----------------------------------------|
|
||||
* | Flags | Byte | Битовая маска флагов. См. ниже значения |
|
||||
* | Flying Speed | Float | Скорость полёта |
|
||||
* | Field of View (FOV) Modifier | Float | Поле зрения |
|
||||
* </pre>
|
||||
*
|
||||
* <p>Флаги "Flags"</p>
|
||||
* <pre>
|
||||
* Bit 0x01 - Неуязвимость (Invulnerable)
|
||||
* Bit 0x02 - В полёте (Flying)
|
||||
* Bit 0x04 - Может летать (Allow Flying)
|
||||
* Bit 0x08 - Creative Mode (Instant Break)
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Player_Abilities_.28clientbound.29">Player Abilities</a>
|
||||
*/
|
||||
@Data
|
||||
public class PlayerAbilitiesPacket implements ServerSidePacket {
|
||||
|
||||
@SuppressWarnings("java:S116")
|
||||
private byte $flags = 0;
|
||||
private float flyingSpeed;
|
||||
private float fieldOfView;
|
||||
|
||||
@Override
|
||||
public void writeSelf(NetByteBuf netByteBuf) {
|
||||
netByteBuf.writeByte(this.$flags);
|
||||
netByteBuf.writeFloat(this.flyingSpeed);
|
||||
netByteBuf.writeFloat(this.fieldOfView);
|
||||
}
|
||||
|
||||
//FIXME использование value значений
|
||||
public void setInvulnerable(boolean value) {
|
||||
this.$flags = (byte) (this.$flags | 0x01);
|
||||
}
|
||||
|
||||
public void setFlying(boolean value) {
|
||||
this.$flags = (byte) (this.$flags | 0x02);
|
||||
}
|
||||
|
||||
public void setCatFly(boolean value) {
|
||||
this.$flags = (byte) (this.$flags | 0x04);
|
||||
}
|
||||
|
||||
public void setCreativeMode(boolean value) {
|
||||
this.$flags = (byte) (this.$flags | 0x08);
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
package mc.protocol.packets.server;
|
||||
|
||||
import lombok.Data;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.model.Location;
|
||||
import mc.protocol.model.Look;
|
||||
import mc.protocol.packets.ServerSidePacket;
|
||||
import mc.protocol.packets.client.TeleportConfirmPacket;
|
||||
|
||||
/**
|
||||
* Установка позиции и угла осмотра Игрока.
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |-------------|--------|-----------------------------------------------------------------------------------|
|
||||
* | X | Double | Абсолютная или относительная позиция по X. Зависит от "Flags" |
|
||||
* | Y | Double | Абсолютная или относительная позиция по Y. Зависит от "Flags" |
|
||||
* | Z | Double | Абсолютная или относительная позиция по Z. Зависит от "Flags" |
|
||||
* | Yaw | Float | Абсолютный или относительный поворот головы по OX, в градусах. Зависит от "Flags" |
|
||||
* | Pitch | Float | Абсолютный или относительный поворот головы по OY, в градусах. Зависит от "Flags" |
|
||||
* | Flags | Byte | Битовая маска значений флагов. См. значения ниже |
|
||||
* | Teleport ID | VarInt | ID для подтверждения клиентом перемещения Игрока |
|
||||
* </pre>
|
||||
*
|
||||
* <p>Значения "Flags"</p>
|
||||
* <pre>
|
||||
* | Field | Bit |
|
||||
* |-------|------|
|
||||
* | X | 0x01 |
|
||||
* | Y | 0x02 |
|
||||
* | Z | 0x04 |
|
||||
* | X_ROT | 0x08 |
|
||||
* | Y_ROT | 0x10 |
|
||||
* </pre>
|
||||
*
|
||||
* <p>Примечание от Dinnerbone про "Flags":</p>
|
||||
* <i>"It's a bitfield, X/Y/Z/Y_ROT/X_ROT. If X is set, the x value is relative and not absolute."</i>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Player_Position_And_Look_.28clientbound.29">Player Position And Look (clientbound)</a>
|
||||
* @see TeleportConfirmPacket
|
||||
*/
|
||||
@Data
|
||||
public class SPlayerPositionAndLookPacket implements ServerSidePacket {
|
||||
|
||||
private Location position;
|
||||
private Look look;
|
||||
@SuppressWarnings("java:S116")
|
||||
private byte $flags = 0;
|
||||
private int teleportId;
|
||||
|
||||
@Override
|
||||
public void writeSelf(NetByteBuf netByteBuf) {
|
||||
netByteBuf.writeDouble(this.position.getX());
|
||||
netByteBuf.writeDouble(this.position.getY());
|
||||
netByteBuf.writeDouble(this.position.getZ());
|
||||
netByteBuf.writeFloat(this.look.getYaw());
|
||||
netByteBuf.writeFloat(this.look.getPitch());
|
||||
netByteBuf.writeByte(this.$flags);
|
||||
netByteBuf.writeVarInt(teleportId);
|
||||
}
|
||||
|
||||
//FIXME использовать value значения
|
||||
public void setFlagX(boolean value) {
|
||||
this.$flags = (byte) (this.$flags | 0x01);
|
||||
}
|
||||
|
||||
public void setFlagY(boolean value) {
|
||||
this.$flags = (byte) (this.$flags | 0x02);
|
||||
}
|
||||
|
||||
public void setFlagZ(boolean value) {
|
||||
this.$flags = (byte) (this.$flags | 0x04);
|
||||
}
|
||||
|
||||
public void setFlagXRot(boolean value) {
|
||||
this.$flags = (byte) (this.$flags | 0x08);
|
||||
}
|
||||
|
||||
public void setFlagYRot(boolean value) {
|
||||
this.$flags = (byte) (this.$flags | 0x10);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package mc.protocol.packets.server;
|
||||
|
||||
import lombok.Data;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.model.Location;
|
||||
import mc.protocol.packets.ServerSidePacket;
|
||||
|
||||
/**
|
||||
* Спавн позиция игрока.
|
||||
*
|
||||
* <p>Используется призаходе игрока на сервер.</p>
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |----------|----------|-----------------------|
|
||||
* | Location | Position | Локация спавна игрока |
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Spawn_Position">Spawn Position</a>
|
||||
*/
|
||||
@Data
|
||||
public class SpawnPositionPacket implements ServerSidePacket {
|
||||
|
||||
private Location spawn;
|
||||
|
||||
@Override
|
||||
public void writeSelf(NetByteBuf netByteBuf) {
|
||||
long spawnSerialized =
|
||||
((long) (floorDouble(spawn.getX()) & 0x3FFFFFF) << 38)
|
||||
| ((long) (floorDouble(spawn.getY()) & 0xFFF) << 26)
|
||||
| (floorDouble(spawn.getZ()) & 0x3FFFFFF);
|
||||
netByteBuf.writeLong(spawnSerialized);
|
||||
}
|
||||
|
||||
private static int floorDouble(double value) {
|
||||
int i = (int) value;
|
||||
return value < (double) i ? i - 1 : i;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package mc.protocol.packets.server;
|
||||
|
||||
import lombok.Data;
|
||||
import mc.protocol.io.NetByteBuf;
|
||||
import mc.protocol.model.ServerInfo;
|
||||
import mc.protocol.packets.ServerSidePacket;
|
||||
import mc.protocol.serializer.ServerInfoSerializer;
|
||||
|
||||
/**
|
||||
* Status server packet, response.
|
||||
*
|
||||
* <p>Информация о сервере</p>
|
||||
*
|
||||
* <p>Структура пакета
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |---------------|--------|-----------------------------------------|
|
||||
* | JSON Response | String | Информация о сервере в JSON формате [1] |
|
||||
*
|
||||
* [1] - <a href="https://wiki.vg/index.php?title=Server_List_Ping&oldid=7555#Response" target="_top">Server List Ping: Response</a>
|
||||
* </pre>
|
||||
*
|
||||
* <p>Пример JSON Response</p>
|
||||
* <pre>
|
||||
* {
|
||||
* "version": {
|
||||
* "name": "1.8.7",
|
||||
* "protocol": 47
|
||||
* },
|
||||
* "players": {
|
||||
* "max": 100,
|
||||
* "online": 5,
|
||||
* "sample": [
|
||||
* {
|
||||
* "name": "thinkofdeath",
|
||||
* "id": "4566e69f-c907-48ee-8d71-d7ba5aa00d20"
|
||||
* }
|
||||
* ]
|
||||
* },
|
||||
* "description": {
|
||||
* "text": "Hello world"
|
||||
* },
|
||||
* "favicon": "data:image/png;base64,<data>"
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p><code>`$.favicon`</code> должен быть формата PNG и размеры 64x64 px</p>
|
||||
*/
|
||||
@Data
|
||||
public class StatusServerResponse implements ServerSidePacket {
|
||||
|
||||
/**
|
||||
* Информация о серере.
|
||||
*/
|
||||
private ServerInfo info;
|
||||
|
||||
@Override
|
||||
public void writeSelf(NetByteBuf netByteBuf) {
|
||||
netByteBuf.writeString(ServerInfoSerializer.toJsonObject(info).toString());
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package mc.protocol.serializer;
|
||||
|
||||
import com.eclipsesource.json.Json;
|
||||
import com.eclipsesource.json.JsonArray;
|
||||
import com.eclipsesource.json.JsonObject;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import mc.protocol.model.ServerInfo;
|
||||
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.stream.Collector;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
@UtilityClass
|
||||
public class ServerInfoSerializer {
|
||||
|
||||
public JsonObject toJsonObject(ServerInfo info) {
|
||||
JsonObject jsonObject = Json.object()
|
||||
.add("version", createVersionObj(info))
|
||||
.add("players", createPlayersObj(info))
|
||||
.add("description", TextSerializer.toJsonObject(info.description()));
|
||||
|
||||
if (info.favicon() != null && !info.favicon().isEmpty()) {
|
||||
jsonObject.add("favicon", info.favicon());
|
||||
}
|
||||
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
private JsonObject createVersionObj(ServerInfo info) {
|
||||
return Json.object()
|
||||
.add("name", info.version().name())
|
||||
.add("protocol", info.version().protocol());
|
||||
}
|
||||
|
||||
private JsonObject createPlayersObj(ServerInfo info) {
|
||||
JsonArray sampleArr = info.players().sample().stream()
|
||||
.map(samplePlayer -> Json.object()
|
||||
.add("name", samplePlayer.name())
|
||||
.add("id", samplePlayer.id()))
|
||||
.collect(Collector.of(Json::array, JsonArray::add, ServerInfoSerializer::jsonArrayAddAll));
|
||||
|
||||
return Json.object()
|
||||
.add("max", info.players().max())
|
||||
.add("online", info.players().online())
|
||||
.add("sample", sampleArr);
|
||||
}
|
||||
|
||||
private static JsonArray jsonArrayAddAll(JsonArray jsonArrayTo, JsonArray jsonArrayFrom) {
|
||||
StreamSupport.stream(
|
||||
Spliterators.spliteratorUnknownSize(jsonArrayFrom.iterator(), Spliterator.ORDERED), false)
|
||||
.forEach(jsonArrayTo::add);
|
||||
return jsonArrayTo;
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
package mc.protocol.serializer;
|
||||
|
||||
import com.eclipsesource.json.Json;
|
||||
import com.eclipsesource.json.JsonArray;
|
||||
import com.eclipsesource.json.JsonObject;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import mc.protocol.model.text.Text;
|
||||
import mc.protocol.model.text.TextColor;
|
||||
import mc.protocol.model.text.TextStyle;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@UtilityClass
|
||||
public class TextSerializer {
|
||||
|
||||
private static final Map<Character, TextStyle> legacyStyleCodes;
|
||||
private static final Map<Character, TextColor> legacyColorCodes;
|
||||
|
||||
public JsonObject toJsonObject(Text text) {
|
||||
JsonObject jsonObject = Json.object();
|
||||
|
||||
if (text.content() != null) {
|
||||
jsonObject.add("text", text.content());
|
||||
}
|
||||
|
||||
if (text.color() != null) {
|
||||
jsonObject.add("color", text.color().getName());
|
||||
}
|
||||
|
||||
if (text.style() != null) {
|
||||
//@formatter:off
|
||||
if (text.style().bold() != null) jsonObject.add("bold", text.style().bold());
|
||||
if (text.style().italic() != null) jsonObject.add("italic", text.style().italic());
|
||||
if (text.style().underline() != null) jsonObject.add("underline", text.style().underline());
|
||||
if (text.style().strikethrough() != null) jsonObject.add("strikethrough", text.style().strikethrough());
|
||||
if (text.style().obfuscated() != null) jsonObject.add("obfuscated", text.style().obfuscated());
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
if (text.children() != null && !text.children().isEmpty()) {
|
||||
JsonArray extra = Json.array();
|
||||
text.children().forEach(child -> extra.add(toJsonObject(child)));
|
||||
jsonObject.add("extra", extra);
|
||||
}
|
||||
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Преобразование строки вида "&4красный" в {@link Text}.
|
||||
*
|
||||
* @param string тест
|
||||
* @return Text
|
||||
*/
|
||||
@SuppressWarnings({"java:S3776", "java:S2583", "java:S135"})
|
||||
public Text fromPlain(String string) {
|
||||
boolean flagSys = false;
|
||||
Text.Builder rootTextBuilder = Text.builder();
|
||||
Text.Builder textBuilder = rootTextBuilder;
|
||||
|
||||
for (char ch : string.toCharArray()) {
|
||||
if (!flagSys) {
|
||||
if ('&' == ch) {
|
||||
flagSys = true;
|
||||
} else {
|
||||
textBuilder.append(ch);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!legacyStyleCodes.containsKey(ch) && !legacyColorCodes.containsKey(ch) && '&' == ch) {
|
||||
textBuilder.append('&');
|
||||
flagSys = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
//noinspection ConstantConditions
|
||||
if (textBuilder.contentBuilder() != null && textBuilder.contentBuilder().length() > 0) {
|
||||
if (textBuilder != rootTextBuilder) {
|
||||
rootTextBuilder.append(textBuilder.build());
|
||||
}
|
||||
textBuilder = Text.builder();
|
||||
}
|
||||
|
||||
if (legacyStyleCodes.containsKey(ch)) {
|
||||
textBuilder.style(legacyStyleCodes.get(ch));
|
||||
} else {
|
||||
textBuilder.color(legacyColorCodes.get(ch));
|
||||
}
|
||||
|
||||
flagSys = false;
|
||||
}
|
||||
|
||||
if (textBuilder != rootTextBuilder) {
|
||||
rootTextBuilder.append(textBuilder.build());
|
||||
}
|
||||
|
||||
return rootTextBuilder.build();
|
||||
}
|
||||
|
||||
static {
|
||||
legacyColorCodes = Map.ofEntries(
|
||||
Map.entry('0', TextColor.BLACK),
|
||||
Map.entry('1', TextColor.DARK_BLUE),
|
||||
Map.entry('2', TextColor.DARK_GREEN),
|
||||
Map.entry('3', TextColor.DARK_AQUA),
|
||||
Map.entry('4', TextColor.DARK_RED),
|
||||
Map.entry('5', TextColor.DARK_PUEPLE),
|
||||
Map.entry('6', TextColor.GOLD),
|
||||
Map.entry('7', TextColor.GRAY),
|
||||
Map.entry('8', TextColor.DARK_GRAY),
|
||||
Map.entry('9', TextColor.BLUE),
|
||||
Map.entry('a', TextColor.GREEN),
|
||||
Map.entry('b', TextColor.AQUA),
|
||||
Map.entry('c', TextColor.RED),
|
||||
Map.entry('d', TextColor.PURPLE),
|
||||
Map.entry('e', TextColor.YELLOW),
|
||||
Map.entry('f', TextColor.WHITE)
|
||||
);
|
||||
|
||||
legacyStyleCodes = Map.of(
|
||||
'k', TextStyle.OBFUSCATED,
|
||||
'l', TextStyle.BOLD,
|
||||
'm', TextStyle.STRIKETHOUGH,
|
||||
'n', TextStyle.UNDERLINE,
|
||||
'o', TextStyle.ITALIC
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package mc.protocol.utils;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public enum ChatMode {
|
||||
FULL,
|
||||
COMMANDS_ONLY,
|
||||
HIDDEN;
|
||||
|
||||
@Nullable
|
||||
public static ChatMode valueById(int id) {
|
||||
// а зачем усложнять?
|
||||
//@formatter:off
|
||||
if (id == 1) return FULL;
|
||||
else if (id == 2) return COMMANDS_ONLY;
|
||||
else if (id == 3) return HIDDEN;
|
||||
else return null;
|
||||
//@formatter:on
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package mc.protocol.utils;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum Difficulty {
|
||||
PEACEFUL(0),
|
||||
EASY(1),
|
||||
NORMAL(2),
|
||||
HARD(3);
|
||||
|
||||
private final int id;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package mc.protocol.utils;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public enum EntityActionAction {
|
||||
START_SNEAKING(0),
|
||||
STOP_SNEAKING(1),
|
||||
LEAVE_BED(2),
|
||||
START_SPRINTING(3),
|
||||
STOP_SPRINTING(4),
|
||||
START_JUMP_WITH_HORSE(5),
|
||||
STOP_JUMP_WITH_HORSE(6),
|
||||
OPEN_HORSE_INVENTORY(7),
|
||||
START_FLYING_WITH_ELYTRA(8);
|
||||
|
||||
@Nullable
|
||||
public static EntityActionAction valueOfCode(int code) {
|
||||
for (EntityActionAction action : EntityActionAction.values()) {
|
||||
if (action.code == code) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final int code;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package mc.protocol.utils;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum GameMode {
|
||||
SURVIVAL(0),
|
||||
CREATIVE(1),
|
||||
ADVENTURE(2),
|
||||
SPECTATOR(3);
|
||||
|
||||
private final int id;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package mc.protocol.utils;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum LevelType {
|
||||
DEFAULT_TYPE("default"),
|
||||
FLAT("flat"),
|
||||
LARGE_BIOMES("largeBiomes"),
|
||||
AMPLIFIED("amplified"),
|
||||
DEFAULT_1_1("default_1_1");
|
||||
|
||||
private final String type;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package mc.protocol.utils;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public enum MainHand {
|
||||
LEFT,
|
||||
RIGHT;
|
||||
|
||||
@Nullable
|
||||
public static MainHand valueById(int id) {
|
||||
// а зачем усложнять?
|
||||
//@formatter:off
|
||||
if (id == 0) return LEFT;
|
||||
else if (id == 1) return RIGHT;
|
||||
else return null;
|
||||
//@formatter:on
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user