diff --git a/src/main/java/net/william278/velocitab/packet/Protocol340Adapter.java b/src/main/java/net/william278/velocitab/packet/Protocol340Adapter.java new file mode 100644 index 0000000..ed4165a --- /dev/null +++ b/src/main/java/net/william278/velocitab/packet/Protocol340Adapter.java @@ -0,0 +1,89 @@ +/* + * This file is part of Velocitab, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package net.william278.velocitab.packet; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +@SuppressWarnings("DuplicatedCode") +public class Protocol340Adapter extends TeamsPacketAdapter { + + public Protocol340Adapter() { + super(Set.of(ProtocolVersion.MINECRAFT_1_12_2)); + } + + @Override + public void decode(ByteBuf byteBuf, UpdateTeamsPacket updateTeamsPacket) { + updateTeamsPacket.teamName(ProtocolUtils.readString(byteBuf)); + UpdateTeamsPacket.UpdateMode mode = UpdateTeamsPacket.UpdateMode.byId(byteBuf.readByte()); + if (mode == UpdateTeamsPacket.UpdateMode.REMOVE_TEAM) { + return; + } + if (mode == UpdateTeamsPacket.UpdateMode.CREATE_TEAM || mode == UpdateTeamsPacket.UpdateMode.UPDATE_INFO) { + updateTeamsPacket.displayName(ProtocolUtils.readString(byteBuf)); + updateTeamsPacket.prefix(ProtocolUtils.readString(byteBuf)); + updateTeamsPacket.suffix(ProtocolUtils.readString(byteBuf)); + updateTeamsPacket.friendlyFlags(UpdateTeamsPacket.FriendlyFlag.fromBitMask(byteBuf.readByte())); + updateTeamsPacket.nameTagVisibility(UpdateTeamsPacket.NameTagVisibility.byId(ProtocolUtils.readString(byteBuf))); + updateTeamsPacket.collisionRule(UpdateTeamsPacket.CollisionRule.byId(ProtocolUtils.readString(byteBuf))); + updateTeamsPacket.color(byteBuf.readByte()); + } + if (mode == UpdateTeamsPacket.UpdateMode.CREATE_TEAM || mode == UpdateTeamsPacket.UpdateMode.ADD_PLAYERS || mode == UpdateTeamsPacket.UpdateMode.REMOVE_PLAYERS) { + int entityCount = ProtocolUtils.readVarInt(byteBuf); + List entities = new ArrayList<>(entityCount); + for (int j = 0; j < entityCount; j++) { + entities.add(ProtocolUtils.readString(byteBuf)); + } + updateTeamsPacket.entities(entities); + } + } + + @Override + public void encode(ByteBuf byteBuf, UpdateTeamsPacket updateTeamsPacket) { + ProtocolUtils.writeString(byteBuf, updateTeamsPacket.teamName().substring(0, Math.min(updateTeamsPacket.teamName().length(), 16))); + UpdateTeamsPacket.UpdateMode mode = updateTeamsPacket.mode(); + byteBuf.writeByte(mode.id()); + if (mode == UpdateTeamsPacket.UpdateMode.REMOVE_TEAM) { + return; + } + if (mode == UpdateTeamsPacket.UpdateMode.CREATE_TEAM || mode == UpdateTeamsPacket.UpdateMode.UPDATE_INFO) { + ProtocolUtils.writeString(byteBuf, updateTeamsPacket.displayName()); + ProtocolUtils.writeString(byteBuf, updateTeamsPacket.prefix()); + ProtocolUtils.writeString(byteBuf, updateTeamsPacket.suffix()); + byteBuf.writeByte(UpdateTeamsPacket.FriendlyFlag.toBitMask(updateTeamsPacket.friendlyFlags())); + ProtocolUtils.writeString(byteBuf, updateTeamsPacket.nameTagVisibility().id()); + ProtocolUtils.writeString(byteBuf, updateTeamsPacket.collisionRule().id()); + byteBuf.writeByte(updateTeamsPacket.color()); + } + if (mode == UpdateTeamsPacket.UpdateMode.CREATE_TEAM || mode == UpdateTeamsPacket.UpdateMode.ADD_PLAYERS || mode == UpdateTeamsPacket.UpdateMode.REMOVE_PLAYERS) { + List entities = updateTeamsPacket.entities(); + ProtocolUtils.writeVarInt(byteBuf, entities != null ? entities.size() : 0); + for (String entity : entities != null ? entities : new ArrayList()) { + ProtocolUtils.writeString(byteBuf, entity); + } + } + } +} diff --git a/src/main/java/net/william278/velocitab/packet/Protocol403Adapter.java b/src/main/java/net/william278/velocitab/packet/Protocol403Adapter.java new file mode 100644 index 0000000..6a3133a --- /dev/null +++ b/src/main/java/net/william278/velocitab/packet/Protocol403Adapter.java @@ -0,0 +1,97 @@ +/* + * This file is part of Velocitab, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package net.william278.velocitab.packet; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +@SuppressWarnings("DuplicatedCode") +public class Protocol403Adapter extends TeamsPacketAdapter { + + public Protocol403Adapter() { + super(Set.of(ProtocolVersion.MINECRAFT_1_13_2, + ProtocolVersion.MINECRAFT_1_14_4, + ProtocolVersion.MINECRAFT_1_15_2, + ProtocolVersion.MINECRAFT_1_16_4, + ProtocolVersion.MINECRAFT_1_17_1, + ProtocolVersion.MINECRAFT_1_18_2, + ProtocolVersion.MINECRAFT_1_19_4, + ProtocolVersion.MINECRAFT_1_20 + )); + } + + @Override + public void decode(ByteBuf byteBuf, UpdateTeamsPacket updateTeamsPacket) { + updateTeamsPacket.teamName(ProtocolUtils.readString(byteBuf)); + UpdateTeamsPacket.UpdateMode mode = UpdateTeamsPacket.UpdateMode.byId(byteBuf.readByte()); + if (mode == UpdateTeamsPacket.UpdateMode.REMOVE_TEAM) { + return; + } + if (mode == UpdateTeamsPacket.UpdateMode.CREATE_TEAM || mode == UpdateTeamsPacket.UpdateMode.UPDATE_INFO) { + updateTeamsPacket.displayName(ProtocolUtils.readString(byteBuf)); + updateTeamsPacket.friendlyFlags(UpdateTeamsPacket.FriendlyFlag.fromBitMask(byteBuf.readByte())); + updateTeamsPacket.nameTagVisibility(UpdateTeamsPacket.NameTagVisibility.byId(ProtocolUtils.readString(byteBuf))); + updateTeamsPacket.collisionRule(UpdateTeamsPacket.CollisionRule.byId(ProtocolUtils.readString(byteBuf))); + updateTeamsPacket.color(byteBuf.readByte()); + updateTeamsPacket.prefix(ProtocolUtils.readString(byteBuf)); + updateTeamsPacket.suffix(ProtocolUtils.readString(byteBuf)); + } + if (mode == UpdateTeamsPacket.UpdateMode.CREATE_TEAM || mode == UpdateTeamsPacket.UpdateMode.ADD_PLAYERS || mode == UpdateTeamsPacket.UpdateMode.REMOVE_PLAYERS) { + int entityCount = ProtocolUtils.readVarInt(byteBuf); + List entities = new ArrayList<>(entityCount); + for (int j = 0; j < entityCount; j++) { + entities.add(ProtocolUtils.readString(byteBuf)); + } + updateTeamsPacket.entities(entities); + } + } + + @Override + public void encode(ByteBuf byteBuf, UpdateTeamsPacket updateTeamsPacket) { + ProtocolUtils.writeString(byteBuf, updateTeamsPacket.teamName()); + UpdateTeamsPacket.UpdateMode mode = updateTeamsPacket.mode(); + byteBuf.writeByte(mode.id()); + if (mode == UpdateTeamsPacket.UpdateMode.REMOVE_TEAM) { + return; + } + if (mode == UpdateTeamsPacket.UpdateMode.CREATE_TEAM || mode == UpdateTeamsPacket.UpdateMode.UPDATE_INFO) { + ProtocolUtils.writeString(byteBuf, getChatString(updateTeamsPacket.displayName())); + byteBuf.writeByte(UpdateTeamsPacket.FriendlyFlag.toBitMask(updateTeamsPacket.friendlyFlags())); + ProtocolUtils.writeString(byteBuf, updateTeamsPacket.nameTagVisibility().id()); + ProtocolUtils.writeString(byteBuf, updateTeamsPacket.collisionRule().id()); + byteBuf.writeByte(updateTeamsPacket.color()); + ProtocolUtils.writeString(byteBuf, getChatString(updateTeamsPacket.prefix())); + ProtocolUtils.writeString(byteBuf, getChatString(updateTeamsPacket.suffix())); + } + if (mode == UpdateTeamsPacket.UpdateMode.CREATE_TEAM || mode == UpdateTeamsPacket.UpdateMode.ADD_PLAYERS || mode == UpdateTeamsPacket.UpdateMode.REMOVE_PLAYERS) { + List entities = updateTeamsPacket.entities(); + ProtocolUtils.writeVarInt(byteBuf, entities != null ? entities.size() : 0); + for (String entity : entities != null ? entities : new ArrayList()) { + ProtocolUtils.writeString(byteBuf, entity); + } + } + } +} diff --git a/src/main/java/net/william278/velocitab/packet/Protocol48Adapter.java b/src/main/java/net/william278/velocitab/packet/Protocol48Adapter.java new file mode 100644 index 0000000..821891e --- /dev/null +++ b/src/main/java/net/william278/velocitab/packet/Protocol48Adapter.java @@ -0,0 +1,87 @@ +/* + * This file is part of Velocitab, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package net.william278.velocitab.packet; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +@SuppressWarnings("DuplicatedCode") +public class Protocol48Adapter extends TeamsPacketAdapter { + + public Protocol48Adapter() { + super(Set.of(ProtocolVersion.MINECRAFT_1_8)); + } + + @Override + public void decode(ByteBuf byteBuf, UpdateTeamsPacket updateTeamsPacket) { + updateTeamsPacket.teamName(ProtocolUtils.readString(byteBuf)); + UpdateTeamsPacket.UpdateMode mode = UpdateTeamsPacket.UpdateMode.byId(byteBuf.readByte()); + if (mode == UpdateTeamsPacket.UpdateMode.REMOVE_TEAM) { + return; + } + if (mode == UpdateTeamsPacket.UpdateMode.CREATE_TEAM || mode == UpdateTeamsPacket.UpdateMode.UPDATE_INFO) { + updateTeamsPacket.displayName(ProtocolUtils.readString(byteBuf)); + updateTeamsPacket.prefix(ProtocolUtils.readString(byteBuf)); + updateTeamsPacket.suffix(ProtocolUtils.readString(byteBuf)); + updateTeamsPacket.friendlyFlags(UpdateTeamsPacket.FriendlyFlag.fromBitMask(byteBuf.readByte())); + updateTeamsPacket.nameTagVisibility(UpdateTeamsPacket.NameTagVisibility.byId(ProtocolUtils.readString(byteBuf))); + updateTeamsPacket.color(byteBuf.readByte()); + } + if (mode == UpdateTeamsPacket.UpdateMode.CREATE_TEAM || mode == UpdateTeamsPacket.UpdateMode.ADD_PLAYERS || mode == UpdateTeamsPacket.UpdateMode.REMOVE_PLAYERS) { + int entityCount = ProtocolUtils.readVarInt(byteBuf); + List entities = new ArrayList<>(entityCount); + for (int j = 0; j < entityCount; j++) { + entities.add(ProtocolUtils.readString(byteBuf)); + } + updateTeamsPacket.entities(entities); + } + } + + @Override + public void encode(ByteBuf byteBuf, UpdateTeamsPacket updateTeamsPacket) { + ProtocolUtils.writeString(byteBuf, updateTeamsPacket.teamName().substring(0, Math.min(updateTeamsPacket.teamName().length(), 16))); + UpdateTeamsPacket.UpdateMode mode = updateTeamsPacket.mode(); + byteBuf.writeByte(mode.id()); + if (mode == UpdateTeamsPacket.UpdateMode.REMOVE_TEAM) { + return; + } + if (mode == UpdateTeamsPacket.UpdateMode.CREATE_TEAM || mode == UpdateTeamsPacket.UpdateMode.UPDATE_INFO) { + ProtocolUtils.writeString(byteBuf, updateTeamsPacket.displayName()); + ProtocolUtils.writeString(byteBuf, updateTeamsPacket.prefix()); + ProtocolUtils.writeString(byteBuf, updateTeamsPacket.suffix()); + byteBuf.writeByte(UpdateTeamsPacket.FriendlyFlag.toBitMask(updateTeamsPacket.friendlyFlags())); + ProtocolUtils.writeString(byteBuf, updateTeamsPacket.nameTagVisibility().id()); + byteBuf.writeByte(updateTeamsPacket.color()); + } + if (mode == UpdateTeamsPacket.UpdateMode.CREATE_TEAM || mode == UpdateTeamsPacket.UpdateMode.ADD_PLAYERS || mode == UpdateTeamsPacket.UpdateMode.REMOVE_PLAYERS) { + List entities = updateTeamsPacket.entities(); + ProtocolUtils.writeVarInt(byteBuf, entities != null ? entities.size() : 0); + for (String entity : entities != null ? entities : new ArrayList()) { + ProtocolUtils.writeString(byteBuf, entity); + } + } + } +} diff --git a/src/main/java/net/william278/velocitab/packet/ScoreboardManager.java b/src/main/java/net/william278/velocitab/packet/ScoreboardManager.java index 84ae471..8fbd338 100644 --- a/src/main/java/net/william278/velocitab/packet/ScoreboardManager.java +++ b/src/main/java/net/william278/velocitab/packet/ScoreboardManager.java @@ -19,6 +19,7 @@ package net.william278.velocitab.packet; +import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.protocol.ProtocolUtils; @@ -38,11 +39,31 @@ public class ScoreboardManager { private final Velocitab plugin; private final Map> createdTeams; private final Map> roleMappings; + private final Set versions; public ScoreboardManager(@NotNull Velocitab velocitab) { this.plugin = velocitab; this.createdTeams = new HashMap<>(); this.roleMappings = new HashMap<>(); + this.versions = new HashSet<>(); + this.registerVersions(); + } + + private void registerVersions() { + versions.add(new Protocol403Adapter()); + versions.add(new Protocol340Adapter()); + versions.add(new Protocol48Adapter()); + } + + public TeamsPacketAdapter getPacketAdapter(ProtocolVersion protocolVersion) { + return versions.stream() + .filter(version -> version.getProtocolVersions().contains(protocolVersion)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("No version found for protocol version " + protocolVersion)); + } + + public void sendProtocolError(String message) { + plugin.log(Level.ERROR, message); } public void resetCache(@NotNull Player player) { @@ -69,7 +90,7 @@ public class ScoreboardManager { return; } if (!createdTeams.getOrDefault(player.getUniqueId(), List.of()).contains(role)) { - dispatchPacket(UpdateTeamsPacket.create(role, playerNames), player); + dispatchPacket(UpdateTeamsPacket.create(plugin, role, playerNames), player); createdTeams.computeIfAbsent(player.getUniqueId(), k -> new ArrayList<>()).add(role); roleMappings.computeIfAbsent(player.getUniqueId(), k -> new HashMap<>()).put(player.getUsername(), role); } else { @@ -77,8 +98,8 @@ public class ScoreboardManager { .entrySet().stream() .filter((entry) -> List.of(playerNames).contains(entry.getKey())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)) - .forEach((playerName, oldRole) -> dispatchPacket(UpdateTeamsPacket.removeFromTeam(oldRole, playerName), player)); - dispatchPacket(UpdateTeamsPacket.addToTeam(role, playerNames), player); + .forEach((playerName, oldRole) -> dispatchPacket(UpdateTeamsPacket.removeFromTeam(plugin, oldRole, playerName), player)); + dispatchPacket(UpdateTeamsPacket.addToTeam(plugin, role, playerNames), player); roleMappings.computeIfAbsent(player.getUniqueId(), k -> new HashMap<>()).put(player.getUsername(), role); } } @@ -101,8 +122,10 @@ public class ScoreboardManager { try { packetRegistration = PacketRegistration.of(UpdateTeamsPacket.class) .direction(ProtocolUtils.Direction.CLIENTBOUND) - .packetSupplier(UpdateTeamsPacket::new) + .packetSupplier(() -> new UpdateTeamsPacket(plugin)) .stateRegistry(StateRegistry.PLAY) + .mapping(0x3E, MINECRAFT_1_8, false) + .mapping(0x44, MINECRAFT_1_12_2, false) .mapping(0x47, MINECRAFT_1_13, false) .mapping(0x4B, MINECRAFT_1_14, false) .mapping(0x4C, MINECRAFT_1_15, false) @@ -117,7 +140,7 @@ public class ScoreboardManager { } public void unregisterPacket() { - if(packetRegistration==null) { + if (packetRegistration == null) { return; } try { diff --git a/src/main/java/net/william278/velocitab/packet/TeamsPacketAdapter.java b/src/main/java/net/william278/velocitab/packet/TeamsPacketAdapter.java new file mode 100644 index 0000000..429d9cc --- /dev/null +++ b/src/main/java/net/william278/velocitab/packet/TeamsPacketAdapter.java @@ -0,0 +1,48 @@ +/* + * This file is part of Velocitab, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package net.william278.velocitab.packet; + +import com.velocitypowered.api.network.ProtocolVersion; +import io.netty.buffer.ByteBuf; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.apache.commons.text.StringEscapeUtils; +import org.jetbrains.annotations.NotNull; + +import java.util.Set; + +@Getter +@RequiredArgsConstructor +public abstract class TeamsPacketAdapter { + + private final Set protocolVersions; + + public abstract void decode(ByteBuf byteBuf, UpdateTeamsPacket updateTeamsPacket); + + public abstract void encode(ByteBuf byteBuf, UpdateTeamsPacket updateTeamsPacket); + + @NotNull + protected String getChatString(@NotNull String string) { + return String.format("{\"text\":\"%s\"}", StringEscapeUtils.escapeJson(string)); + } + + +} diff --git a/src/main/java/net/william278/velocitab/packet/UpdateTeamsPacket.java b/src/main/java/net/william278/velocitab/packet/UpdateTeamsPacket.java index 1d54e94..0ec8d92 100644 --- a/src/main/java/net/william278/velocitab/packet/UpdateTeamsPacket.java +++ b/src/main/java/net/william278/velocitab/packet/UpdateTeamsPacket.java @@ -26,24 +26,25 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; import lombok.*; import lombok.experimental.Accessors; -import org.apache.commons.text.StringEscapeUtils; +import net.william278.velocitab.Velocitab; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; @Getter @Setter @ToString @AllArgsConstructor -@NoArgsConstructor @EqualsAndHashCode(callSuper = false) @Accessors(fluent = true) public class UpdateTeamsPacket implements MinecraftPacket { + private final Velocitab plugin; + private String teamName; private UpdateMode mode; private String displayName; @@ -55,89 +56,77 @@ public class UpdateTeamsPacket implements MinecraftPacket { private String suffix; private List entities; + public UpdateTeamsPacket(Velocitab plugin) { + this.plugin = plugin; + } + @NotNull - protected static UpdateTeamsPacket create(@NotNull String teamName, @NotNull String... teamMembers) { - return new UpdateTeamsPacket() + protected static UpdateTeamsPacket create(@NotNull Velocitab plugin, @NotNull String teamName, @NotNull String... teamMembers) { + return new UpdateTeamsPacket(plugin) .teamName(teamName.length() > 16 ? teamName.substring(0, 16) : teamName) .mode(UpdateMode.CREATE_TEAM) - .displayName(getChatString(teamName)) + .displayName(teamName) .friendlyFlags(List.of(FriendlyFlag.CAN_HURT_FRIENDLY)) .nameTagVisibility(NameTagVisibility.ALWAYS) .collisionRule(CollisionRule.ALWAYS) .color(15) - .prefix(getChatString("")) - .suffix(getChatString("")) + .prefix("") + .suffix("") .entities(Arrays.asList(teamMembers)); } @NotNull - protected static UpdateTeamsPacket addToTeam(@NotNull String teamName, @NotNull String... teamMembers) { - return new UpdateTeamsPacket() + protected static UpdateTeamsPacket addToTeam(@NotNull Velocitab plugin, @NotNull String teamName, @NotNull String... teamMembers) { + return new UpdateTeamsPacket(plugin) .teamName(teamName.length() > 16 ? teamName.substring(0, 16) : teamName) .mode(UpdateMode.ADD_PLAYERS) .entities(Arrays.asList(teamMembers)); } @NotNull - protected static UpdateTeamsPacket removeFromTeam(@NotNull String teamName, @NotNull String... teamMembers) { - return new UpdateTeamsPacket() + protected static UpdateTeamsPacket removeFromTeam(@NotNull Velocitab plugin, @NotNull String teamName, @NotNull String... teamMembers) { + return new UpdateTeamsPacket(plugin) .teamName(teamName.length() > 16 ? teamName.substring(0, 16) : teamName) .mode(UpdateMode.REMOVE_PLAYERS) .entities(Arrays.asList(teamMembers)); } - @NotNull - private static String getChatString(@NotNull String string) { - return "{\"text\":\"" + StringEscapeUtils.escapeJson(string) + "\"}"; - } - @Override public void decode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - teamName = ProtocolUtils.readString(byteBuf); - mode = UpdateMode.byId(byteBuf.readByte()); - if (mode == UpdateMode.REMOVE_TEAM) { + Optional scoreboardManagerOptional = plugin.getScoreboardManager(); + + if (scoreboardManagerOptional.isEmpty()) { return; } - if (mode == UpdateMode.CREATE_TEAM || mode == UpdateMode.UPDATE_INFO) { - displayName = ProtocolUtils.readString(byteBuf); - friendlyFlags = FriendlyFlag.fromBitMask(byteBuf.readByte()); - nameTagVisibility = NameTagVisibility.byId(ProtocolUtils.readString(byteBuf)); - collisionRule = CollisionRule.byId(ProtocolUtils.readString(byteBuf)); - color = byteBuf.readByte(); - prefix = ProtocolUtils.readString(byteBuf); - suffix = ProtocolUtils.readString(byteBuf); - } - if (mode == UpdateMode.CREATE_TEAM || mode == UpdateMode.ADD_PLAYERS || mode == UpdateMode.REMOVE_PLAYERS) { - int entityCount = ProtocolUtils.readVarInt(byteBuf); - entities = new ArrayList<>(entityCount); - for (int j = 0; j < entityCount; j++) { - entities.add(ProtocolUtils.readString(byteBuf)); - } + + ScoreboardManager scoreboardManager = scoreboardManagerOptional.get(); + + if (mode == null) { + scoreboardManager.sendProtocolError("Something went wrong while decoding a UpdateTeamsPacket" + + ", if your server is on 1.8.x and you are using ViaVersion," + + ", please disable 'auto-team' in the config.yml and reload it."); } + + scoreboardManager.getPacketAdapter(protocolVersion).decode(byteBuf, this); } @Override public void encode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - ProtocolUtils.writeString(byteBuf, teamName); - byteBuf.writeByte(mode.id()); - if (mode == UpdateMode.REMOVE_TEAM) { + Optional scoreboardManagerOptional = plugin.getScoreboardManager(); + + if (scoreboardManagerOptional.isEmpty()) { return; } - if (mode == UpdateMode.CREATE_TEAM || mode == UpdateMode.UPDATE_INFO) { - ProtocolUtils.writeString(byteBuf, displayName); - byteBuf.writeByte(FriendlyFlag.toBitMask(friendlyFlags)); - ProtocolUtils.writeString(byteBuf, nameTagVisibility.id()); - ProtocolUtils.writeString(byteBuf, collisionRule.id()); - byteBuf.writeByte(color); - ProtocolUtils.writeString(byteBuf, prefix); - ProtocolUtils.writeString(byteBuf, suffix); - } - if (mode == UpdateMode.CREATE_TEAM || mode == UpdateMode.ADD_PLAYERS || mode == UpdateMode.REMOVE_PLAYERS) { - ProtocolUtils.writeVarInt(byteBuf, entities != null ? entities.size() : 0); - for (String entity : entities != null ? entities : new ArrayList()) { - ProtocolUtils.writeString(byteBuf, entity); - } + + ScoreboardManager scoreboardManager = scoreboardManagerOptional.get(); + + if (mode == null) { + scoreboardManager.sendProtocolError("Something went wrong while encoding a UpdateTeamsPacket" + + ", if your server is on 1.8.x and you are using ViaVersion," + + ", please disable 'auto-team' in the config.yml and reload it."); } + + scoreboardManager.getPacketAdapter(protocolVersion).encode(byteBuf, this); } @Override diff --git a/src/main/java/net/william278/velocitab/tab/PlayerTabList.java b/src/main/java/net/william278/velocitab/tab/PlayerTabList.java index 4b16dc4..a555e0c 100644 --- a/src/main/java/net/william278/velocitab/tab/PlayerTabList.java +++ b/src/main/java/net/william278/velocitab/tab/PlayerTabList.java @@ -67,6 +67,7 @@ public class PlayerTabList { final Player joined = event.getPlayer(); plugin.getScoreboardManager().ifPresent(manager -> manager.resetCache(joined)); + // Remove the player from the tracking list if they are switching servers final RegisteredServer previousServer = event.getPreviousServer(); if (previousServer == null) { @@ -90,6 +91,8 @@ public class PlayerTabList { final TabPlayer tabPlayer = plugin.getTabPlayer(joined); players.add(tabPlayer); + + // Update lists plugin.getServer().getScheduler() .buildTask(plugin, () -> { @@ -111,9 +114,12 @@ public class PlayerTabList { () -> createEntry(player, tabList).thenAccept(tabList::addEntry) ); addPlayerToTabList(player, tabPlayer); + player.sendHeaderAndFooter(this); + } + plugin.getScoreboardManager().ifPresent(manager -> manager.setRoles(joined, playerRoles)); }) .delay(500, TimeUnit.MILLISECONDS)