diff --git a/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index 271f6fa12..70dcae4fa 100644 --- a/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -60,6 +60,9 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { } } else { // Just forward the packet on. We don't have anything to handle at this time. + if (packet.getClass().getName().contains("Scoreboard")) { + System.out.println(packet); + } connection.getProxyPlayer().getConnection().write(packet); } } diff --git a/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 4ce8953a0..4a1c9db37 100644 --- a/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -3,6 +3,7 @@ package com.velocitypowered.proxy.connection.client; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.backend.ServerConnection; import com.velocitypowered.proxy.data.ServerInfo; +import com.velocitypowered.proxy.data.scoreboard.Scoreboard; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.packets.*; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; @@ -34,6 +35,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { private final Set clientPluginMsgChannels = new HashSet<>(); private PluginMessage brandMessage; private int currentDimension; + private Scoreboard serverScoreboard = new Scoreboard(); public ClientPlaySessionHandler(ConnectedPlayer player) { this.player = player; diff --git a/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index fb0ed5498..033665005 100644 --- a/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -64,6 +64,14 @@ public enum StateRegistry { map(0x33, MINECRAFT_1_11), map(0x34, MINECRAFT_1_12), map(0x35, MINECRAFT_1_12_2)); + CLIENTBOUND.register(ScoreboardDisplay.class, ScoreboardDisplay::new, + map(0x3B, MINECRAFT_1_12_2)); + CLIENTBOUND.register(ScoreboardObjective.class, ScoreboardObjective::new, + map(0x42, MINECRAFT_1_12_2)); + CLIENTBOUND.register(ScoreboardTeam.class, ScoreboardTeam::new, + map(0x44, MINECRAFT_1_12_2)); + CLIENTBOUND.register(ScoreboardSetScore.class, ScoreboardSetScore::new, + map(0x45, MINECRAFT_1_12_2)); } }, LOGIN { diff --git a/src/main/java/com/velocitypowered/proxy/protocol/packets/ScoreboardDisplay.java b/src/main/java/com/velocitypowered/proxy/protocol/packets/ScoreboardDisplay.java new file mode 100644 index 000000000..1abff8745 --- /dev/null +++ b/src/main/java/com/velocitypowered/proxy/protocol/packets/ScoreboardDisplay.java @@ -0,0 +1,47 @@ +package com.velocitypowered.proxy.protocol.packets; + +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolConstants; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +public class ScoreboardDisplay implements MinecraftPacket { + private byte position; + private String displayName; + + public byte getPosition() { + return position; + } + + public void setPosition(byte position) { + this.position = position; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + @Override + public String toString() { + return "ScoreboardDisplay{" + + "position=" + position + + ", displayName='" + displayName + '\'' + + '}'; + } + + @Override + public void decode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { + this.position = buf.readByte(); + this.displayName = ProtocolUtils.readString(buf, 16); + } + + @Override + public void encode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { + buf.writeByte(position); + ProtocolUtils.writeString(buf, displayName); + } +} diff --git a/src/main/java/com/velocitypowered/proxy/protocol/packets/ScoreboardObjective.java b/src/main/java/com/velocitypowered/proxy/protocol/packets/ScoreboardObjective.java new file mode 100644 index 000000000..3ada51f83 --- /dev/null +++ b/src/main/java/com/velocitypowered/proxy/protocol/packets/ScoreboardObjective.java @@ -0,0 +1,75 @@ +package com.velocitypowered.proxy.protocol.packets; + +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolConstants; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +public class ScoreboardObjective implements MinecraftPacket { + private String id; + private byte mode; + private String displayName; + private String type; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public byte getMode() { + return mode; + } + + public void setMode(byte mode) { + this.mode = mode; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + @Override + public String toString() { + return "ScoreboardObjective{" + + "id='" + id + '\'' + + ", mode=" + mode + + ", displayName='" + displayName + '\'' + + ", type='" + type + '\'' + + '}'; + } + + @Override + public void decode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { + this.id = ProtocolUtils.readString(buf, 16); + this.mode = buf.readByte(); + if (this.mode != 1) { + this.displayName = ProtocolUtils.readString(buf, 32); + this.type = ProtocolUtils.readString(buf, 16); + } + } + + @Override + public void encode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { + ProtocolUtils.writeString(buf, id); + buf.writeByte(mode); + if (this.mode != 1) { + ProtocolUtils.writeString(buf, displayName); + ProtocolUtils.writeString(buf, type); + } + } +} diff --git a/src/main/java/com/velocitypowered/proxy/protocol/packets/ScoreboardSetScore.java b/src/main/java/com/velocitypowered/proxy/protocol/packets/ScoreboardSetScore.java new file mode 100644 index 000000000..8c553245d --- /dev/null +++ b/src/main/java/com/velocitypowered/proxy/protocol/packets/ScoreboardSetScore.java @@ -0,0 +1,75 @@ +package com.velocitypowered.proxy.protocol.packets; + +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolConstants; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +public class ScoreboardSetScore implements MinecraftPacket { + private String entity; + private byte action; + private String objective; + private int value; + + public String getEntity() { + return entity; + } + + public void setEntity(String entity) { + this.entity = entity; + } + + public byte getAction() { + return action; + } + + public void setAction(byte action) { + this.action = action; + } + + public String getObjective() { + return objective; + } + + public void setObjective(String objective) { + this.objective = objective; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + @Override + public String toString() { + return "ScoreboardSetScore{" + + "entity='" + entity + '\'' + + ", action=" + action + + ", objective='" + objective + '\'' + + ", value=" + value + + '}'; + } + + @Override + public void decode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { + this.entity = ProtocolUtils.readString(buf, 40); + this.action = buf.readByte(); + this.objective = ProtocolUtils.readString(buf, 16); + if (this.action == 0) { + value = ProtocolUtils.readVarInt(buf); + } + } + + @Override + public void encode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { + ProtocolUtils.writeString(buf, entity); + buf.writeByte(action); + ProtocolUtils.writeString(buf, objective); + if (this.action == 0) { + ProtocolUtils.writeVarInt(buf, value); + } + } +} diff --git a/src/main/java/com/velocitypowered/proxy/protocol/packets/ScoreboardTeam.java b/src/main/java/com/velocitypowered/proxy/protocol/packets/ScoreboardTeam.java new file mode 100644 index 000000000..0fd4a6c5e --- /dev/null +++ b/src/main/java/com/velocitypowered/proxy/protocol/packets/ScoreboardTeam.java @@ -0,0 +1,190 @@ +package com.velocitypowered.proxy.protocol.packets; + +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolConstants; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +import java.util.ArrayList; +import java.util.List; + +public class ScoreboardTeam implements MinecraftPacket { + private String id; + private byte mode; + + private String displayName; + private String prefix; + private String suffix; + private byte flags; + private String nameTagVisibility; + private String collisionRule; + private byte color; + private List entities; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public byte getMode() { + return mode; + } + + public void setMode(byte mode) { + this.mode = mode; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public String getSuffix() { + return suffix; + } + + public void setSuffix(String suffix) { + this.suffix = suffix; + } + + public byte getFlags() { + return flags; + } + + public void setFlags(byte flags) { + this.flags = flags; + } + + public String getNameTagVisibility() { + return nameTagVisibility; + } + + public void setNameTagVisibility(String nameTagVisibility) { + this.nameTagVisibility = nameTagVisibility; + } + + public String getCollisionRule() { + return collisionRule; + } + + public void setCollisionRule(String collisionRule) { + this.collisionRule = collisionRule; + } + + public byte getColor() { + return color; + } + + public void setColor(byte color) { + this.color = color; + } + + public List getEntities() { + return entities; + } + + public void setEntities(List entities) { + this.entities = entities; + } + + @Override + public String toString() { + return "ScoreboardTeam{" + + "id='" + id + '\'' + + ", mode=" + mode + + ", displayName='" + displayName + '\'' + + ", prefix='" + prefix + '\'' + + ", suffix='" + suffix + '\'' + + ", flags=" + flags + + ", nameTagVisibility='" + nameTagVisibility + '\'' + + ", collisionRule='" + collisionRule + '\'' + + ", color=" + color + + ", entities=" + entities + + '}'; + } + + @Override + public void decode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { + this.id = ProtocolUtils.readString(buf, 16); + this.mode = buf.readByte(); + + switch (mode) { + case 0: // create + case 2: // update + this.displayName = ProtocolUtils.readString(buf, 32); + this.prefix = ProtocolUtils.readString(buf, 16); + this.suffix = ProtocolUtils.readString(buf, 16); + this.flags = buf.readByte(); + this.nameTagVisibility = ProtocolUtils.readString(buf, 32); + this.collisionRule = ProtocolUtils.readString(buf, 32); + this.color = buf.readByte(); + if (mode == 0) { + this.entities = readEntities(buf); + } + break; + case 1: // remove + break; + case 3: // add player + case 4: // remove player + this.entities = readEntities(buf); + break; + } + } + + @Override + public void encode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { + ProtocolUtils.writeString(buf, id); + buf.writeByte(mode); + switch (mode) { + case 0: // create + case 2: // update + ProtocolUtils.writeString(buf, displayName); + ProtocolUtils.writeString(buf, prefix); + ProtocolUtils.writeString(buf, suffix); + buf.writeByte(flags); + ProtocolUtils.writeString(buf, nameTagVisibility); + ProtocolUtils.writeString(buf, collisionRule); + buf.writeByte(color); + if (mode == 0) { + writeEntities(buf, entities); + } + break; + case 1: + break; + case 3: + case 4: + writeEntities(buf, entities); + break; + } + } + + private static List readEntities(ByteBuf buf) { + List entities = new ArrayList<>(); + int size = ProtocolUtils.readVarInt(buf); + for (int i = 0; i < size; i++) { + entities.add(ProtocolUtils.readString(buf, 40)); + } + return entities; + } + + private static void writeEntities(ByteBuf buf, List entities) { + ProtocolUtils.writeVarInt(buf, entities.size()); + for (String entity : entities) { + ProtocolUtils.writeString(buf, entity); + } + } +}