Compare commits

...
42 Commits
Author SHA1 Message Date
NEZNAMY 1a44c97d5a 4.1.8 2024-08-30 18:57:45 +02:00
NEZNAMY 29cf0a26d6 4.1.8-SNAPSHOT 2024-08-25 20:11:13 +02:00
NEZNAMY 33d172598d [BungeeCord] Avoid sending UPDATE_LIST_ORDER tablist action to <1.21.2 players (#1359) 2024-08-25 20:10:53 +02:00
NEZNAMY af1e685c2b Merge pull request #1357 from hans362/fix-get-skin
Get skin from profile properties by property name
2024-08-20 16:01:48 +02:00
hans362 09129974db Get skin from profile properties by property name 2024-08-20 21:26:08 +08:00
NEZNAMY 0efb69fb4b [Fabric] Add 1.21.1 to supported versions 2024-08-10 09:46:22 +02:00
NEZNAMY 5cbec52ea3 4.1.7 2024-08-10 09:38:23 +02:00
NEZNAMY 8db9e64121 Update to 1.21.1 2024-08-10 09:37:20 +02:00
NEZNAMY 05009b17f0 [Layout] Fix API usage causing placeholders to not refresh (#1347) 2024-08-06 17:57:41 +02:00
NEZNAMY 032af707dd [Sorting] Fix sorting placeholder using old instance when a placeholder is overridden 2024-07-25 20:52:33 +02:00
NEZNAMY cf227a97f3 [BungeeCord] Add try/catch for yet another NPE in BungeeCord code (#1338) 2024-07-25 15:56:21 +02:00
NEZNAMY 1a2075dfe2 [Bukkit] Fix compatibility with random modded server 2024-07-22 19:26:57 +02:00
NEZNAMY 1de7665309 [Bug fix] Colors not displaying correctly in Fabric and Velocity console (#1298) 2024-06-26 14:25:05 +02:00
NEZNAMY 9473037127 Merge pull request #1323 from sunmisc/master
represent getOnlinePlayers as a collection
2024-06-22 23:37:47 +02:00
sunmisc dcb234dc08 stream api to collection 2024-06-23 00:35:16 +03:00
sunmisc 79eb34fc32 Revert "stream api to collection"
This reverts commit 40544ef5d3.
2024-06-23 00:31:38 +03:00
sunmisc 40544ef5d3 stream api to collection 2024-06-23 00:19:33 +03:00
sunmisc 14dfa0154a Stream api for getOnlinePlayers 2024-06-22 23:44:51 +03:00
NEZNAMY 7df2aba2d1 [RedisBungee] Override %serveronline% to count redis players as well (#1316) 2024-06-16 20:10:25 +02:00
NEZNAMY 9edf3176ea [MiniMessage] Add dummy character to parsed text to disable color compacting (#1312) 2024-06-16 09:16:57 +02:00
NEZNAMY ec73aa13b4 4.1.7-SNAPSHOT 2024-06-16 09:16:48 +02:00
NEZNAMY 6f002cd61b Change action builds to only upload from v5 branch 2024-06-13 21:11:12 +02:00
NEZNAMY cf065ba27d 4.1.6 2024-06-13 19:19:54 +02:00
NEZNAMY f96e263bd7 Add 1.21 support 2024-06-13 19:19:41 +02:00
NEZNAMY a22f8eccaf Update message about unlimited nametags 2024-06-13 15:28:44 +02:00
NEZNAMY 718ee89211 [BungeeCord] Fix another issue leading to "Network Protocol Error" disconnect on 1.20.5+ 2024-06-13 11:33:04 +02:00
NEZNAMY 54b44ce6cd [Unlimited nametags] Print console warn if the feature is enabled 2024-06-13 11:30:26 +02:00
NEZNAMY 29da28e955 [BungeeCord] Fix error in pipeline injector (#1310) 2024-06-12 17:44:24 +02:00
NEZNAMY fa195389ab [Sorting] Fix sorting by pre-defined values space trimming inconsistency (#1308) 2024-06-11 15:39:39 +02:00
NEZNAMY 9e3864be53 [Bukkit] Add missing support for mojang mapped jars 2024-06-06 15:16:17 +02:00
NEZNAMY 29b89b3bb7 [Commands] Fix error when setting property value to ' or " 2024-06-01 16:50:02 +02:00
NEZNAMY e741608261 [Placeholders] Fix server placeholders not returning proper value on request sometimes 2024-05-30 16:10:38 +02:00
NEZNAMY 8e8a4cc9e8 [Teams] [Bukkit] Fix team action not being taken correctly on 1.8 - 1.12, causing issues with previous commit 2024-05-29 13:34:35 +02:00
NEZNAMY 3bb6e0c3f2 [Teams] Fix another instance of "Network Protocol Error" disconnect on 1.20.5+ 2024-05-28 14:40:17 +02:00
NEZNAMY 4c3b13a81c 4.1.6-SNAPSHOT 2024-05-28 14:40:04 +02:00
NEZNAMY 6b9063c789 4.1.5 2024-05-27 15:58:52 +02:00
NEZNAMY ce0a45b76c [Bukkit] Add support for latest 1.21 snapshot 2024-05-27 13:46:47 +02:00
NEZNAMY 41a0bd37ce [Sorting] Fix number compression bug (#1297) 2024-05-26 12:38:28 +02:00
NEZNAMY 449d3cb3ee [BossBar] Fix error when trying to display bossbar that was not visible on join 2024-05-22 10:14:52 +02:00
NEZNAMY a1a3852b08 [BossBar] Fix Network Protocol Error disconnect on server switch 2024-05-20 12:41:07 +02:00
NEZNAMY ef63df5175 [BossBar] Make %countdown% return 0 after announcement is over instead of going to negative numbers 2024-05-20 11:08:08 +02:00
NEZNAMY 17e57f9d0c [Bug fix] Fix disabled tablist formatting referencing wrong variable 2024-05-16 21:00:01 +02:00
53 changed files with 375 additions and 177 deletions

No files matched your search

+1 -1
View File
@@ -2,7 +2,7 @@ name: Build
on:
push:
branches:
- master
- v5
jobs:
build:
name: Build
@@ -1,5 +1,6 @@
package me.neznamy.tab.api;
import java.util.Collection;
import java.util.UUID;
import lombok.NonNull;
@@ -67,8 +68,17 @@ public abstract class TabAPI {
*
* @return collection of online players
*/
@Deprecated
public abstract @NotNull TabPlayer[] getOnlinePlayers();
/**
* Returns a stream of all online players
*
* @return stream of online players
*/
public abstract @NotNull Collection<? extends TabPlayer> onlinePlayers();
/**
* Return BossBar manager instance if the feature is enabled. If not, returns {@code null}.
*
+1 -1
View File
@@ -4,7 +4,7 @@ plugins {
allprojects {
group = "me.neznamy"
version = "4.1.5-SNAPSHOT"
version = "4.1.8"
description = "An all-in-one solution that works"
ext.set("id", "tab")
@@ -97,7 +97,7 @@ public class BukkitTabExpansion extends PlaceholderExpansion implements TabExpan
}
if (player == null) return "<Player cannot be null>";
TabPlayer p = TAB.getInstance().getPlayer(player.getUniqueId());
if (p == null || !p.isLoaded()) return "<Player is not loaded>";
if (p == null) return "<Player is not loaded>";
return p.expansionValues.values.get(identifier);
}
@@ -29,8 +29,8 @@ public class ComponentConverter {
private final FunctionWithException<String, Object> newTextComponent;
private final BiFunction<ChatModifier, Boolean, Object> convertModifier;
private final Class<?> ChatModifier = BukkitReflection.getClass("network.chat.ChatModifier", "ChatModifier");
private final Class<Enum> EnumChatFormat = (Class<Enum>) BukkitReflection.getClass("EnumChatFormat");
private final Class<?> ChatModifier = BukkitReflection.getClass("network.chat.Style", "network.chat.ChatModifier", "ChatModifier");
private final Class<Enum> EnumChatFormat = (Class<Enum>) BukkitReflection.getClass("ChatFormatting", "EnumChatFormat");
private final Constructor<?> newChatModifier;
private final Method ChatBaseComponent_addSibling;
private final Field Component_modifier;
@@ -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.
@@ -50,30 +50,30 @@ public class ComponentConverter {
* If something failed
*/
private ComponentConverter() throws ReflectiveOperationException {
Class<?> IChatBaseComponent = BukkitReflection.getClass("network.chat.IChatBaseComponent", "IChatBaseComponent");
Class<?> IChatBaseComponent = BukkitReflection.getClass("network.chat.Component", "network.chat.IChatBaseComponent", "IChatBaseComponent");
if (BukkitReflection.getMinorVersion() >= 19) {
Method IChatBaseComponent_b = ReflectionUtils.getMethod(IChatBaseComponent, new String[] {"b", "literal"}, String.class);
newTextComponent = text -> IChatBaseComponent_b.invoke(null, text);
Class<?> IChatMutableComponent = BukkitReflection.getClass("network.chat.IChatMutableComponent", "IChatMutableComponent");
Class<?> IChatMutableComponent = BukkitReflection.getClass("network.chat.MutableComponent", "network.chat.IChatMutableComponent", "IChatMutableComponent");
Component_modifier = ReflectionUtils.getOnlyField(IChatMutableComponent, ChatModifier);
ChatBaseComponent_addSibling = ReflectionUtils.getOnlyMethod(IChatMutableComponent, IChatMutableComponent, IChatBaseComponent);
} else {
Class<?> ChatComponentText = BukkitReflection.getClass("network.chat.ChatComponentText", "ChatComponentText");
Class<?> ChatComponentText = BukkitReflection.getClass("network.chat.TextComponent", "network.chat.ChatComponentText", "ChatComponentText");
Constructor<?> newChatComponentText = ChatComponentText.getConstructor(String.class);
newTextComponent = newChatComponentText::newInstance;
Class<?> ChatBaseComponent = BukkitReflection.getClass("network.chat.ChatBaseComponent", "ChatBaseComponent");
Class<?> ChatBaseComponent = BukkitReflection.getClass("network.chat.BaseComponent", "network.chat.ChatBaseComponent", "ChatBaseComponent");
Component_modifier = ReflectionUtils.getOnlyField(ChatBaseComponent, ChatModifier);
ChatBaseComponent_addSibling = ReflectionUtils.getOnlyMethod(ChatComponentText, IChatBaseComponent, IChatBaseComponent);
}
if (BukkitReflection.getMinorVersion() >= 16) {
Class<?> chatHexColor = BukkitReflection.getClass("network.chat.ChatHexColor", "ChatHexColor");
Class<?> MinecraftKey = 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);
ChatHexColor_fromRGB = ReflectionUtils.getOnlyMethod(chatHexColor, chatHexColor, int.class);
Class<?> chatHexColor = BukkitReflection.getClass("network.chat.TextColor", "network.chat.ChatHexColor", "ChatHexColor");
Class<?> ResourceLocation = BukkitReflection.getClass("resources.ResourceLocation", "resources.MinecraftKey", "MinecraftKey");
Class<?> chatClickable = BukkitReflection.getClass("network.chat.ClickEvent", "network.chat.ChatClickable", "ChatClickable");
Class<?> chatHoverable = BukkitReflection.getClass("network.chat.HoverEvent", "network.chat.ChatHoverable", "ChatHoverable");
ResourceLocation_tryParse = ReflectionUtils.getMethod(ResourceLocation, new String[]{"tryParse", "m_135820_", "a"}, String.class);
ChatHexColor_fromRGB = ReflectionUtils.getMethods(chatHexColor, chatHexColor, int.class).get(0); // There should only be 1, but some mods add more
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())
);
}
@@ -16,6 +16,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
/**
* Class storing all team related fields and methods.
@@ -70,7 +71,12 @@ public class TeamPacketData {
emptyScoreboard = Scoreboard.getConstructor().newInstance();
newScoreboardTeam = scoreboardTeam.getConstructor(Scoreboard, String.class);
TeamPacket_NAME = ReflectionUtils.getFields(TeamPacketClass, String.class).get(0);
TeamPacket_ACTION = ReflectionUtils.getInstanceFields(TeamPacketClass, int.class).get(0);
List<Field> intFields = ReflectionUtils.getInstanceFields(TeamPacketClass, int.class);
if (minorVersion >= 8 && minorVersion <= 12) {
TeamPacket_ACTION = intFields.get(1);
} else {
TeamPacket_ACTION = intFields.get(0);
}
TeamPacket_PLAYERS = ReflectionUtils.getOnlyField(TeamPacketClass, Collection.class);
ScoreboardTeam_getPlayerNameSet = ReflectionUtils.getOnlyMethod(scoreboardTeam, Collection.class);
chatFormats = (Enum<?>[]) enumChatFormatClass.getMethod("values").invoke(null);
@@ -302,7 +308,7 @@ public class TeamPacketData {
public void onPacketSend(@NonNull TabPlayer player, @NonNull Object packet) {
if (!TeamPacketClass.isInstance(packet)) return;
int action = TeamPacket_ACTION.getInt(packet);
if (action == TeamAction.REMOVE || action == TeamAction.UPDATE) return;
if (action == TeamAction.UPDATE) return;
TeamPacket_PLAYERS.set(packet, player.getScoreboard().onTeamPacket(
action, (String) TeamPacket_NAME.get(packet), (Collection<String>) TeamPacket_PLAYERS.get(packet)));
}
+1 -1
View File
@@ -1,7 +1,7 @@
dependencies {
implementation(projects.shared)
implementation("org.bstats:bstats-bungeecord:3.0.1")
compileOnly("net.md-5:bungeecord-proxy:1.20-R0.2-SNAPSHOT")
compileOnly("net.md-5:bungeecord-proxy:1.20-R0.3-SNAPSHOT")
compileOnly("com.github.limework.redisbungee:RedisBungee-Bungee:0.11.0")
compileOnly("com.github.LeonMangler:PremiumVanishAPI:2.8.8")
}
@@ -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(() -> {
@@ -57,6 +59,7 @@ public class BungeeEventListener implements EventListener<ProxiedPlayer>, Listen
// Sending these packets before login packet will also crash the client on 1.20.3
if (player.getVersion().getNetworkId() >= ProtocolVersion.V1_20_2.getNetworkId()) {
player.getScoreboard().freeze();
player.getBossBar().freeze();
}
tab.getFeatureManager().onJoin(player);
@@ -14,6 +14,8 @@ import net.md_5.bungee.protocol.packet.*;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* Scoreboard handler for BungeeCord. Because it does not offer
@@ -158,8 +160,9 @@ public class BungeeScoreboard extends Scoreboard<BungeeTabPlayer, BaseComponent>
}
if (isAntiOverrideTeams() && packet instanceof Team) {
Team team = (Team) packet;
if (team.getMode() == TeamAction.REMOVE || team.getMode() == TeamAction.UPDATE) return;
team.setPlayers(onTeamPacket(team.getMode(), team.getName(), Lists.newArrayList(team.getPlayers())).toArray(new String[0]));
if (team.getMode() == TeamAction.UPDATE) return;
List<String> players = team.getPlayers() == null ? Collections.emptyList() : Lists.newArrayList(team.getPlayers());
team.setPlayers(onTeamPacket(team.getMode(), team.getName(), players).toArray(new String[0]));
}
}
}
@@ -71,7 +71,20 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
@Override
public void sendMessage(@NotNull TabComponent message) {
getPlayer().sendMessage((BaseComponent) message.convert(getVersion()));
try {
getPlayer().sendMessage((BaseComponent) message.convert(getVersion()));
} catch (NullPointerException BungeeCordBug) {
// java.lang.NullPointerException: Cannot invoke "net.md_5.bungee.protocol.MinecraftEncoder.getProtocol()" because the return value of "io.netty.channel.ChannelPipeline.get(java.lang.Class)" is null
// at net.md_5.bungee.netty.ChannelWrapper.getEncodeProtocol(ChannelWrapper.java:51)
// at net.md_5.bungee.UserConnection.sendPacketQueued(UserConnection.java:198)
// at net.md_5.bungee.UserConnection.sendMessage(UserConnection.java:565)
// at net.md_5.bungee.UserConnection.sendMessage(UserConnection.java:520)
// at net.md_5.bungee.UserConnection.sendMessage(UserConnection.java:508)
if (TAB.getInstance().getConfiguration().isDebugMode()) {
TAB.getInstance().getErrorManager().printError("Failed to send message to player " + getName() +
" (online = " + getPlayer().isConnected() + "): " + message.convert(getVersion()), BungeeCordBug);
}
}
}
@Override
@@ -80,8 +93,13 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
LoginResult loginResult = ((InitialHandler)getPlayer().getPendingConnection()).getLoginProfile();
if (loginResult == null) return null;
Property[] properties = loginResult.getProperties();
if (properties == null || properties.length == 0) return null; //Offline mode
return new TabList.Skin(properties[0].getValue(), properties[0].getSignature());
if (properties == null) return null; //Offline mode
for (Property property : properties) {
if (property.getName().equals(TabList.TEXTURES_PROPERTY)) {
return new TabList.Skin(property.getValue(), property.getSignature());
}
}
return null;
}
@Override
@@ -20,7 +20,15 @@ public class BungeeTabList1193 extends BungeeTabList {
private static final Map<Action, EnumSet<PlayerListItemUpdate.Action>> actions = new EnumMap<>(Action.class);
static {
actions.put(Action.ADD_PLAYER, EnumSet.allOf(PlayerListItemUpdate.Action.class));
// Do not use allOf because <1.21.2 does not support UPDATE_LIST_ORDER
// TODO Once bungeecord dependency is updated, support it properly
actions.put(Action.ADD_PLAYER, EnumSet.of(
PlayerListItemUpdate.Action.ADD_PLAYER,
PlayerListItemUpdate.Action.UPDATE_GAMEMODE,
PlayerListItemUpdate.Action.UPDATE_LISTED,
PlayerListItemUpdate.Action.UPDATE_LATENCY,
PlayerListItemUpdate.Action.UPDATE_DISPLAY_NAME
));
actions.put(Action.UPDATE_GAME_MODE, EnumSet.of(PlayerListItemUpdate.Action.UPDATE_GAMEMODE));
actions.put(Action.UPDATE_DISPLAY_NAME, EnumSet.of(PlayerListItemUpdate.Action.UPDATE_DISPLAY_NAME));
actions.put(Action.UPDATE_LATENCY, EnumSet.of(PlayerListItemUpdate.Action.UPDATE_LATENCY));
+2 -2
View File
@@ -12,11 +12,11 @@ repositories {
dependencies {
api(projects.shared)
minecraft("com.mojang:minecraft:24w19a")
minecraft("com.mojang:minecraft:1.21.1")
mappings(loom.officialMojangMappings())
modImplementation("me.lucko:fabric-permissions-api:0.2-SNAPSHOT")
modImplementation("net.fabricmc:fabric-loader:0.15.9")
val version = "0.97.8+1.20.6"
val version = "0.100.1+1.21"
modImplementation(fabricApi.module("fabric-api-base", version))
modImplementation(fabricApi.module("fabric-lifecycle-events-v1", version))
modImplementation(fabricApi.module("fabric-networking-api-v1", version))
@@ -4,7 +4,7 @@ import com.mojang.authlib.properties.Property;
import io.netty.channel.Channel;
import lombok.SneakyThrows;
import me.neznamy.tab.platforms.fabric.loader.Loader;
import me.neznamy.tab.platforms.fabric.loader.Loader_1_20_5;
import me.neznamy.tab.platforms.fabric.loader.Loader_1_21_1;
import me.neznamy.tab.shared.ProtocolVersion;
import me.neznamy.tab.shared.backend.EntityData;
import me.neznamy.tab.shared.backend.Location;
@@ -38,7 +38,7 @@ public class FabricMultiVersion {
private static final ProtocolVersion serverVersion = ProtocolVersion.fromFriendlyName(FabricTAB.minecraftVersion);
/** Method loader using latest supported MC version */
private static final Loader loaderNew = new Loader_1_20_5();
private static final Loader loaderNew = new Loader_1_21_1();
/** Method loader using 1.18.2 */
private static final Loader loader1_18_2 = createLoader("1_18_2");
@@ -42,14 +42,13 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* Method loader compiled using Minecraft 1.20.5.
* Method loader compiled using Minecraft 1.21.1.
*/
@SuppressWarnings({
"unchecked", // Java generic types
"DataFlowIssue", // Profile is not null on add action
"unused" // Actually used, just via reflection
"DataFlowIssue" // Profile is not null on add action
})
public class Loader_1_20_5 implements Loader {
public class Loader_1_21_1 implements Loader {
@Override
@NotNull
@@ -96,7 +95,7 @@ public class Loader_1_20_5 implements Loader {
null,
null,
null,
modifier.getFont() == null ? null : new ResourceLocation(modifier.getFont())
modifier.getFont() == null ? null : ResourceLocation.tryParse(modifier.getFont())
);
}
@@ -147,7 +146,7 @@ public class Loader_1_20_5 implements Loader {
@Override
public void checkTeamPacket(@NotNull Packet<?> packet, @NotNull FabricScoreboard scoreboard) {
if (packet instanceof ClientboundSetPlayerTeamPacket team) {
if (team.method == Scoreboard.TeamAction.REMOVE || team.method == Scoreboard.TeamAction.UPDATE) return;
if (team.method == Scoreboard.TeamAction.UPDATE) return;
team.players = scoreboard.onTeamPacket(team.method, team.getName(), team.players);
}
}
@@ -320,12 +319,12 @@ public class Loader_1_20_5 implements Loader {
@Override
public void logInfo(@NotNull TabComponent message) {
MinecraftServer.LOGGER.info("[TAB] " + message.toLegacyText());
MinecraftServer.LOGGER.info("[TAB] " + message.toRawText());
}
@Override
public void logWarn(@NotNull TabComponent message) {
MinecraftServer.LOGGER.warn("[TAB] " + message.toLegacyText());
MinecraftServer.LOGGER.warn("[TAB] " + message.toRawText());
}
/**
@@ -361,10 +360,6 @@ public class Loader_1_20_5 implements Loader {
static final Map<TabList.Action, EnumSet<ClientboundPlayerInfoUpdatePacket.Action>> actionMap = createActionMap();
public static EnumSet<ClientboundPlayerInfoUpdatePacket.Action> convertAction(TabList.Action action) {
return EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.valueOf(action.name()));
}
private static Map<TabList.Action, EnumSet<ClientboundPlayerInfoUpdatePacket.Action>> createActionMap() {
Map<TabList.Action, EnumSet<ClientboundPlayerInfoUpdatePacket.Action>> actions = new EnumMap<>(TabList.Action.class);
actions.put(TabList.Action.ADD_PLAYER, EnumSet.allOf(ClientboundPlayerInfoUpdatePacket.Action.class));
+1 -1
View File
@@ -20,7 +20,7 @@
"1.18", "1.18.1", "1.18.2",
"1.19", "1.19.1", "1.19.2", "1.19.3", "1.19.4",
"1.20", "1.20.1", "1.20.2", "1.20.3", "1.20.4", "1.20.5", "1.20.6",
"1.21-alpha.24.19.a"
"1.21", "1.21.1"
]
},
"recommends": {
@@ -147,7 +147,7 @@ public class Loader_1_14_4 implements Loader {
public void checkTeamPacket(@NotNull Packet<?> packet, @NotNull FabricScoreboard scoreboard) {
if (packet instanceof ClientboundSetPlayerTeamPacket) {
int action = ReflectionUtils.getInstanceFields(packet.getClass(), int.class).get(0).getInt(packet);
if (action == Scoreboard.TeamAction.REMOVE || action == Scoreboard.TeamAction.UPDATE) return;
if (action == Scoreboard.TeamAction.UPDATE) return;
Field playersField = ReflectionUtils.getFields(packet.getClass(), Collection.class).get(0);
Collection<String> players = (Collection<String>) playersField.get(packet);
String teamName = String.valueOf(ReflectionUtils.getFields(packet.getClass(), String.class).get(0).get(packet));
@@ -319,13 +319,13 @@ public class Loader_1_14_4 implements Loader {
@SneakyThrows
public void logInfo(@NotNull TabComponent message) {
Object logger = ReflectionUtils.getFields(MinecraftServer.class, Class.forName("org.apache.logging.log4j.Logger")).get(0).get(null);
logger.getClass().getMethod("info", String.class).invoke(logger, "[TAB] " + message.toLegacyText());
logger.getClass().getMethod("info", String.class).invoke(logger, "[TAB] " + message.toRawText());
}
@Override
@SneakyThrows
public void logWarn(@NotNull TabComponent message) {
Object logger = ReflectionUtils.getFields(MinecraftServer.class, Class.forName("org.apache.logging.log4j.Logger")).get(0).get(null);
logger.getClass().getMethod("warn", String.class).invoke(logger, "[TAB] " + message.toLegacyText());
logger.getClass().getMethod("warn", String.class).invoke(logger, "[TAB] " + message.toRawText());
}
}
@@ -3,7 +3,7 @@ package me.neznamy.tab.shared;
import lombok.Getter;
import me.neznamy.tab.api.event.TabEvent;
import me.neznamy.tab.shared.chat.EnumChatFormat;
import me.neznamy.tab.shared.chat.SimpleComponent;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.platform.TabPlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -118,13 +118,13 @@ public class ErrorManager {
if (file.length() < TabConstants.MAX_LOG_SIZE)
buf.write(dateFormat.format(new Date()) + "[TAB v" + TabConstants.PLUGIN_VERSION + "] " + EnumChatFormat.decolor(message) + System.lineSeparator());
if (intoConsoleToo || TAB.getInstance().getConfiguration().isDebugMode())
TAB.getInstance().getPlatform().logWarn(new SimpleComponent(message));
TAB.getInstance().getPlatform().logWarn(TabComponent.fromColoredText(message));
}
for (String line : error) {
if (file.length() < TabConstants.MAX_LOG_SIZE)
buf.write(dateFormat.format(new Date()) + line + System.lineSeparator());
if (intoConsoleToo || TAB.getInstance().getConfiguration().isDebugMode())
TAB.getInstance().getPlatform().logWarn(new SimpleComponent(line));
TAB.getInstance().getPlatform().logWarn(TabComponent.fromColoredText(line));
}
}
} catch (IOException ex) {
@@ -134,7 +134,7 @@ public class ErrorManager {
lines.add("Original error: " + message);
lines.addAll(error);
for (String line : lines) {
TAB.getInstance().getPlatform().logWarn(new SimpleComponent(line));
TAB.getInstance().getPlatform().logWarn(TabComponent.fromColoredText(line));
}
}
}
@@ -3,6 +3,7 @@ package me.neznamy.tab.shared;
import java.util.*;
import me.neznamy.tab.api.placeholder.PlayerPlaceholder;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.config.Configs;
import me.neznamy.tab.shared.config.mysql.MySQLUserConfiguration;
import me.neznamy.tab.shared.features.*;
@@ -487,6 +488,18 @@ public class FeatureManager {
NameTag unlimited = TAB.getInstance().getPlatform().getUnlimitedNameTags();
if (unlimited instanceof NameTagX) {
featureManager.registerFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS, unlimited);
for (String message : new String[]{
"---------------------------------------------------------------------",
"You have unlimited nametag mode feature enabled.",
"This feature is scheduled for removal in a future TAB release.",
"Please considering the alternative solutions available to achieve your desired result.",
"No bug reports with this feature will be accepted anymore.",
"No support with this feature will be provided anymore.",
"See https://gist.github.com/NEZNAMY/f4cabf2fd9251a836b5eb877720dee5c/ for more info.",
"---------------------------------------------------------------------"
}) {
TAB.getInstance().getPlatform().logWarn(TabComponent.fromColoredText(message));
}
} else {
featureManager.registerFeature(TabConstants.Feature.NAME_TAGS, unlimited);
}
@@ -11,6 +11,8 @@ import org.jetbrains.annotations.NotNull;
public enum ProtocolVersion {
UNKNOWN,
V1_21_1 (767),
V1_21 (767),
V1_20_6 (766),
V1_20_5 (766),
V1_20_4 (765),
@@ -81,7 +83,7 @@ public enum ProtocolVersion {
private static final ProtocolVersion[] VALUES = values();
/** Newest MC version this plugin jar knows */
public static final ProtocolVersion LATEST_KNOWN_VERSION = V1_20_6;
public static final ProtocolVersion LATEST_KNOWN_VERSION = VALUES[1];
/** Version's network id found at <a href="https://wiki.vg/Protocol_version_numbers">wiki.vg</a> */
private final int networkId;
@@ -10,7 +10,7 @@ import me.neznamy.tab.api.scoreboard.ScoreboardManager;
import me.neznamy.tab.api.tablist.HeaderFooterManager;
import me.neznamy.tab.api.tablist.TabListFormatManager;
import me.neznamy.tab.shared.chat.EnumChatFormat;
import me.neznamy.tab.shared.chat.SimpleComponent;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.config.helper.ConfigHelper;
import me.neznamy.tab.shared.cpu.CpuManager;
import me.neznamy.tab.shared.features.nametags.NameTag;
@@ -28,6 +28,8 @@ import org.jetbrains.annotations.Nullable;
import org.yaml.snakeyaml.error.YAMLException;
import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@@ -184,10 +186,10 @@ public class TAB extends TabAPI {
cpu.enable();
configHelper.startup().checkErrorLog();
configHelper.startup().printWarnCount();
platform.logInfo(new SimpleComponent(EnumChatFormat.GREEN + "Enabled in " + (System.currentTimeMillis()-time) + "ms"));
platform.logInfo(TabComponent.fromColoredText(EnumChatFormat.GREEN + "Enabled in " + (System.currentTimeMillis()-time) + "ms"));
return configuration.getMessages().getReloadSuccess();
} catch (YAMLException e) {
platform.logWarn(new SimpleComponent(EnumChatFormat.RED + "Did not enable due to a broken configuration file."));
platform.logWarn(TabComponent.fromColoredText(EnumChatFormat.RED + "Did not enable due to a broken configuration file."));
kill();
return (configuration == null ? "&4Failed to reload, file %file% has broken syntax. Check console for more info."
: configuration.getMessages().getReloadFailBrokenFile()).replace("%file%", brokenFile);
@@ -208,7 +210,7 @@ public class TAB extends TabAPI {
long time = System.currentTimeMillis();
if (configuration.getMysql() != null) configuration.getMysql().closeConnection();
featureManager.unload();
platform.logInfo(new SimpleComponent(EnumChatFormat.GREEN + "Disabled in " + (System.currentTimeMillis()-time) + "ms"));
platform.logInfo(TabComponent.fromColoredText(EnumChatFormat.GREEN + "Disabled in " + (System.currentTimeMillis()-time) + "ms"));
} catch (Throwable e) {
errorManager.criticalError("Failed to disable", e);
}
@@ -293,6 +295,11 @@ public class TAB extends TabAPI {
return featureManager.getFeature(TabConstants.Feature.HEADER_FOOTER);
}
@Override
public @NotNull Collection<? extends TabPlayer> onlinePlayers() {
return Collections.unmodifiableCollection(data.values());
}
@Override
public @Nullable TabListFormatManager getTabListFormatManager() {
return featureManager.getFeature(TabConstants.Feature.PLAYER_LIST);
@@ -317,6 +324,6 @@ public class TAB extends TabAPI {
*/
public void debug(@NotNull String message) {
if (configuration != null && configuration.isDebugMode())
platform.logInfo(new SimpleComponent(EnumChatFormat.BLUE + "[DEBUG] " + message));
platform.logInfo(TabComponent.fromColoredText(EnumChatFormat.BLUE + "[DEBUG] " + message));
}
}
@@ -19,4 +19,11 @@ public class SimpleComponent extends TabComponent {
public String toLegacyText() {
return text;
}
@Override
@NotNull
public String toRawText() {
return text;
}
}
@@ -115,17 +115,14 @@ public class StructuredComponent extends TabComponent {
return builder.toString();
}
/**
* Returns raw text without colors, only works correctly when component is organized
*
* @return raw text in this component and all child components
*/
public @NotNull String toRawText() {
StringBuilder builder = new StringBuilder();
builder.append(text);
for (StructuredComponent child : getExtra()) {
builder.append(child.text);
@Override
@NotNull
public String toRawText() {
StringBuilder builder = new StringBuilder(text);
for (StructuredComponent extra : getExtra()) {
builder.append(extra.toRawText());
}
return builder.toString();
}
}
@@ -64,6 +64,15 @@ public abstract class TabComponent {
*/
public abstract String toLegacyText();
/**
* Converts this component into a string that only consists of text without any formatting.
*
* @return String containing text of the component and extras
*/
@NotNull
public abstract String toRawText();
/**
* Returns the most optimized component based on text. Returns null if text is null,
* organized component if RGB colors are used or simple component with only text field
@@ -14,13 +14,17 @@ public class MiniMessageFormat implements RGBFormatter {
private static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer.builder()
.hexColors().useUnusualXRepeatedCharacterHexFormat().build();
/** Dummy character to append to disable MiniMessage's color compacting that prevents team color from being detected as last color of prefix */
private static final char dummyChar = Character.MAX_VALUE;
@Override
@NotNull
public String reformat(@NotNull String text) {
if (!text.contains("<")) return text; // User did not even attempt to use MiniMessage
if (text.contains(EnumChatFormat.COLOR_STRING)) return text;
try {
return SERIALIZER.serialize(MiniMessage.miniMessage().deserialize(text));
String serialized = SERIALIZER.serialize(MiniMessage.miniMessage().deserialize(text + dummyChar));
return serialized.substring(0, serialized.length()-1); // Remove the dummy char back
} catch (Throwable ignored) {
return text;
}
@@ -4,7 +4,7 @@ import java.text.DecimalFormat;
import java.util.Map;
import java.util.Map.Entry;
import me.neznamy.tab.shared.chat.SimpleComponent;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.cpu.CpuReport;
import me.neznamy.tab.shared.platform.TabPlayer;
import me.neznamy.tab.shared.chat.EnumChatFormat;
@@ -74,13 +74,13 @@ public class CpuCommand extends SubCommand {
}
public void sendToConsole(@NotNull Map<String, Map<String, Float>> features) {
TAB.getInstance().getPlatform().logInfo(new SimpleComponent(EnumChatFormat.color("&8&l" + LINE_CHAR + " &6Features:")));
TAB.getInstance().getPlatform().logInfo(TabComponent.fromColoredText(EnumChatFormat.color("&8&l" + LINE_CHAR + " &6Features:")));
for (Entry<String, Map<String, Float>> entry : features.entrySet()) {
TAB.getInstance().getPlatform().logInfo(new SimpleComponent(EnumChatFormat.color(
TAB.getInstance().getPlatform().logInfo(TabComponent.fromColoredText(EnumChatFormat.color(
String.format("&8&l%s &7%s &7(%s%%&7):", LINE_CHAR, entry.getKey(),
colorize(decimal3.format(entry.getValue().values().stream().mapToDouble(Float::floatValue).sum()), 5, 1)))));
for (Entry<String, Float> type : entry.getValue().entrySet()) {
TAB.getInstance().getPlatform().logInfo(new SimpleComponent(EnumChatFormat.color(
TAB.getInstance().getPlatform().logInfo(TabComponent.fromColoredText(EnumChatFormat.color(
String.format("&8&l%s &7%s - %s%%", LINE_CHAR, type.getKey(), colorize(decimal3.format(type.getValue()), 5, 1)))));
}
}
@@ -91,7 +91,7 @@ public class CpuCommand extends SubCommand {
for (Entry<String, Map<String, Float>> entry : features.entrySet()) {
double featureTotal = entry.getValue().values().stream().mapToDouble(Float::floatValue).sum();
String core = String.format("&8&l%s &7%s &7(%s%%&7):", LINE_CHAR, entry.getKey(), colorize(decimal3.format(featureTotal), 5, 1));
sender.sendMessage(new SimpleComponent(EnumChatFormat.color(core)));
sender.sendMessage(TabComponent.fromColoredText(EnumChatFormat.color(core)));
}
}
@@ -42,7 +42,7 @@ public abstract class PropertyCommand extends SubCommand {
server = args[args.length-1];
value = value.startsWith("-s") ? "" : value.substring(0, value.length()-server.length()-4);
}
if ((value.startsWith("\"") && value.endsWith("\"")) || (value.startsWith("'") && value.endsWith("'"))) {
if (((value.startsWith("\"") && value.endsWith("\"")) || (value.startsWith("'") && value.endsWith("'"))) && value.length() > 1) {
value = value.substring(1, value.length()-1);
}
String property = args[1].toLowerCase();
@@ -3,7 +3,7 @@ package me.neznamy.tab.shared.config;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.TabConstants;
import me.neznamy.tab.shared.chat.EnumChatFormat;
import me.neznamy.tab.shared.chat.SimpleComponent;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.config.file.ConfigurationFile;
import me.neznamy.tab.shared.config.file.YamlConfigurationFile;
import org.jetbrains.annotations.NotNull;
@@ -25,7 +25,7 @@ public class Converter {
public void convert2810to290(@NotNull ConfigurationFile animations) {
if (animations.getValues().size() == 1 && animations.getValues().containsKey("animations")) {
TAB.getInstance().getPlatform().logInfo(new SimpleComponent(EnumChatFormat.YELLOW + "Performing configuration conversion from 2.8.10 to 2.9.0"));
TAB.getInstance().getPlatform().logInfo(TabComponent.fromColoredText(EnumChatFormat.YELLOW + "Performing configuration conversion from 2.8.10 to 2.9.0"));
animations.setValues(animations.getConfigurationSection("animations"));
animations.save();
}
@@ -42,7 +42,7 @@ public class Converter {
*/
public void convert292to300(@NotNull ConfigurationFile currentConfig) throws IOException {
if (!currentConfig.hasConfigOption("change-nametag-prefix-suffix")) return;
TAB.getInstance().getPlatform().logInfo(new SimpleComponent(EnumChatFormat.YELLOW + "Performing configuration conversion from 2.9.2 to 3.0.0"));
TAB.getInstance().getPlatform().logInfo(TabComponent.fromColoredText(EnumChatFormat.YELLOW + "Performing configuration conversion from 2.9.2 to 3.0.0"));
File folder = TAB.getInstance().getDataFolder();
moveOldFiles();
@@ -346,13 +346,13 @@ public class Converter {
public void convert301to302(@NotNull ConfigurationFile config) {
if (config.removeOption("placeholders.remove-strings")) {
TAB.getInstance().getPlatform().logInfo(new SimpleComponent(EnumChatFormat.YELLOW + "Performing configuration conversion from 3.0.1 to 3.0.2"));
TAB.getInstance().getPlatform().logInfo(TabComponent.fromColoredText(EnumChatFormat.YELLOW + "Performing configuration conversion from 3.0.1 to 3.0.2"));
}
}
public void convert331to332(@NotNull ConfigurationFile config) {
if (config.removeOption("scoreboard-teams.unlimited-nametag-mode.use-marker-tag-for-1-8-x-clients")) {
TAB.getInstance().getPlatform().logInfo(new SimpleComponent(EnumChatFormat.YELLOW + "Performing configuration conversion from 3.3.1 to 3.3.2)"));
TAB.getInstance().getPlatform().logInfo(TabComponent.fromColoredText(EnumChatFormat.YELLOW + "Performing configuration conversion from 3.3.1 to 3.3.2)"));
}
}
@@ -360,7 +360,7 @@ public class Converter {
public void convert332to400(@NotNull ConfigurationFile config) throws IOException {
// Removed config options
if (config.hasConfigOption("fix-pet-names")) {
TAB.getInstance().getPlatform().logInfo(new SimpleComponent(EnumChatFormat.YELLOW + "Performing configuration conversion from 3.3.2 to 4.0.0"));
TAB.getInstance().getPlatform().logInfo(TabComponent.fromColoredText(EnumChatFormat.YELLOW + "Performing configuration conversion from 3.3.2 to 4.0.0"));
config.set("fix-pet-names", null);
config.set("bossbar.disable-in-worlds", null);
config.set("bossbar.disable-in-servers", null);
@@ -425,13 +425,13 @@ public class Converter {
public void convert403to404(@NotNull ConfigurationFile config) {
if (config.removeOption("global-playerlist.update-latency")) {
TAB.getInstance().getPlatform().logInfo(new SimpleComponent(EnumChatFormat.YELLOW + "Performing configuration conversion from 4.0.3 to 4.0.4"));
TAB.getInstance().getPlatform().logInfo(TabComponent.fromColoredText(EnumChatFormat.YELLOW + "Performing configuration conversion from 4.0.3 to 4.0.4"));
}
}
public void convert409to410(@NotNull ConfigurationFile config) {
if (config.hasConfigOption("yellow-number-in-tablist")) {
TAB.getInstance().getPlatform().logInfo(new SimpleComponent(EnumChatFormat.YELLOW + "Performing configuration conversion from 4.0.9 to 4.1.0"));
TAB.getInstance().getPlatform().logInfo(TabComponent.fromColoredText(EnumChatFormat.YELLOW + "Performing configuration conversion from 4.0.9 to 4.1.0"));
Map<Object, Object> section = config.getConfigurationSection("yellow-number-in-tablist");
section.put("fancy-value", "&7Ping: %ping%");
config.set("yellow-number-in-tablist", null);
@@ -14,7 +14,7 @@ import java.util.List;
import lombok.NonNull;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.chat.EnumChatFormat;
import me.neznamy.tab.shared.chat.SimpleComponent;
import me.neznamy.tab.shared.chat.TabComponent;
import org.jetbrains.annotations.Nullable;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
@@ -56,13 +56,13 @@ public class YamlConfigurationFile extends ConfigurationFile {
if (input != null) input.close();
TAB tab = TAB.getInstance();
tab.setBrokenFile(destination.getName());
tab.getPlatform().logWarn(new SimpleComponent("File " + destination + " has broken syntax."));
tab.getPlatform().logInfo(new SimpleComponent(EnumChatFormat.GOLD + "Error message from yaml parser: " + e.getMessage()));
tab.getPlatform().logWarn(TabComponent.fromColoredText("File " + destination + " has broken syntax."));
tab.getPlatform().logInfo(TabComponent.fromColoredText(EnumChatFormat.GOLD + "Error message from yaml parser: " + e.getMessage()));
List<String> suggestions = YamlAssist.getSuggestions(file);
if (!suggestions.isEmpty()) {
tab.getPlatform().logInfo(new SimpleComponent(EnumChatFormat.LIGHT_PURPLE + "Suggestions to fix yaml syntax:"));
tab.getPlatform().logInfo(TabComponent.fromColoredText(EnumChatFormat.LIGHT_PURPLE + "Suggestions to fix yaml syntax:"));
for (String suggestion : suggestions) {
tab.getPlatform().logInfo(new SimpleComponent(EnumChatFormat.LIGHT_PURPLE + "- " + suggestion));
tab.getPlatform().logInfo(TabComponent.fromColoredText(EnumChatFormat.LIGHT_PURPLE + "- " + suggestion));
}
}
throw e;
@@ -79,7 +79,7 @@ public class YamlConfigurationFile extends ConfigurationFile {
writer.close();
fixHeader();
} catch (IOException e) {
TAB.getInstance().getPlatform().logWarn(new SimpleComponent("Failed to save yaml file " + file.getPath() + " with content " + values.toString()));
TAB.getInstance().getPlatform().logWarn(TabComponent.fromColoredText("Failed to save yaml file " + file.getPath() + " with content " + values.toString()));
}
}
}
@@ -2,7 +2,7 @@ package me.neznamy.tab.shared.config.helper;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.chat.EnumChatFormat;
import me.neznamy.tab.shared.chat.SimpleComponent;
import me.neznamy.tab.shared.chat.TabComponent;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
@@ -100,6 +100,6 @@ public class HintPrinter {
* Message to log
*/
private void hint(@NotNull String message) {
TAB.getInstance().getPlatform().logInfo(new SimpleComponent(EnumChatFormat.GOLD + "[Hint] " + message));
TAB.getInstance().getPlatform().logInfo(TabComponent.fromColoredText(EnumChatFormat.GOLD + "[Hint] " + message));
}
}
@@ -3,7 +3,7 @@ package me.neznamy.tab.shared.config.helper;
import me.neznamy.tab.api.bossbar.BossBar;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.chat.EnumChatFormat;
import me.neznamy.tab.shared.chat.SimpleComponent;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.features.sorting.types.SortingType;
import me.neznamy.tab.shared.platform.TabPlayer;
import me.neznamy.tab.shared.proxy.ProxyTabPlayer;
@@ -196,6 +196,6 @@ public class RuntimeErrorPrinter {
* Message to log
*/
private void error(@NotNull String message) {
TAB.getInstance().getPlatform().logWarn(new SimpleComponent(message));
TAB.getInstance().getPlatform().logWarn(TabComponent.fromColoredText(message));
}
}
@@ -4,7 +4,7 @@ import me.neznamy.tab.api.bossbar.BarColor;
import me.neznamy.tab.api.bossbar.BarStyle;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.TabConstants;
import me.neznamy.tab.shared.chat.SimpleComponent;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.features.layout.GroupPattern;
import me.neznamy.tab.shared.features.layout.LayoutManagerImpl;
import me.neznamy.tab.shared.features.sorting.types.SortingType;
@@ -389,7 +389,7 @@ public class StartupWarnPrinter {
private void startupWarn(@NotNull String... messages) {
warnCount++;
for (String message : messages) {
TAB.getInstance().getPlatform().logWarn(new SimpleComponent(message));
TAB.getInstance().getPlatform().logWarn(TabComponent.fromColoredText(message));
}
}
@@ -398,7 +398,7 @@ public class StartupWarnPrinter {
*/
public void printWarnCount() {
if (warnCount == 0) return;
TAB.getInstance().getPlatform().logWarn(new SimpleComponent("Found a total of " + warnCount + " issues."));
TAB.getInstance().getPlatform().logWarn(TabComponent.fromColoredText("Found a total of " + warnCount + " issues."));
// Reset after printing to prevent count going up on each reload
warnCount = 0;
}
@@ -14,7 +14,7 @@ import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.chat.EnumChatFormat;
import me.neznamy.tab.shared.chat.SimpleComponent;
import me.neznamy.tab.shared.chat.TabComponent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -37,7 +37,7 @@ public class MySQL {
properties.setProperty("useSSL", String.valueOf(useSSL));
properties.setProperty("characterEncoding", "UTF-8");
con = DriverManager.getConnection(String.format("jdbc:mysql://%s:%d/%s", host, port, database), properties);
TAB.getInstance().getPlatform().logInfo(new SimpleComponent(EnumChatFormat.GREEN + "Successfully connected to MySQL"));
TAB.getInstance().getPlatform().logInfo(TabComponent.fromColoredText(EnumChatFormat.GREEN + "Successfully connected to MySQL"));
}
public void closeConnection() throws SQLException {
@@ -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);
@@ -111,7 +111,7 @@ public class LayoutPattern extends TabFeature implements Refreshable, Layout {
public void addFixedSlot(int slot, @NonNull String text, @NonNull String skin, int ping) {
ensureActive();
fixedSlots.put(slot, new FixedSlot(manager, slot, this, manager.getUUID(slot), text,
"Layout-" + text + "-SLOT-" + slot, skin, "Layout-" + text + "-SLOT-" + slot+ "-skin", ping));
"Layout-" + name + "-SLOT-" + slot, skin, "Layout-" + name + "-SLOT-" + slot+ "-skin", ping));
}
@Override
@@ -227,6 +227,16 @@ public abstract class RedisSupport extends TabFeature implements JoinListener, Q
}
return count;
});
TAB.getInstance().getPlaceholderManager().registerPlayerPlaceholder(TabConstants.Placeholder.SERVER_ONLINE, 1000, p -> {
int count = 0;
for (TabPlayer player : TAB.getInstance().getOnlinePlayers()) {
if (((TabPlayer)p).getServer().equals(player.getServer()) && !player.isVanished()) count++;
}
for (RedisPlayer player : redisPlayers.values()) {
if (((TabPlayer)p).getServer().equals(player.getServer()) && !player.isVanished()) count++;
}
return count;
});
}
@Override
@@ -61,14 +61,15 @@ public class Placeholder extends SortingType {
@Override
public String getChars(@NotNull TabPlayer p) {
String output = EnumChatFormat.color(setPlaceholders(p));
p.sortingData.teamNameNote += "\n-> " + sortingPlaceholder.getIdentifier() + " returned \"&e" + output + "&r\"";
p.sortingData.teamNameNote += "\n-> " + sortingPlaceholder + " returned \"&e" + output + "&r\"";
int position;
if (!sortingMap.containsKey(output.toLowerCase(Locale.US))) {
TAB.getInstance().getConfigHelper().runtime().valueNotInPredefinedValues(sortingPlaceholder.getIdentifier(), sortingMap.keySet(), output, p);
String cleanOutput = output.trim().toLowerCase(Locale.US);
if (!sortingMap.containsKey(cleanOutput)) {
TAB.getInstance().getConfigHelper().runtime().valueNotInPredefinedValues(sortingPlaceholder, sortingMap.keySet(), cleanOutput, p);
position = sortingMap.size()+1;
p.sortingData.teamNameNote += "&c (not in list)&r. ";
} else {
position = sortingMap.get(output.toLowerCase(Locale.US));
position = sortingMap.get(cleanOutput);
p.sortingData.teamNameNote += "&r &a(#" + position + " in list). &r";
}
return String.valueOf((char) (position + 47));
@@ -24,7 +24,7 @@ public class PlaceholderAtoZ extends SortingType {
@Override
public String getChars(@NotNull TabPlayer p) {
String output = setPlaceholders(p);
p.sortingData.teamNameNote += "\n-> " + sortingPlaceholder.getIdentifier() + " returned \"&e" + output + "&r\". &r";
p.sortingData.teamNameNote += "\n-> " + sortingPlaceholder + " returned \"&e" + output + "&r\". &r";
return sorting.isCaseSensitiveSorting() ? output : output.toLowerCase();
}
}
@@ -24,7 +24,7 @@ public class PlaceholderHighToLow extends SortingType {
@Override
public String getChars(@NotNull TabPlayer p) {
String output = setPlaceholders(p);
p.sortingData.teamNameNote += "\n-> " + sortingPlaceholder.getIdentifier() + " returned \"&e" + output + "&r\". &r";
return compressNumber(DEFAULT_NUMBER - parseDouble(sortingPlaceholder.getIdentifier(), output, 0, p));
p.sortingData.teamNameNote += "\n-> " + sortingPlaceholder + " returned \"&e" + output + "&r\". &r";
return compressNumber(DEFAULT_NUMBER - parseDouble(sortingPlaceholder, output, 0, p));
}
}
@@ -24,7 +24,7 @@ public class PlaceholderLowToHigh extends SortingType {
@Override
public String getChars(@NotNull TabPlayer p) {
String output = setPlaceholders(p);
p.sortingData.teamNameNote += "\n-> " + sortingPlaceholder.getIdentifier() + " returned \"&e" + output + "&r\". &r";
return compressNumber(DEFAULT_NUMBER + parseDouble(sortingPlaceholder.getIdentifier(), output, 0, p));
p.sortingData.teamNameNote += "\n-> " + sortingPlaceholder + " returned \"&e" + output + "&r\". &r";
return compressNumber(DEFAULT_NUMBER + parseDouble(sortingPlaceholder, output, 0, p));
}
}
@@ -24,7 +24,7 @@ public class PlaceholderZtoA extends SortingType {
@Override
public String getChars(@NotNull TabPlayer p) {
char[] chars = setPlaceholders(p).toCharArray();
p.sortingData.teamNameNote += "\n-> " + sortingPlaceholder.getIdentifier() + " returned \"&e" + new String(chars) + "&r\". &r";
p.sortingData.teamNameNote += "\n-> " + sortingPlaceholder + " returned \"&e" + new String(chars) + "&r\". &r";
for (int i=0; i<chars.length; i++) {
char c = chars[i];
if (c >= 65 && c <= 90) {
@@ -28,7 +28,7 @@ public abstract class SortingType {
protected final int DEFAULT_NUMBER = Integer.MAX_VALUE / 2;
/** Placeholder to sort by, if sorting type uses it */
protected TabPlaceholder sortingPlaceholder;
protected String sortingPlaceholder;
/**
* Constructs new instance with given parameter
@@ -43,7 +43,7 @@ public abstract class SortingType {
TAB.getInstance().getConfigHelper().startup().invalidSortingPlaceholder(sortingPlaceholder, this);
} else {
sorting.addUsedPlaceholder(sortingPlaceholder);
this.sortingPlaceholder = TAB.getInstance().getPlaceholderManager().getPlaceholder(sortingPlaceholder);
this.sortingPlaceholder = sortingPlaceholder;
}
}
@@ -56,7 +56,8 @@ public abstract class SortingType {
*/
protected String setPlaceholders(TabPlayer player) {
if (sortingPlaceholder == null) return "";
return sortingPlaceholder.set(sortingPlaceholder.getIdentifier(), player);
TabPlaceholder placeholder = TAB.getInstance().getPlaceholderManager().getPlaceholder(sortingPlaceholder);
return placeholder.set(placeholder.getIdentifier(), player);
}
/**
@@ -80,27 +81,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();
}
@@ -90,7 +90,7 @@ public class ServerPlaceholderImpl extends TabPlaceholder implements ServerPlace
@Override
@NotNull
public String getLastValueSafe(@NotNull TabPlayer player) {
return identifier;
return lastValue;
}
/**
@@ -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
}
}
@@ -37,6 +37,12 @@ public abstract class Scoreboard<T extends TabPlayer, C> {
/** Player-to-Team map of expected teams of players */
private final Map<String, String> expectedTeams = new HashMap<>();
/** Map of blocked team adds, key is player and value is team name */
private final Map<String, String> blockedTeamAdds = new HashMap<>();
/** Map of allowed team adds, key is player and value is team name */
private final Map<String, String> allowedTeamAdds = new HashMap<>();
/** Flag tracking time between Login packet send and its processing */
private boolean frozen;
@@ -372,26 +378,48 @@ public abstract class Scoreboard<T extends TabPlayer, C> {
@NotNull
public Collection<String> onTeamPacket(int action, @NonNull String teamName, @NonNull Collection<String> players) {
Collection<String> newList = new ArrayList<>();
for (String entry : players) {
String expectedTeam = expectedTeams.get(entry);
if (expectedTeam == null) {
newList.add(entry);
continue;
}
if (!teamName.equals(expectedTeam)) {
// on REMOVE_PLAYER don't warn, just remove the player (required to prevent FPS drop, #1193)
// will still throw error and freeze if removing after team handling was paused (API, disable condition),
// since expected team is null, but add action was blocked previously but remove will not be blocked anymore,
// but that is a very specific case that people are unlikely to even reproduce
// workaround would be complicated, just let it be for now
if (action == TeamAction.CREATE || action == TeamAction.ADD_PLAYER) {
if (action == TeamAction.CREATE || action == TeamAction.ADD_PLAYER) {
for (String entry : players) {
String expectedTeam = expectedTeams.get(entry);
if (expectedTeam == null) {
blockedTeamAdds.remove(entry);
allowedTeamAdds.put(entry, teamName);
newList.add(entry);
continue;
}
if (teamName.equals(expectedTeam)) {
newList.add(entry);
allowedTeamAdds.remove(entry);
} else {
blockedTeamAdds.put(entry, teamName);
logTeamOverride(teamName, entry, expectedTeam);
}
} else {
newList.add(entry);
}
return newList;
}
return newList;
if (action == TeamAction.REMOVE_PLAYER) {
// TAB does not send remove player, making checks easier
for (String entry : players) {
String expectedTeam = expectedTeams.get(entry);
if (expectedTeam != null) {
allowedTeamAdds.remove(entry);
blockedTeamAdds.remove(entry);
continue;
}
if (allowedTeamAdds.containsKey(entry)) {
allowedTeamAdds.remove(entry);
newList.add(entry);
continue;
}
blockedTeamAdds.remove(entry);
}
return newList;
}
if (action == TeamAction.REMOVE) {
allowedTeamAdds.entrySet().removeIf(entry -> entry.getValue().equals(teamName));
blockedTeamAdds.entrySet().removeIf(entry -> entry.getValue().equals(teamName));
}
return players;
}
/**
@@ -403,7 +431,7 @@ public abstract class Scoreboard<T extends TabPlayer, C> {
* @param player
* Player who was about to be added into the team
* @param expectedTeam
* Expected name of the team
* Expected team
*/
public static void logTeamOverride(@NonNull String team, @NonNull String player, @NonNull String expectedTeam) {
String message = "Blocked attempt to add player " + player + " into team " + team + " (expected team: " + expectedTeam + ")";
@@ -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;
}
}
@@ -84,7 +84,12 @@ public class SpongeTabPlayer extends BackendTabPlayer {
public TabList.Skin getSkin() {
List<ProfileProperty> list = getPlayer().profile().properties();
if (list.isEmpty()) return null; // Offline mode
return new TabList.Skin(list.get(0).value(), list.get(0).signature().orElse(null));
for (ProfileProperty property : list) {
if (property.name().equals(TabList.TEXTURES_PROPERTY)) {
return new TabList.Skin(property.value(), property.signature().orElse(null));
}
}
return null;
}
@Override
@@ -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);
}
}
}
@@ -9,7 +9,6 @@ import me.neznamy.tab.platforms.velocity.features.VelocityRedisSupport;
import me.neznamy.tab.platforms.velocity.hook.VelocityPremiumVanishHook;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.TabConstants;
import me.neznamy.tab.shared.chat.EnumChatFormat;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.features.injection.PipelineInjector;
import me.neznamy.tab.shared.features.redis.RedisSupport;
@@ -18,6 +17,8 @@ import me.neznamy.tab.shared.hook.PremiumVanishHook;
import me.neznamy.tab.shared.proxy.ProxyPlatform;
import me.neznamy.tab.shared.util.ReflectionUtils;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
import org.bstats.charts.SimplePie;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -32,6 +33,9 @@ public class VelocityPlatform extends ProxyPlatform {
@NotNull
private final VelocityTAB plugin;
/** Logger for components */
private static final ComponentLogger logger = ComponentLogger.logger("TAB");
/** Plugin message channel */
@Getter
private final MinecraftChannelIdentifier MCI = MinecraftChannelIdentifier.from(TabConstants.PLUGIN_MESSAGE_CHANNEL_NAME);
@@ -68,12 +72,12 @@ public class VelocityPlatform extends ProxyPlatform {
@Override
public void logInfo(@NotNull TabComponent message) {
plugin.getLogger().info(message.toLegacyText());
logger.info(AdventureHook.toAdventureComponent(message, true));
}
@Override
public void logWarn(@NotNull TabComponent message) {
plugin.getLogger().warn(EnumChatFormat.RED + message.toLegacyText());
logger.warn(Component.text("").color(NamedTextColor.RED).append(AdventureHook.toAdventureComponent(message, true)));
}
@Override
@@ -7,7 +7,6 @@ import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.player.TabList;
import lombok.Getter;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.TabConstants;
@@ -18,7 +17,6 @@ import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import java.nio.file.Path;
import java.util.UUID;
/**
* Main class for Velocity.
@@ -54,9 +52,8 @@ public class VelocityTAB {
*/
@Subscribe
public void onProxyInitialization(@Nullable ProxyInitializeEvent event) {
if (!ReflectionUtils.methodExists(TabList.class, "getEntry", UUID.class)) {
logger.warn(EnumChatFormat.RED + "The plugin requires Velocity build #229 " +
"(released on February 20th, 2023) and up to work.");
if (!ReflectionUtils.classExists("net.kyori.adventure.text.logger.slf4j.ComponentLogger")) {
logger.warn(EnumChatFormat.RED + "The plugin requires Velocity build #274 (released on October 12th, 2023) and up to work.");
return;
}
TAB.create(new VelocityPlatform(this));
@@ -65,7 +65,12 @@ public class VelocityTabPlayer extends ProxyTabPlayer {
public TabList.Skin getSkin() {
List<GameProfile.Property> properties = getPlayer().getGameProfile().getProperties();
if (properties.isEmpty()) return null; //Offline mode
return new TabList.Skin(properties.get(0).getValue(), properties.get(0).getSignature());
for (GameProfile.Property property : properties) {
if (property.getName().equals(TabList.TEXTURES_PROPERTY)) {
return new TabList.Skin(property.getValue(), property.getSignature());
}
}
return null;
}
@Override