Compare commits

...
7 Commits
11 changed files with 111 additions and 44 deletions

No files matched your search

+1 -1
View File
@@ -4,7 +4,7 @@ plugins {
allprojects {
group = "me.neznamy"
version = "4.1.5-SNAPSHOT"
version = "4.1.5"
description = "An all-in-one solution that works"
ext.set("id", "tab")
@@ -41,7 +41,7 @@ public class ComponentConverter {
// 1.16+
private Method ChatHexColor_fromRGB;
private Constructor<?> newMinecraftKey;
private Method ResourceLocation_tryParse;
/**
* Constructs new instance and loads all NMS classes, constructors and methods.
@@ -67,13 +67,13 @@ public class ComponentConverter {
}
if (BukkitReflection.getMinorVersion() >= 16) {
Class<?> chatHexColor = BukkitReflection.getClass("network.chat.ChatHexColor", "ChatHexColor");
Class<?> MinecraftKey = BukkitReflection.getClass("resources.MinecraftKey", "MinecraftKey");
Class<?> ResourceLocation = BukkitReflection.getClass("resources.MinecraftKey", "MinecraftKey");
Class<?> chatClickable = BukkitReflection.getClass("network.chat.ChatClickable", "ChatClickable");
Class<?> chatHoverable = BukkitReflection.getClass("network.chat.ChatHoverable", "ChatHoverable");
newMinecraftKey = MinecraftKey.getConstructor(String.class);
ResourceLocation_tryParse = ReflectionUtils.getMethod(ResourceLocation, new String[]{"tryParse", "m_135820_", "a"}, String.class);
ChatHexColor_fromRGB = ReflectionUtils.getOnlyMethod(chatHexColor, chatHexColor, int.class);
newChatModifier = ReflectionUtils.setAccessible(ChatModifier.getDeclaredConstructor(chatHexColor, Boolean.class, Boolean.class, Boolean.class,
Boolean.class, Boolean.class, chatClickable, chatHoverable, String.class, MinecraftKey));
Boolean.class, Boolean.class, chatClickable, chatHoverable, String.class, ResourceLocation));
convertModifier = this::createModifierModern;
} else {
newChatModifier = ChatModifier.getConstructor();
@@ -124,7 +124,7 @@ public class ComponentConverter {
null,
null,
null,
modifier.getFont() == null ? null : newMinecraftKey.newInstance(modifier.getFont())
modifier.getFont() == null ? null : ResourceLocation_tryParse.invoke(null, modifier.getFont())
);
}
@@ -29,10 +29,12 @@ public class BungeeBossBar implements BossBar {
@NotNull
private final Map<UUID, Integer> styles = new HashMap<>();
/** Flag tracking whether boss bars should be frozen or not */
private boolean frozen;
@Override
public void create(@NotNull UUID id, @NotNull String title, float progress, @NotNull BarColor color, @NotNull BarStyle style) {
if (player.getVersion().getMinorVersion() < 9) return;
if (frozen) return; // Server switch
net.md_5.bungee.protocol.packet.BossBar packet = new net.md_5.bungee.protocol.packet.BossBar(id, 0);
packet.setHealth(progress);
packet.setTitle(TabComponent.optimized(title).convert(player.getVersion()));
@@ -46,8 +48,7 @@ public class BungeeBossBar implements BossBar {
@Override
public void update(@NotNull UUID id, @NotNull String title) {
if (player.getVersion().getMinorVersion() < 9) return;
if (frozen) return; // Server switch
net.md_5.bungee.protocol.packet.BossBar packet = new net.md_5.bungee.protocol.packet.BossBar(id, 3);
packet.setTitle(TabComponent.optimized(title).convert(player.getVersion()));
player.sendPacket(packet);
@@ -55,8 +56,7 @@ public class BungeeBossBar implements BossBar {
@Override
public void update(@NotNull UUID id, float progress) {
if (player.getVersion().getMinorVersion() < 9) return;
if (frozen) return; // Server switch
net.md_5.bungee.protocol.packet.BossBar packet = new net.md_5.bungee.protocol.packet.BossBar(id, 2);
packet.setHealth(progress);
player.sendPacket(packet);
@@ -64,8 +64,7 @@ public class BungeeBossBar implements BossBar {
@Override
public void update(@NotNull UUID id, @NotNull BarStyle style) {
if (player.getVersion().getMinorVersion() < 9) return;
if (frozen) return; // Server switch
net.md_5.bungee.protocol.packet.BossBar packet = new net.md_5.bungee.protocol.packet.BossBar(id, 4);
packet.setDivision(style.ordinal());
packet.setColor(colors.get(id));
@@ -76,8 +75,7 @@ public class BungeeBossBar implements BossBar {
@Override
public void update(@NotNull UUID id, @NotNull BarColor color) {
if (player.getVersion().getMinorVersion() < 9) return;
if (frozen) return; // Server switch
net.md_5.bungee.protocol.packet.BossBar packet = new net.md_5.bungee.protocol.packet.BossBar(id, 4);
packet.setDivision(styles.get(id));
packet.setColor(color.ordinal());
@@ -88,11 +86,20 @@ public class BungeeBossBar implements BossBar {
@Override
public void remove(@NotNull UUID id) {
if (player.getVersion().getMinorVersion() < 9) return;
if (frozen) return; // Server switch
player.sendPacket(new net.md_5.bungee.protocol.packet.BossBar(id, 1));
colors.remove(id);
styles.remove(id);
}
}
@Override
public void freeze() {
frozen = true;
}
@Override
public void unfreeze() {
frozen = false;
}
}
@@ -42,10 +42,12 @@ public class BungeeEventListener implements EventListener<ProxiedPlayer>, Listen
TAB tab = TAB.getInstance();
if (tab.isPluginDisabled()) return;
// Avoid 1.20.3 client crash on scoreboard packets, do it sync to prevent packet being sent after event, but before processing
// Avoid 1.20.3+ client crash on scoreboard packets, do it sync to prevent packet being sent after event, but before processing
// Avoid 1.20.5+ client disconnect with "Network Protocol Error"
TabPlayer p = tab.getPlayer(e.getPlayer().getUniqueId());
if (p != null && p.getVersion().getNetworkId() >= ProtocolVersion.V1_20_3.getNetworkId()) {
if (p != null && p.getVersion().getNetworkId() >= ProtocolVersion.V1_20_2.getNetworkId()) {
p.getScoreboard().freeze();
p.getBossBar().freeze();
}
tab.getCPUManager().runTask(() -> {
@@ -237,7 +237,7 @@ public class PlayerList extends TabFeature implements TabListFormatManager, Join
connectedPlayer.getTabList().setAntiOverride(antiOverrideTabList);
updateProperties(connectedPlayer);
if (disableChecker.isDisableConditionMet(connectedPlayer)) {
connectedPlayer.disabledHeaderFooter.set(true);
connectedPlayer.disabledPlayerList.set(true);
return;
}
Runnable r = () -> {
@@ -264,12 +264,12 @@ public class BossBarLine implements BossBar {
public void addPlayer(@NonNull me.neznamy.tab.api.TabPlayer p) {
TabPlayer player = (TabPlayer) p;
if (players.contains(player)) return;
players.add(player);
player.setProperty(textRefresher, propertyTitle, title);
player.setProperty(progressRefresher, propertyProgress, progress);
player.setProperty(colorRefresher, propertyColor, color);
player.setProperty(styleRefresher, propertyStyle, style);
sendToPlayerRaw(player);
players.add(player);
}
@Override
@@ -83,8 +83,11 @@ public class BossBarManagerImpl extends TabFeature implements BossBarManager, Jo
@Override
public void load() {
TAB.getInstance().getPlaceholderManager().registerServerPlaceholder(TabConstants.Placeholder.COUNTDOWN, 100,
() -> TimeUnit.MILLISECONDS.toSeconds(announceEndTime - System.currentTimeMillis()));
TAB.getInstance().getPlaceholderManager().registerServerPlaceholder(TabConstants.Placeholder.COUNTDOWN, 100, () -> {
long seconds = TimeUnit.MILLISECONDS.toSeconds(announceEndTime - System.currentTimeMillis());
if (seconds < 0) return 0;
return seconds;
});
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()) {
onJoin(p);
}
@@ -165,12 +168,11 @@ public class BossBarManagerImpl extends TabFeature implements BossBarManager, Jo
}
}
@Override
public void onLoginPacket(TabPlayer player) {
// Since 1.20.2, Login packet clears BossBars as well
if (player.getVersion().getNetworkId() >= ProtocolVersion.V1_20_2.getNetworkId()) {
player.getBossBar().unfreeze();
for (BossBar bar : lineValues) {
if (bar.containsPlayer(player)) {
((BossBarLine)bar).sendToPlayerRaw(player);
@@ -80,27 +80,27 @@ public abstract class SortingType {
/**
* Compresses a number to ### format, where # is a character symbol representing
* a number in a base of 65536. The first two represent the whole part, the third one decimal part.
* a number in a base of 65534. The first two represent the whole part, the third one decimal part.
* The maximum number it will work properly with is {@link Integer#MAX_VALUE}.
*
* @param number
* Number to convert
* @return 3 characters long String of converted number with a base of 65536.
* @return 3 characters long String of converted number with a base of 65534.
*/
public String compressNumber(double number) {
int wholePart = (int) number;
char decimalChar = (char) ((number - wholePart) * (Character.MAX_VALUE - 1));
int base = Character.MAX_VALUE - 1;
char decimalChar = (char) ((number - wholePart) * base);
// The \ symbol breaks json syntax, skip it (and reduce range) (why is it not being escaped by json writer?)
if (decimalChar >= '\\') decimalChar++;
StringBuilder sb = new StringBuilder();
while (wholePart > 0) {
char digit = (char) (wholePart % (Character.MAX_VALUE - 1));
char digit = (char) (wholePart % base);
if (digit >= '\\') digit++;
sb.append(digit);
wholePart /= Character.MAX_VALUE;
sb.insert(0, digit);
wholePart /= base;
}
sb.reverse();
if (sb.length() == 1) sb.insert(0, (char) 0); // Avoid a single # if number is < 65535
if (sb.length() == 1) sb.insert(0, (char) 0); // Avoid a single # if number is < base
sb.append(decimalChar);
return sb.toString();
}
@@ -74,4 +74,19 @@ public interface BossBar {
* Unique identifier to match the bossbar with other functions
*/
void remove(@NotNull UUID id);
/**
* Freezes the class, not letting any packets through.
*/
default void freeze() {
// Empty by default
}
/**
* Unfreezes the class, enabling it back.
*/
default void unfreeze() {
// Empty by default
}
}
@@ -1,14 +1,17 @@
package me.neznamy.tab.shared.platform.impl;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import me.neznamy.tab.api.bossbar.BarColor;
import me.neznamy.tab.api.bossbar.BarStyle;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.platform.BossBar;
import me.neznamy.tab.shared.platform.TabPlayer;
import me.neznamy.tab.shared.util.ReflectionUtils;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.bossbar.BossBar.Color;
import net.kyori.adventure.bossbar.BossBar.Overlay;
@@ -17,23 +20,25 @@ import org.jetbrains.annotations.NotNull;
/**
* Shared BossBar implementation using Adventure API.
*/
@AllArgsConstructor
@RequiredArgsConstructor
public class AdventureBossBar implements BossBar {
/** Flag tracking whether this implementation is available on the server or not */
@Getter
private static final boolean available = ReflectionUtils.classExists("net.kyori.adventure.bossbar.BossBar");
/** Player this BossBar belongs to */
private final TabPlayer player;
/** BossBars currently visible to the player */
private final Map<UUID, net.kyori.adventure.bossbar.BossBar> bossBars = new HashMap<>();
/** Flag tracking whether boss bars should be frozen or not */
private boolean frozen;
@Override
public void create(@NotNull UUID id, @NotNull String title, float progress, @NotNull BarColor color, @NotNull BarStyle style) {
if (bossBars.containsKey(id)) {
// Can happen on 1.20.2+ on Velocity on server switch
((Audience)player.getPlayer()).hideBossBar(bossBars.get(id));
((Audience)player.getPlayer()).showBossBar(bossBars.get(id));
return;
}
if (frozen) return; // Server switch
net.kyori.adventure.bossbar.BossBar bar = net.kyori.adventure.bossbar.BossBar.bossBar(
TabComponent.optimized(title).convert(player.getVersion()),
progress,
@@ -46,26 +51,42 @@ public class AdventureBossBar implements BossBar {
@Override
public void update(@NotNull UUID id, @NotNull String title) {
if (frozen) return; // Server switch
bossBars.get(id).name(TabComponent.optimized(title).convert(player.getVersion()));
}
@Override
public void update(@NotNull UUID id, float progress) {
if (frozen) return; // Server switch
bossBars.get(id).progress(progress);
}
@Override
public void update(@NotNull UUID id, @NotNull BarStyle style) {
if (frozen) return; // Server switch
bossBars.get(id).overlay(Overlay.valueOf(style.name()));
}
@Override
public void update(@NotNull UUID id, @NotNull BarColor color) {
if (frozen) return; // Server switch
bossBars.get(id).color(Color.valueOf(color.name()));
}
@Override
public void remove(@NotNull UUID id) {
if (frozen) return; // Server switch
((Audience)player.getPlayer()).hideBossBar(bossBars.remove(id));
}
@Override
public void freeze() {
bossBars.clear();
frozen = true;
}
@Override
public void unfreeze() {
frozen = false;
}
}
@@ -1,12 +1,15 @@
package me.neznamy.tab.platforms.velocity;
import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.command.CommandExecuteEvent;
import com.velocitypowered.api.event.command.CommandExecuteEvent.CommandResult;
import com.velocitypowered.api.event.connection.DisconnectEvent;
import com.velocitypowered.api.event.connection.PluginMessageEvent;
import com.velocitypowered.api.event.player.ServerPostConnectEvent;
import com.velocitypowered.api.event.player.ServerPreConnectEvent;
import com.velocitypowered.api.proxy.Player;
import me.neznamy.tab.shared.ProtocolVersion;
import me.neznamy.tab.shared.TabConstants;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.features.bossbar.BossBarManagerImpl;
@@ -32,6 +35,23 @@ public class VelocityEventListener implements EventListener<Player> {
quit(e.getPlayer().getUniqueId());
}
/**
* Freezes Boss bar for 1.20.2+ players due to bug with adventure that causes disconnect
* on 1.20.5+ with "Network Protocol Error"
*
* @param e
* Event fired before player switches server for proper freezing
*/
@Subscribe(order = PostOrder.LAST)
public void preConnect(@NotNull ServerPreConnectEvent e) {
if (e.getResult().isAllowed()) {
TabPlayer p = TAB.getInstance().getPlayer(e.getPlayer().getUniqueId());
if (p != null && p.getVersion().getNetworkId() >= ProtocolVersion.V1_20_2.getNetworkId()) {
p.getBossBar().freeze();
}
}
}
/**
* Listens to player connecting to a backend server. This handles
* both initial connections and server switch.
@@ -97,4 +117,4 @@ public class VelocityEventListener implements EventListener<Player> {
public TabPlayer createPlayer(@NotNull Player player) {
return new VelocityTabPlayer((VelocityPlatform) TAB.getInstance().getPlatform(), player);
}
}
}