diff --git a/core/src/main/java/mc/core/network/NetStream.java b/core/src/main/java/mc/core/network/NetStream.java index 1709f4e..e82d53c 100644 --- a/core/src/main/java/mc/core/network/NetStream.java +++ b/core/src/main/java/mc/core/network/NetStream.java @@ -7,6 +7,8 @@ package mc.core.network; import lombok.Getter; import lombok.Setter; +import java.util.UUID; + public abstract class NetStream { @Getter @Setter @@ -24,6 +26,7 @@ public abstract class NetStream { public abstract float readFloat(); public abstract double readDouble(); public abstract String readString(); + public abstract UUID readUUID(); public abstract void writeBoolean(boolean value); public abstract void writeByte(int value); @@ -36,6 +39,7 @@ public abstract class NetStream { public abstract void writeFloat(float value); public abstract void writeDouble(double value); public abstract void writeString(String value); + public abstract void writeUUID(UUID uuid); public abstract void skipBytes(int count); } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetStream_p340.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetStream_p340.java index 923b4c3..b1ebdc9 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetStream_p340.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetStream_p340.java @@ -8,6 +8,7 @@ import lombok.extern.slf4j.Slf4j; import mc.core.network.NetStream; import java.nio.charset.StandardCharsets; +import java.util.UUID; @Slf4j public abstract class NetStream_p340 extends NetStream { @@ -70,4 +71,15 @@ public abstract class NetStream_p340 extends NetStream { writeBytes(buf); } } + + @Override + public UUID readUUID() { + return new UUID(readLong(), readLong()); + } + + @Override + public void writeUUID(UUID uuid) { + writeLong(uuid.getMostSignificantBits()); + writeLong(uuid.getLeastSignificantBits()); + } } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/State.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/State.java index 2b7b727..5d2144f 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/State.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/State.java @@ -60,11 +60,13 @@ public enum State { .put(PluginMessagePacket.class, 0x18) .put(KeepAlivePacket.class, 0x1F) .put(JoinGamePacket.class, 0x23) + .put(PlayerAbilitiesPacket.class, 0x2C) + .put(PlayerListItemPacket.class, 0x2E) + .put(PlayerPositionAndLookPacket.class, 0x2F) .put(SpawnPositionPacket.class, 0x46) .put(TimeUpdatePacket.class, 0x47) .put(TitlePacket.class, 0x48) - .put(PlayerAbilitiesPacket.class, 0x2C) - .put(PlayerPositionAndLookPacket.class, 0x2F) + .put(PlayerListHeaderAndFooterPacket.class, 0x4A) .build() ); diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerListHeaderAndFooterPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerListHeaderAndFooterPacket.java new file mode 100644 index 0000000..91ae687 --- /dev/null +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerListHeaderAndFooterPacket.java @@ -0,0 +1,35 @@ +/* + * DmitriyMX + * 2018-07-11 + */ +package mc.core.network.proto_1_12_2.packets; + +import lombok.Setter; +import lombok.ToString; +import mc.core.network.NetStream; +import mc.core.network.SCPacket; +import mc.core.network.proto_1_12_2.serializers.TextSerializer; +import mc.core.text.Text; + +@Setter +@ToString +public class PlayerListHeaderAndFooterPacket implements SCPacket { + // To remove the header/footer, send a empty translatable component: {"translate":""} + private Text header; + private Text footer; + + @Override + public void writeSelf(NetStream netStream) { + if (header == null) { + netStream.writeString("{\"translate\":\"\"}"); + } else { + netStream.writeString(TextSerializer.serialize(header).toString()); + } + + if (footer == null) { + netStream.writeString("{\"translate\":\"\"}"); + } else { + netStream.writeString(TextSerializer.serialize(footer).toString()); + } + } +} diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerListItemPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerListItemPacket.java new file mode 100644 index 0000000..f5f72c4 --- /dev/null +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerListItemPacket.java @@ -0,0 +1,81 @@ +/* + * DmitriyMX + * 2018-07-11 + */ +package mc.core.network.proto_1_12_2.packets; + +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; +import mc.core.network.NetStream; +import mc.core.network.SCPacket; +import mc.core.network.proto_1_12_2.serializers.TextSerializer; +import mc.core.player.PlayerMode; +import mc.core.text.Text; + +import java.util.*; + +@Slf4j +@Getter +@Setter +@ToString +public class PlayerListItemPacket implements SCPacket { + public static final int ACTION_ADD_PLAYER = 0, + ACTION_UPDATE_GAMEMODE = 1, + ACTION_UPDATE_LATENCY = 2, + ACTION_UPDATE_DISPLAY_NAME = 3, + ACTION_REMOVE_PLAYER = 4; + + @Data + @ToString + public static class PlayerData { + private UUID uuid; + private String name; + private Properties properties = new Properties(); + private PlayerMode gameMode; + private int ping; + private boolean hasDisplayName = false; + private Text displayName; + } + + private int action; + private List listPlayers = new ArrayList<>(); + + @Override + public void writeSelf(NetStream netStream) { + netStream.writeVarInt(action); + netStream.writeVarInt(listPlayers.size()); + + for (PlayerData playerData : listPlayers) { + netStream.writeUUID(playerData.uuid); + + if (action == ACTION_ADD_PLAYER) { + netStream.writeString(playerData.name); + netStream.writeVarInt(playerData.properties.size()); + + for (Map.Entry entry : playerData.properties.entrySet()) { + netStream.writeString(entry.getKey().toString()); + netStream.writeString(entry.getValue().toString()); + netStream.writeBoolean(false); // Is Signed + } + } + + if (action == ACTION_ADD_PLAYER || action == ACTION_UPDATE_GAMEMODE) { + netStream.writeVarInt(playerData.gameMode.getId()); + } + + if (action == ACTION_ADD_PLAYER || action == ACTION_UPDATE_LATENCY) { + netStream.writeVarInt(playerData.ping); + } + + if (action == ACTION_ADD_PLAYER || action == ACTION_UPDATE_DISPLAY_NAME) { + netStream.writeBoolean(playerData.hasDisplayName); + if (playerData.hasDisplayName) { + netStream.writeString(TextSerializer.serialize(playerData.displayName).toString()); + } + } + } + } +} diff --git a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/handlers/LoginHandler.java b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/handlers/LoginHandler.java index f31d4ee..ea92f81 100644 --- a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/handlers/LoginHandler.java +++ b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/handlers/LoginHandler.java @@ -16,6 +16,7 @@ import mc.core.player.PlayerManager; import mc.core.player.PlayerMode; import mc.core.text.Text; import mc.core.text.TextColor; +import mc.core.text.TextStyle; import mc.core.world.World; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -86,6 +87,31 @@ public class LoginHandler extends AbstractStateHandler implements LoginStateHand channel.writeAndFlush(pkt4); player.setChannel(new WrapperNetChannel(channel)); + + // Send items + PlayerListItemPacket pkt5 = new PlayerListItemPacket(); + pkt5.setAction(PlayerListItemPacket.ACTION_ADD_PLAYER); + PlayerListItemPacket.PlayerData playerData = new PlayerListItemPacket.PlayerData(); + playerData.setUuid(player.getUUID()); + playerData.setName(player.getName()); + playerData.setGameMode(PlayerMode.CREATIVE); + playerData.setPing(0); + playerData.setHasDisplayName(true); + playerData.setDisplayName(Text.builder() + .append(Text.of(TextColor.RED, TextStyle.BOLD, player.getName().substring(0,1))) + .append(Text.of(TextColor.WHITE, player.getName().substring(1))) + .build() + ); + pkt5.getListPlayers().add(playerData); + channel.writeAndFlush(pkt5); + + // Send header/footer БЕфиЮ list + PlayerListHeaderAndFooterPacket pkt6 = new PlayerListHeaderAndFooterPacket(); + Text text = Text.of(TextColor.GOLD, "============================="); + pkt6.setHeader(text); + pkt6.setFooter(text); + channel.writeAndFlush(pkt6); + playerManager.joinServer(player); } }