mirror of
https://github.com/NEZNAMY/TAB.git
synced 2026-11-12 20:22:01 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5c5502abe | ||
|
|
194e8ffbd9 | ||
|
|
ef39458abd | ||
|
|
6a6907fb0a | ||
|
|
8bb7c4a4a6 | ||
|
|
91700e7ed0 | ||
|
|
661c2e6fc3 | ||
|
|
3d053a6149 | ||
|
|
34179e4f62 | ||
|
|
a23e5d9f50 | ||
|
|
1cbcbf70d9 | ||
|
|
0a7371aaec | ||
|
|
da13e2d861 | ||
|
|
5b18fa8c25 | ||
|
|
347231850a | ||
|
|
b1f9bdc26c | ||
|
|
03c9b95041 | ||
|
|
6e7e1d783b | ||
|
|
cfb9b0a029 | ||
|
|
b7ea6e5af6 | ||
|
|
44104df712 | ||
|
|
5de20d1c58 | ||
|
|
d156303740 | ||
|
|
6e36eb3554 | ||
|
|
f7f3891817 | ||
|
|
1ec28856ff | ||
|
|
9658e0b74d | ||
|
|
86cd8d4151 | ||
|
|
2418eb206e | ||
|
|
08fa715d26 | ||
|
|
52426de283 | ||
|
|
64b3da14c4 | ||
|
|
bf7341c52c | ||
|
|
e3490564a2 | ||
|
|
6218f0ed16 | ||
|
|
54e8e1ea98 | ||
|
|
4cd50fb3d5 | ||
|
|
590286a6c2 | ||
|
|
6c96650dcc | ||
|
|
7c83a74fd8 | ||
|
|
7b3f60cb3b | ||
|
|
bfc845088a | ||
|
|
e67d93a592 | ||
|
|
b518b980ae | ||
|
|
744bc1403a |
No files matched your search
@@ -5,5 +5,12 @@ package me.neznamy.tab.api.bossbar;
|
||||
* Calling ordinal() will return color's network ID.
|
||||
*/
|
||||
public enum BarColor {
|
||||
PINK, BLUE, RED, GREEN, YELLOW, PURPLE, WHITE
|
||||
|
||||
PINK,
|
||||
BLUE,
|
||||
RED,
|
||||
GREEN,
|
||||
YELLOW,
|
||||
PURPLE,
|
||||
WHITE
|
||||
}
|
||||
@@ -1,22 +1,14 @@
|
||||
package me.neznamy.tab.api.bossbar;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* An enum representing all available BossBar styles.
|
||||
* Calling ordinal() will return style's network ID.
|
||||
* Style names are equal to NMS names.
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public enum BarStyle {
|
||||
|
||||
PROGRESS("SOLID"),
|
||||
NOTCHED_6("SEGMENTED_6"),
|
||||
NOTCHED_10("SEGMENTED_10"),
|
||||
NOTCHED_12("SEGMENTED_12"),
|
||||
NOTCHED_20("SEGMENTED_20");
|
||||
|
||||
/** Style's name used in Bukkit API */
|
||||
@Getter private final String bukkitName;
|
||||
PROGRESS,
|
||||
NOTCHED_6,
|
||||
NOTCHED_10,
|
||||
NOTCHED_12,
|
||||
NOTCHED_20
|
||||
}
|
||||
+1
-1
@@ -4,7 +4,7 @@ plugins {
|
||||
|
||||
allprojects {
|
||||
group = "me.neznamy"
|
||||
version = "4.0.4"
|
||||
version = "4.0.7"
|
||||
description = "An all-in-one solution that works"
|
||||
|
||||
ext.set("id", "tab")
|
||||
|
||||
@@ -111,7 +111,7 @@ public class BukkitPipelineInjector extends NettyPipelineInjector {
|
||||
if (actions.contains(TabList.Action.UPDATE_DISPLAY_NAME.name()) || actions.contains(TabList.Action.ADD_PLAYER.name())) {
|
||||
displayName = BukkitTabList.PlayerInfoData_DisplayName.get(nmsData);
|
||||
IChatBaseComponent newDisplayName = TAB.getInstance().getFeatureManager().onDisplayNameChange(receiver, id);
|
||||
if (newDisplayName != null) displayName = TAB.getInstance().getPlatform().toComponent(newDisplayName, receiver.getVersion());
|
||||
if (newDisplayName != null) displayName = ((BukkitTabPlayer)receiver).getPlatform().toComponent(newDisplayName, receiver.getVersion());
|
||||
if (!BukkitReflection.is1_19_3Plus()) BukkitTabList.PlayerInfoData_DisplayName.set(nmsData, displayName);
|
||||
}
|
||||
if (actions.contains(TabList.Action.UPDATE_LATENCY.name()) || actions.contains(TabList.Action.ADD_PLAYER.name())) {
|
||||
@@ -139,6 +139,11 @@ public class BukkitPipelineInjector extends NettyPipelineInjector {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLogin(@NotNull Object packet) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
@SneakyThrows
|
||||
|
||||
@@ -44,12 +44,13 @@ public class BukkitTAB extends JavaPlugin {
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
if (ProtocolVersion.fromFriendlyName(Bukkit.getBukkitVersion().split("-")[0]) == ProtocolVersion.UNKNOWN_SERVER_VERSION) {
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] Your server version is not compatible. " +
|
||||
"This plugin version was made for " + ProtocolVersion.values()[ProtocolVersion.values().length-1].getFriendlyName() +
|
||||
" - " + ProtocolVersion.values()[3].getFriendlyName() + ". Disabling."));
|
||||
Bukkit.getConsoleSender().sendMessage(String.format(
|
||||
"%s[TAB] Your server version is not compatible. This plugin version was made for %s - %s. Disabling.",
|
||||
EnumChatFormat.RED.getFormat(), ProtocolVersion.V1_5, ProtocolVersion.LATEST_KNOWN_VERSION
|
||||
));
|
||||
} else {
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] A compatibility issue " +
|
||||
"with your server was found. Unless you are running some really weird server software, this is a bug."));
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.RED.getFormat() + "[TAB] A compatibility issue " +
|
||||
"with your server was found. Unless you are running some really weird server software, this is a bug.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.mojang.authlib.properties.Property;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import me.neznamy.tab.platforms.bukkit.header.HeaderFooter;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.BukkitReflection;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
@@ -33,10 +34,6 @@ import java.util.*;
|
||||
public class BukkitTabList implements TabList {
|
||||
|
||||
// NMS Fields
|
||||
private static Class<?> HeaderFooterClass;
|
||||
private static Constructor<?> newHeaderFooter;
|
||||
private static Field HEADER;
|
||||
private static Field FOOTER;
|
||||
|
||||
public static Class<?> PlayerInfoClass;
|
||||
private static Constructor<?> newPlayerInfo;
|
||||
@@ -76,7 +73,6 @@ public class BukkitTabList implements TabList {
|
||||
IChatBaseComponent = Class.forName("net.minecraft.network.chat.Component");
|
||||
EntityPlayer = Class.forName("net.minecraft.server.level.ServerPlayer");
|
||||
EnumGamemodeClass = (Class<Enum>) Class.forName("net.minecraft.world.level.GameType");
|
||||
HeaderFooterClass = Class.forName("net.minecraft.network.protocol.game.ClientboundTabListPacket");
|
||||
if (BukkitReflection.is1_19_3Plus()) {
|
||||
ClientboundPlayerInfoRemovePacket = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket");
|
||||
PlayerInfoClass = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket");
|
||||
@@ -92,7 +88,6 @@ public class BukkitTabList implements TabList {
|
||||
IChatBaseComponent = Class.forName("net.minecraft.network.chat.IChatBaseComponent");
|
||||
EntityPlayer = Class.forName("net.minecraft.server.level.EntityPlayer");
|
||||
EnumGamemodeClass = (Class<Enum>) Class.forName("net.minecraft.world.level.EnumGamemode");
|
||||
HeaderFooterClass = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutPlayerListHeaderFooter");
|
||||
if (BukkitReflection.is1_19_3Plus()) {
|
||||
ClientboundPlayerInfoRemovePacket = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket");
|
||||
PlayerInfoClass = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket");
|
||||
@@ -107,25 +102,14 @@ public class BukkitTabList implements TabList {
|
||||
} else {
|
||||
IChatBaseComponent = BukkitReflection.getLegacyClass("IChatBaseComponent");
|
||||
EntityPlayer = BukkitReflection.getLegacyClass("EntityPlayer");
|
||||
HeaderFooterClass = BukkitReflection.getLegacyClass("PacketPlayOutPlayerListHeaderFooter");
|
||||
PlayerInfoClass = BukkitReflection.getLegacyClass("PacketPlayOutPlayerInfo");
|
||||
ActionClass = (Class<Enum>) BukkitReflection.getLegacyClass("PacketPlayOutPlayerInfo$EnumPlayerInfoAction", "EnumPlayerInfoAction");
|
||||
playerInfoDataClass = BukkitReflection.getLegacyClass("PacketPlayOutPlayerInfo$PlayerInfoData", "PlayerInfoData");
|
||||
EnumGamemodeClass = (Class<Enum>) BukkitReflection.getLegacyClass("EnumGamemode", "WorldSettings$EnumGamemode");
|
||||
}
|
||||
|
||||
// Header & Footer
|
||||
if (BukkitReflection.getMinorVersion() >= 17) {
|
||||
newHeaderFooter = HeaderFooterClass.getConstructor(IChatBaseComponent, IChatBaseComponent);
|
||||
} else {
|
||||
newHeaderFooter = HeaderFooterClass.getConstructor();
|
||||
HEADER = ReflectionUtils.getFields(HeaderFooterClass, IChatBaseComponent).get(0);
|
||||
FOOTER = ReflectionUtils.getFields(HeaderFooterClass, IChatBaseComponent).get(1);
|
||||
}
|
||||
|
||||
// Info packet
|
||||
PLAYERS = ReflectionUtils.getOnlyField(PlayerInfoClass, List.class);
|
||||
newPlayerInfoData = ReflectionUtils.getOnlyConstructor(playerInfoDataClass);
|
||||
newPlayerInfoData = playerInfoDataClass.getConstructors()[0]; // #1105, a specific 1.8.8 fork has 2 constructors
|
||||
PlayerInfoData_Profile = ReflectionUtils.getOnlyField(playerInfoDataClass, GameProfile.class);
|
||||
PlayerInfoData_Latency = ReflectionUtils.getOnlyField(playerInfoDataClass, int.class);
|
||||
PlayerInfoData_GameMode = ReflectionUtils.getOnlyField(playerInfoDataClass, EnumGamemodeClass);
|
||||
@@ -190,15 +174,7 @@ public class BukkitTabList implements TabList {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void setPlayerListHeaderFooter(@NotNull IChatBaseComponent header, @NotNull IChatBaseComponent footer) {
|
||||
if (HeaderFooterClass == null) return;
|
||||
if (BukkitReflection.getMinorVersion() >= 17) {
|
||||
player.sendPacket(newHeaderFooter.newInstance(toComponent(header), toComponent(footer)));
|
||||
} else {
|
||||
Object packet = newHeaderFooter.newInstance();
|
||||
HEADER.set(packet, toComponent(header));
|
||||
FOOTER.set(packet, toComponent(footer));
|
||||
player.sendPacket(packet);
|
||||
}
|
||||
if (HeaderFooter.getInstance() != null) HeaderFooter.getInstance().set(player, header, footer);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
|
||||
@@ -21,6 +21,26 @@ import java.util.UUID;
|
||||
@RequiredArgsConstructor
|
||||
public class BukkitBossBar implements BossBar {
|
||||
|
||||
/** Color array for fast access */
|
||||
private static final org.bukkit.boss.BarColor[] colors = new org.bukkit.boss.BarColor[] {
|
||||
org.bukkit.boss.BarColor.PINK,
|
||||
org.bukkit.boss.BarColor.BLUE,
|
||||
org.bukkit.boss.BarColor.RED,
|
||||
org.bukkit.boss.BarColor.GREEN,
|
||||
org.bukkit.boss.BarColor.YELLOW,
|
||||
org.bukkit.boss.BarColor.PURPLE,
|
||||
org.bukkit.boss.BarColor.WHITE
|
||||
};
|
||||
|
||||
/** Style array for fast access */
|
||||
private static final org.bukkit.boss.BarStyle[] styles = new org.bukkit.boss.BarStyle[] {
|
||||
org.bukkit.boss.BarStyle.SOLID,
|
||||
org.bukkit.boss.BarStyle.SEGMENTED_6,
|
||||
org.bukkit.boss.BarStyle.SEGMENTED_10,
|
||||
org.bukkit.boss.BarStyle.SEGMENTED_12,
|
||||
org.bukkit.boss.BarStyle.SEGMENTED_20
|
||||
};
|
||||
|
||||
/** Player this handler belongs to */
|
||||
@NotNull
|
||||
private final BukkitTabPlayer player;
|
||||
@@ -34,8 +54,9 @@ public class BukkitBossBar implements BossBar {
|
||||
if (bossBars.containsKey(id)) return;
|
||||
org.bukkit.boss.BossBar bar = Bukkit.createBossBar(
|
||||
BukkitUtils.toBukkitFormat(IChatBaseComponent.optimizedComponent(title), player.getVersion().getMinorVersion() >= 16),
|
||||
org.bukkit.boss.BarColor.valueOf(color.name()),
|
||||
org.bukkit.boss.BarStyle.valueOf(style.getBukkitName()));
|
||||
colors[color.ordinal()],
|
||||
styles[style.ordinal()]
|
||||
);
|
||||
bar.setProgress(progress);
|
||||
bar.addPlayer(player.getPlayer());
|
||||
bossBars.put(id, bar);
|
||||
@@ -53,12 +74,12 @@ public class BukkitBossBar implements BossBar {
|
||||
|
||||
@Override
|
||||
public void update(@NotNull UUID id, @NotNull BarStyle style) {
|
||||
bossBars.get(id).setStyle(org.bukkit.boss.BarStyle.valueOf(style.getBukkitName()));
|
||||
bossBars.get(id).setStyle(styles[style.ordinal()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull UUID id, @NotNull BarColor color) {
|
||||
bossBars.get(id).setColor(org.bukkit.boss.BarColor.valueOf(color.name()));
|
||||
bossBars.get(id).setColor(colors[color.ordinal()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,6 +21,26 @@ import java.util.UUID;
|
||||
@RequiredArgsConstructor
|
||||
public class ViaBossBar implements BossBar {
|
||||
|
||||
/** Color array for fast access */
|
||||
private static final BossColor[] colors = new BossColor[] {
|
||||
BossColor.PINK,
|
||||
BossColor.BLUE,
|
||||
BossColor.RED,
|
||||
BossColor.GREEN,
|
||||
BossColor.YELLOW,
|
||||
BossColor.PURPLE,
|
||||
BossColor.WHITE
|
||||
};
|
||||
|
||||
/** Style array for fast access */
|
||||
private static final BossStyle[] styles = new BossStyle[] {
|
||||
BossStyle.SOLID,
|
||||
BossStyle.SEGMENTED_6,
|
||||
BossStyle.SEGMENTED_10,
|
||||
BossStyle.SEGMENTED_12,
|
||||
BossStyle.SEGMENTED_20
|
||||
};
|
||||
|
||||
/** Player this handler belongs to */
|
||||
@NotNull
|
||||
private final BukkitTabPlayer player;
|
||||
@@ -35,8 +55,9 @@ public class ViaBossBar implements BossBar {
|
||||
com.viaversion.viaversion.api.legacy.bossbar.BossBar bar = Via.getAPI().legacyAPI().createLegacyBossBar(
|
||||
IChatBaseComponent.optimizedComponent(title).toString(player.getVersion()),
|
||||
progress,
|
||||
BossColor.valueOf(color.name()),
|
||||
BossStyle.valueOf(style.getBukkitName()));
|
||||
colors[color.ordinal()],
|
||||
styles[style.ordinal()]
|
||||
);
|
||||
viaBossBars.put(id, bar);
|
||||
bar.addPlayer(player.getPlayer().getUniqueId());
|
||||
}
|
||||
@@ -53,12 +74,12 @@ public class ViaBossBar implements BossBar {
|
||||
|
||||
@Override
|
||||
public void update(@NotNull UUID id, @NotNull BarStyle style) {
|
||||
viaBossBars.get(id).setStyle(BossStyle.valueOf(style.getBukkitName()));
|
||||
viaBossBars.get(id).setStyle(styles[style.ordinal()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull UUID id, @NotNull BarColor color) {
|
||||
viaBossBars.get(id).setColor(BossColor.valueOf(color.name()));
|
||||
viaBossBars.get(id).setColor(colors[color.ordinal()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package me.neznamy.tab.platforms.bukkit.header;
|
||||
|
||||
import lombok.Getter;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitUtils;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Header/footer sender using Bukkit API. Despite this feature getting
|
||||
* added into the game in 1.8, Bukkit team took 4 entire years to add
|
||||
* it to the API, which eventually made it there in 1.13. <p>
|
||||
* The input is just a String, meaning Bukkit will have to deserialize it
|
||||
* into components, which is a massive performance loss. It also does not
|
||||
* seem to support fonts.
|
||||
*/
|
||||
public class BukkitHeaderFooter extends HeaderFooter {
|
||||
|
||||
/** Flag tracking whether this class can be used on current server */
|
||||
@Getter
|
||||
private static final boolean available = ReflectionUtils.methodExists(Player.class, "setPlayerListHeaderFooter", String.class, String.class);
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation") // Marked as deprecated by Paper to make us use their methods instead
|
||||
public void set(@NotNull BukkitTabPlayer player, @NotNull IChatBaseComponent header, @NotNull IChatBaseComponent footer) {
|
||||
player.getPlayer().setPlayerListHeaderFooter(
|
||||
BukkitUtils.toBukkitFormat(header, player.getVersion().getMinorVersion() >= 16),
|
||||
BukkitUtils.toBukkitFormat(footer, player.getVersion().getMinorVersion() >= 16)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package me.neznamy.tab.platforms.bukkit.header;
|
||||
|
||||
import lombok.Getter;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.BukkitReflection;
|
||||
import me.neznamy.tab.shared.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A class responsible for sending header/footer to players on request.
|
||||
*/
|
||||
public abstract class HeaderFooter {
|
||||
|
||||
/** Instance of the class, null if no implementation is available */
|
||||
@Getter
|
||||
@Nullable
|
||||
private static HeaderFooter instance;
|
||||
|
||||
/**
|
||||
* Finds the best available instance for current server software.
|
||||
*/
|
||||
public static void findInstance() {
|
||||
if (PacketHeaderFooter.isAvailable()) {
|
||||
instance = new PacketHeaderFooter();
|
||||
} else if (PaperHeaderFooter.isAvailable()) {
|
||||
instance = new PaperHeaderFooter();
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.RED.getFormat() + "[TAB] Failed to initialize NMS fields for " +
|
||||
"sending Header/Footer due to a compatibility error. Using fallback solution using Paper API.");
|
||||
} else if (BukkitHeaderFooter.isAvailable()) {
|
||||
instance = new BukkitHeaderFooter();
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.RED.getFormat() + "[TAB] Failed to initialize NMS fields for " +
|
||||
"sending Header/Footer due to a compatibility error. Using fallback solution using Bukkit API. " +
|
||||
"This will drastically drop performance, as well as miss support for fonts (added in 1.16). " +
|
||||
"Please update the plugin with to version proper support for your server version.");
|
||||
} else if (BukkitReflection.getMinorVersion() >= 8){
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.RED.getFormat() + "[TAB] Failed to initialize NMS fields for " +
|
||||
"sending Header/Footer due to a compatibility error. No fallback solution was found either. This will " +
|
||||
"result in the feature not working. " +
|
||||
"Please update the plugin with to version proper support for your server version.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends header/footer to player.
|
||||
*
|
||||
* @param player
|
||||
* Player to send header/footer to.
|
||||
* @param header
|
||||
* Header to use.
|
||||
* @param footer
|
||||
* Footer to use.
|
||||
*/
|
||||
public abstract void set(@NotNull BukkitTabPlayer player, @NotNull IChatBaseComponent header, @NotNull IChatBaseComponent footer);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package me.neznamy.tab.platforms.bukkit.header;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.BukkitReflection;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* Header/footer sender that uses NMS to send packets. Available
|
||||
* on all versions since 1.8 when the feature was added into the game.
|
||||
*/
|
||||
public class PacketHeaderFooter extends HeaderFooter {
|
||||
|
||||
private static Constructor<?> newHeaderFooter;
|
||||
private static Field HEADER;
|
||||
private static Field FOOTER;
|
||||
|
||||
@Getter
|
||||
private static boolean available;
|
||||
|
||||
static {
|
||||
try {
|
||||
if (BukkitReflection.getMinorVersion() >= 8) {
|
||||
Class<?> IChatBaseComponent;
|
||||
Class<?> HeaderFooterClass;
|
||||
if (BukkitReflection.isMojangMapped()) {
|
||||
IChatBaseComponent = Class.forName("net.minecraft.network.chat.Component");
|
||||
HeaderFooterClass = Class.forName("net.minecraft.network.protocol.game.ClientboundTabListPacket");
|
||||
} else if (BukkitReflection.getMinorVersion() >= 17) {
|
||||
IChatBaseComponent = Class.forName("net.minecraft.network.chat.IChatBaseComponent");
|
||||
HeaderFooterClass = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutPlayerListHeaderFooter");
|
||||
} else {
|
||||
IChatBaseComponent = BukkitReflection.getLegacyClass("IChatBaseComponent");
|
||||
HeaderFooterClass = BukkitReflection.getLegacyClass("PacketPlayOutPlayerListHeaderFooter");
|
||||
}
|
||||
if (BukkitReflection.getMinorVersion() >= 17) {
|
||||
newHeaderFooter = HeaderFooterClass.getConstructor(IChatBaseComponent, IChatBaseComponent);
|
||||
} else {
|
||||
newHeaderFooter = HeaderFooterClass.getConstructor();
|
||||
HEADER = ReflectionUtils.getFields(HeaderFooterClass, IChatBaseComponent).get(0);
|
||||
FOOTER = ReflectionUtils.getFields(HeaderFooterClass, IChatBaseComponent).get(1);
|
||||
}
|
||||
available = true;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
// Print exception to find out what went wrong
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public void set(@NotNull BukkitTabPlayer player, @NotNull IChatBaseComponent header, @NotNull IChatBaseComponent footer) {
|
||||
Object headerComponent = player.getPlatform().toComponent(header, player.getVersion());
|
||||
Object footerComponent = player.getPlatform().toComponent(footer, player.getVersion());
|
||||
if (BukkitReflection.getMinorVersion() >= 17) {
|
||||
player.sendPacket(newHeaderFooter.newInstance(headerComponent, footerComponent));
|
||||
} else {
|
||||
Object packet = newHeaderFooter.newInstance();
|
||||
HEADER.set(packet, headerComponent);
|
||||
FOOTER.set(packet, footerComponent);
|
||||
player.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package me.neznamy.tab.platforms.bukkit.header;
|
||||
|
||||
import lombok.Getter;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.hook.AdventureHook;
|
||||
import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Header/footer sender using Paper's API added in 1.16.5.
|
||||
* Due to lack of component cache for adventure components in TAB,
|
||||
* there is a performance loss compared to using NMS. However, we do not
|
||||
* need to serialize/deserialize anything ourselves thanks to direct component
|
||||
* conversion, so in the end it is roughly the same.
|
||||
*/
|
||||
public class PaperHeaderFooter extends HeaderFooter {
|
||||
|
||||
/** Flag tracking whether this class can be used on current server */
|
||||
@Getter
|
||||
private static final boolean available = ReflectionUtils.classExists("net.kyori.adventure.text.Component") &&
|
||||
ReflectionUtils.methodExists(Player.class, "sendPlayerListHeaderAndFooter", Component.class, Component.class);
|
||||
|
||||
@Override
|
||||
public void set(@NotNull BukkitTabPlayer player, @NotNull IChatBaseComponent header, @NotNull IChatBaseComponent footer) {
|
||||
player.getPlayer().sendPlayerListHeaderAndFooter(
|
||||
AdventureHook.toAdventureComponent(header, player.getVersion()),
|
||||
AdventureHook.toAdventureComponent(footer, player.getVersion())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package me.neznamy.tab.platforms.bukkit.nms;
|
||||
|
||||
import lombok.*;
|
||||
import me.neznamy.tab.platforms.bukkit.platform.BukkitPlatform;
|
||||
import me.neznamy.tab.shared.ProtocolVersion;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.backend.EntityData;
|
||||
@@ -73,17 +74,21 @@ public class DataWatcher implements EntityData {
|
||||
*/
|
||||
public static void load() throws ReflectiveOperationException {
|
||||
int minorVersion = BukkitReflection.getMinorVersion();
|
||||
Class<?> Entity;
|
||||
if (BukkitReflection.isMojangMapped()) {
|
||||
Entity = Class.forName("net.minecraft.world.entity.Entity");
|
||||
DataWatcher = Class.forName("net.minecraft.network.syncher.SynchedEntityData");
|
||||
DataWatcherObject = Class.forName("net.minecraft.network.syncher.EntityDataAccessor");
|
||||
DataWatcherRegistry = Class.forName("net.minecraft.network.syncher.EntityDataSerializers");
|
||||
DataWatcherSerializer = Class.forName("net.minecraft.network.syncher.EntityDataSerializer");
|
||||
} else if (minorVersion >= 17) {
|
||||
Entity = Class.forName("net.minecraft.world.entity.Entity");
|
||||
DataWatcher = Class.forName("net.minecraft.network.syncher.DataWatcher");
|
||||
DataWatcherObject = Class.forName("net.minecraft.network.syncher.DataWatcherObject");
|
||||
DataWatcherRegistry = Class.forName("net.minecraft.network.syncher.DataWatcherRegistry");
|
||||
DataWatcherSerializer = Class.forName("net.minecraft.network.syncher.DataWatcherSerializer");
|
||||
} else {
|
||||
Entity = BukkitReflection.getLegacyClass("Entity");
|
||||
DataWatcher = BukkitReflection.getLegacyClass("DataWatcher");
|
||||
if (minorVersion >= 9) {
|
||||
DataWatcherObject = BukkitReflection.getLegacyClass("DataWatcherObject");
|
||||
@@ -91,47 +96,46 @@ public class DataWatcher implements EntityData {
|
||||
DataWatcherSerializer = BukkitReflection.getLegacyClass("DataWatcherSerializer");
|
||||
}
|
||||
}
|
||||
newDataWatcher = ReflectionUtils.getOnlyConstructor(DataWatcher);
|
||||
if (BukkitReflection.isMojangMapped()) {
|
||||
DataWatcher_register = DataWatcher.getMethod("define", DataWatcherObject, Object.class);
|
||||
} else if (minorVersion >= 9) {
|
||||
DataWatcher_register = ReflectionUtils.getMethod(DataWatcher, new String[]{"register", "a", "m_135372_"}, DataWatcherObject, Object.class); // {Bukkit, Bukkit 1.18+, Mohist 1.18.2}
|
||||
if (minorVersion >= 7) {
|
||||
newDataWatcher = DataWatcher.getConstructor(Entity);
|
||||
} else {
|
||||
newDataWatcher = DataWatcher.getConstructor();
|
||||
}
|
||||
if (minorVersion >= 9) {
|
||||
DataWatcher_register = ReflectionUtils.getMethod(
|
||||
DataWatcher,
|
||||
new String[]{"define", "register", "a", "m_135372_"}, // {Bukkit 1.20.2+, Bukkit, Bukkit 1.18+, Mohist 1.18.2}
|
||||
DataWatcherObject, Object.class
|
||||
);
|
||||
} else {
|
||||
DataWatcher_register = ReflectionUtils.getMethod(DataWatcher, new String[]{"func_75682_a", "a"}, int.class, Object.class); // {Thermos 1.7.10, Bukkit}
|
||||
}
|
||||
if (minorVersion >= 19) {
|
||||
if (BukkitReflection.isMojangMapped()) {
|
||||
DataWatcher_packDirty = DataWatcher.getMethod("packDirty");
|
||||
} else {
|
||||
DataWatcher_packDirty = DataWatcher.getMethod("b");
|
||||
}
|
||||
DataWatcher_packDirty = ReflectionUtils.getMethod(DataWatcher, new String[] {"packDirty", "b"}); // {Mojang | 1.20.2+, 1.20.2-}
|
||||
}
|
||||
if (BukkitReflection.is1_19_3Plus()) {
|
||||
DataWatcher_markDirty = ReflectionUtils.getOnlyMethod(DataWatcher, void.class, DataWatcherObject);
|
||||
DataWatcher_markDirty = ReflectionUtils.getMethods(DataWatcher, void.class, DataWatcherObject).get(0);
|
||||
}
|
||||
if (minorVersion >= 9) {
|
||||
newDataWatcherObject = DataWatcherObject.getConstructor(int.class, DataWatcherSerializer);
|
||||
DataWatcherSerializer_BYTE = ReflectionUtils.getField(DataWatcherRegistry, "BYTE", "a", "f_135027_").get(null); // Mohist 1.18.2
|
||||
DataWatcherSerializer_FLOAT = ReflectionUtils.getField(DataWatcherRegistry, "FLOAT", "c", "f_135029_").get(null); // Mohist 1.18.2
|
||||
DataWatcherSerializer_STRING = ReflectionUtils.getField(DataWatcherRegistry, "STRING", "d", "f_135030_").get(null); // Mohist 1.18.2
|
||||
if (BukkitReflection.isMojangMapped()) {
|
||||
DataWatcherSerializer_OPTIONAL_COMPONENT = DataWatcherRegistry.getDeclaredField("OPTIONAL_COMPONENT").get(null);
|
||||
DataWatcherSerializer_BOOLEAN = DataWatcherRegistry.getDeclaredField("BOOLEAN").get(null);
|
||||
} else {
|
||||
if (BukkitReflection.is1_19_3Plus()) {
|
||||
DataWatcherSerializer_OPTIONAL_COMPONENT = DataWatcherRegistry.getDeclaredField("g").get(null);
|
||||
if (BukkitReflection.is1_19_4Plus()) {
|
||||
DataWatcherSerializer_BOOLEAN = DataWatcherRegistry.getDeclaredField("k").get(null);
|
||||
} else {
|
||||
DataWatcherSerializer_BOOLEAN = DataWatcherRegistry.getDeclaredField("j").get(null);
|
||||
}
|
||||
if (BukkitReflection.is1_19_3Plus()) {
|
||||
DataWatcherSerializer_OPTIONAL_COMPONENT = ReflectionUtils.getField(DataWatcherRegistry, "OPTIONAL_COMPONENT", "g").get(null);
|
||||
if (BukkitReflection.is1_19_4Plus()) {
|
||||
DataWatcherSerializer_BOOLEAN = ReflectionUtils.getField(DataWatcherRegistry, "BOOLEAN", "k").get(null);
|
||||
} else {
|
||||
if (minorVersion >= 13) {
|
||||
DataWatcherSerializer_OPTIONAL_COMPONENT = ReflectionUtils.getField(DataWatcherRegistry, "f", "f_135032_").get(null); // Mohist 1.18.2
|
||||
DataWatcherSerializer_BOOLEAN = ReflectionUtils.getField(DataWatcherRegistry, "i", "f_135035_").get(null); // Mohist 1.18.2
|
||||
} else {
|
||||
DataWatcherSerializer_BOOLEAN = DataWatcherRegistry.getDeclaredField("h").get(null);
|
||||
}
|
||||
DataWatcherSerializer_BOOLEAN = ReflectionUtils.getField(DataWatcherRegistry, "BOOLEAN", "j").get(null);
|
||||
}
|
||||
} else {
|
||||
if (minorVersion >= 13) {
|
||||
DataWatcherSerializer_OPTIONAL_COMPONENT = ReflectionUtils.getField(DataWatcherRegistry,
|
||||
"OPTIONAL_COMPONENT", "f", "f_135032_").get(null); // Mohist 1.18.2
|
||||
DataWatcherSerializer_BOOLEAN = ReflectionUtils.getField(DataWatcherRegistry,
|
||||
"BOOLEAN", "i", "f_135035_").get(null); // Mohist 1.18.2
|
||||
} else {
|
||||
DataWatcherSerializer_BOOLEAN = DataWatcherRegistry.getDeclaredField("h").get(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,7 +176,7 @@ public class DataWatcher implements EntityData {
|
||||
public void setCustomName(@NotNull String customName, @NotNull ProtocolVersion clientVersion) {
|
||||
if (BukkitReflection.getMinorVersion() >= 13) {
|
||||
setValue(2, DataWatcherSerializer_OPTIONAL_COMPONENT,
|
||||
Optional.of(TAB.getInstance().getPlatform().toComponent(IChatBaseComponent.optimizedComponent(customName), clientVersion)));
|
||||
Optional.of(((BukkitPlatform)TAB.getInstance().getPlatform()).toComponent(IChatBaseComponent.optimizedComponent(customName), clientVersion)));
|
||||
} else if (BukkitReflection.getMinorVersion() >= 8) {
|
||||
setValue(2, DataWatcherSerializer_STRING, customName);
|
||||
} else {
|
||||
@@ -285,4 +289,4 @@ public class DataWatcher implements EntityData {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.SneakyThrows;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitTabList;
|
||||
import me.neznamy.tab.platforms.bukkit.header.HeaderFooter;
|
||||
import me.neznamy.tab.platforms.bukkit.scoreboard.PacketScoreboard;
|
||||
import me.neznamy.tab.shared.ProtocolVersion;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
@@ -74,11 +75,12 @@ public class NMSStorage {
|
||||
if (minorVersion >= 8) {
|
||||
ChatSerializer_DESERIALIZE = ReflectionUtils.getMethods(ChatSerializer, Object.class, String.class).get(0);
|
||||
CHANNEL = ReflectionUtils.getOnlyField(NetworkManager, Channel.class);
|
||||
try {
|
||||
getProfile = ReflectionUtils.getOnlyMethod(EntityHuman, GameProfile.class);
|
||||
} catch (IllegalStateException catServer) {
|
||||
getProfile = ReflectionUtils.getMethod(EntityHuman, new String[] {"getProfile"});
|
||||
}
|
||||
|
||||
// There is only supposed to be one, however there are exceptions:
|
||||
// #1 - CatServer adds another method
|
||||
// #2 - Random mods may perform deep hack into the server and add another one (see #1089)
|
||||
// Get first and hope for the best, alternatively players may not have correct skins in layout, but who cares
|
||||
getProfile = ReflectionUtils.getMethods(EntityHuman, GameProfile.class).get(0);
|
||||
}
|
||||
PLAYER_CONNECTION = ReflectionUtils.getOnlyField(EntityPlayer, PlayerConnection);
|
||||
getHandle = Class.forName("org.bukkit.craftbukkit." + serverPackage + ".entity.CraftPlayer").getMethod("getHandle");
|
||||
@@ -86,6 +88,7 @@ public class NMSStorage {
|
||||
DataWatcher.load();
|
||||
PacketEntityView.load();
|
||||
PacketScoreboard.load();
|
||||
HeaderFooter.findInstance();
|
||||
if (minorVersion < 17) {
|
||||
PING = ReflectionUtils.getField(EntityPlayer, "ping", "field_71138_i"); // 1.5.2 - 1.16.5, 1.7.10 Thermos
|
||||
}
|
||||
|
||||
@@ -174,12 +174,10 @@ public class PacketEntityView implements EntityView {
|
||||
Class<?> Vec3D = getClass("world.phys.Vec3", "world.phys.Vec3D");
|
||||
Vec3D_Empty = ReflectionUtils.getOnlyField(Vec3D, Vec3D).get(null);
|
||||
Class<?> EntityTypes = getClass("world.entity.EntityType", "world.entity.EntityTypes");
|
||||
if (BukkitReflection.isMojangMapped()) {
|
||||
EntityTypes_ARMOR_STAND = EntityTypes.getDeclaredField("ARMOR_STAND").get(null);
|
||||
} else if (BukkitReflection.getMinorVersion() >= 19) {
|
||||
EntityTypes_ARMOR_STAND = EntityTypes.getDeclaredField("d").get(null);
|
||||
if (BukkitReflection.getMinorVersion() >= 19) {
|
||||
EntityTypes_ARMOR_STAND = ReflectionUtils.getField(EntityTypes, "ARMOR_STAND", "d").get(null);
|
||||
} else {
|
||||
EntityTypes_ARMOR_STAND = ReflectionUtils.getField(EntityTypes, "c", "f_20529_").get(null); // Mohist 1.18.2
|
||||
EntityTypes_ARMOR_STAND = ReflectionUtils.getField(EntityTypes, "ARMOR_STAND", "c", "f_20529_").get(null); // Mohist 1.18.2
|
||||
}
|
||||
if (BukkitReflection.getMinorVersion() >= 19) {
|
||||
newSpawnEntity = SpawnEntityClass.getConstructor(int.class, UUID.class, double.class, double.class, double.class, float.class, float.class, EntityTypes, int.class, Vec3D, double.class);
|
||||
|
||||
@@ -47,7 +47,7 @@ import java.lang.reflect.Field;
|
||||
* Implementation of Platform interface for Bukkit platform
|
||||
*/
|
||||
@Getter
|
||||
public class BukkitPlatform implements BackendPlatform<Object> {
|
||||
public class BukkitPlatform implements BackendPlatform {
|
||||
|
||||
/** Plugin instance for registering tasks and events */
|
||||
@NotNull
|
||||
@@ -233,7 +233,15 @@ public class BukkitPlatform implements BackendPlatform<Object> {
|
||||
return plugin.getDataFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Converts internal component class to platform's component class
|
||||
*
|
||||
* @param component
|
||||
* Component to convert
|
||||
* @param version
|
||||
* Game version to convert component for
|
||||
* @return Converted component
|
||||
*/
|
||||
public Object toComponent(@NotNull IChatBaseComponent component, @NotNull ProtocolVersion version) {
|
||||
return NMSStorage.getInstance().componentCache.get(component, version);
|
||||
}
|
||||
|
||||
+95
-42
@@ -37,7 +37,6 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
private static Constructor<?> newDisplayObjective;
|
||||
public static Field DisplayObjective_POSITION;
|
||||
public static Field DisplayObjective_OBJECTIVE_NAME;
|
||||
public static Enum[] DisplaySlot_values;
|
||||
|
||||
// PacketPlayOutScoreboardScore
|
||||
private static Class<Enum> EnumScoreboardAction;
|
||||
@@ -67,7 +66,6 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
public static Field TeamPacket_PLAYERS;
|
||||
private static Class<Enum> EnumNameTagVisibility;
|
||||
private static Class<Enum> EnumTeamPush;
|
||||
private static Class<Enum> EnumChatFormatClass;
|
||||
private static Constructor<?> newScoreboardTeam;
|
||||
private static Method ScoreboardTeam_getPlayerNameSet;
|
||||
private static Method ScoreboardTeam_setNameTagVisibility;
|
||||
@@ -78,6 +76,13 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
private static Method ScoreboardTeam_setAllowFriendlyFire;
|
||||
private static Method ScoreboardTeam_setCanSeeFriendlyInvisibles;
|
||||
|
||||
private static Enum[] scoreboardActions;
|
||||
private static Enum[] displaySlots;
|
||||
private static Enum[] nameVisibilities;
|
||||
private static Enum[] collisionRules;
|
||||
private static Enum[] healthDisplays;
|
||||
private static Enum[] chatFormats;
|
||||
|
||||
public static void load() throws ReflectiveOperationException {
|
||||
int minorVersion = BukkitReflection.getMinorVersion();
|
||||
Class<?> scoreboardTeam;
|
||||
@@ -87,9 +92,10 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
Class<?> scoreboard;
|
||||
Class<?> scorePacketClass;
|
||||
Class<?> IChatBaseComponent = null;
|
||||
Class<Enum> enumChatFormatClass;
|
||||
if (BukkitReflection.isMojangMapped()) {
|
||||
IChatBaseComponent = Class.forName("net.minecraft.network.chat.Component");
|
||||
EnumChatFormatClass = (Class<Enum>) Class.forName("net.minecraft.ChatFormatting");
|
||||
enumChatFormatClass = (Class<Enum>) Class.forName("net.minecraft.ChatFormatting");
|
||||
DisplayObjectiveClass = Class.forName("net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket");
|
||||
ObjectivePacketClass = Class.forName("net.minecraft.network.protocol.game.ClientboundSetObjectivePacket");
|
||||
scoreboard = Class.forName("net.minecraft.world.scores.Scoreboard");
|
||||
@@ -105,7 +111,7 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
EnumTeamPush = (Class<Enum>) Class.forName("net.minecraft.world.scores.Team$CollisionRule");
|
||||
} else if (minorVersion >= 17) {
|
||||
IChatBaseComponent = Class.forName("net.minecraft.network.chat.IChatBaseComponent");
|
||||
EnumChatFormatClass = (Class<Enum>) Class.forName("net.minecraft.EnumChatFormat");
|
||||
enumChatFormatClass = (Class<Enum>) Class.forName("net.minecraft.EnumChatFormat");
|
||||
DisplayObjectiveClass = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutScoreboardDisplayObjective");
|
||||
ObjectivePacketClass = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutScoreboardObjective");
|
||||
scoreboard = Class.forName("net.minecraft.world.scores.Scoreboard");
|
||||
@@ -120,7 +126,7 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
EnumNameTagVisibility = (Class<Enum>) Class.forName("net.minecraft.world.scores.ScoreboardTeamBase$EnumNameTagVisibility");
|
||||
EnumTeamPush = (Class<Enum>) Class.forName("net.minecraft.world.scores.ScoreboardTeamBase$EnumTeamPush");
|
||||
} else {
|
||||
EnumChatFormatClass = (Class<Enum>) getLegacyClass("EnumChatFormat");
|
||||
enumChatFormatClass = (Class<Enum>) getLegacyClass("EnumChatFormat");
|
||||
DisplayObjectiveClass = getLegacyClass("PacketPlayOutScoreboardDisplayObjective", "Packet208SetScoreboardDisplayObjective");
|
||||
ObjectivePacketClass = getLegacyClass("PacketPlayOutScoreboardObjective", "Packet206SetScoreboardObjective");
|
||||
TeamPacketClass = getLegacyClass("PacketPlayOutScoreboardTeam", "Packet209SetScoreboardTeam");
|
||||
@@ -148,7 +154,7 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
Class<?> DisplaySlot = Class.forName("net.minecraft.world.scores.DisplaySlot");
|
||||
DisplayObjective_POSITION = ReflectionUtils.getOnlyField(DisplayObjectiveClass, DisplaySlot);
|
||||
newDisplayObjective = DisplayObjectiveClass.getConstructor(DisplaySlot, scoreboardObjective);
|
||||
DisplaySlot_values = (Enum[]) DisplaySlot.getDeclaredMethod("values").invoke(null);
|
||||
displaySlots = (Enum[]) DisplaySlot.getDeclaredMethod("values").invoke(null);
|
||||
} else {
|
||||
DisplayObjective_POSITION = ReflectionUtils.getOnlyField(DisplayObjectiveClass, int.class);
|
||||
newDisplayObjective = DisplayObjectiveClass.getConstructor(int.class, scoreboardObjective);
|
||||
@@ -168,7 +174,12 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
newScorePacket_1_13 = scorePacketClass.getConstructor(EnumScoreboardAction, String.class, String.class, int.class);
|
||||
newObjectivePacket = ObjectivePacketClass.getConstructor(scoreboardObjective, int.class);
|
||||
Objective_DISPLAY_NAME = ReflectionUtils.getOnlyField(ObjectivePacketClass, IChatBaseComponent);
|
||||
ScoreboardTeam_setColor = ReflectionUtils.getOnlyMethod(scoreboardTeam, void.class, EnumChatFormatClass);
|
||||
ScoreboardTeam_setColor = ReflectionUtils.getOnlyMethod(scoreboardTeam, void.class, enumChatFormatClass);
|
||||
scoreboardActions = new Enum[] {
|
||||
Enum.valueOf(EnumScoreboardAction, "CHANGE"),
|
||||
Enum.valueOf(EnumScoreboardAction, "REMOVE")
|
||||
};
|
||||
chatFormats = (Enum[]) enumChatFormatClass.getMethod("values").invoke(null);
|
||||
} else {
|
||||
newScorePacket_String = scorePacketClass.getConstructor(String.class);
|
||||
newObjectivePacket = ObjectivePacketClass.getConstructor();
|
||||
@@ -180,8 +191,21 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
newScorePacket = scorePacketClass.getConstructor(scoreboardScoreClass, int.class);
|
||||
}
|
||||
}
|
||||
if (minorVersion >= 8) {
|
||||
nameVisibilities = new Enum[] {
|
||||
Enum.valueOf(EnumNameTagVisibility, "ALWAYS"),
|
||||
Enum.valueOf(EnumNameTagVisibility, "NEVER"),
|
||||
Enum.valueOf(EnumNameTagVisibility, "HIDE_FOR_OTHER_TEAMS"),
|
||||
Enum.valueOf(EnumNameTagVisibility, "HIDE_FOR_OWN_TEAM")
|
||||
};
|
||||
healthDisplays = new Enum[] {
|
||||
Enum.valueOf(EnumScoreboardHealthDisplay, "INTEGER"),
|
||||
Enum.valueOf(EnumScoreboardHealthDisplay, "HEARTS")
|
||||
};
|
||||
}
|
||||
if (minorVersion >= 9) {
|
||||
ScoreboardTeam_setCollisionRule = ReflectionUtils.getOnlyMethod(scoreboardTeam, void.class, EnumTeamPush);
|
||||
collisionRules = (Enum[]) EnumTeamPush.getMethod("values").invoke(null); // <1.13 has wrong enum constant names
|
||||
}
|
||||
if (minorVersion >= 17) {
|
||||
TeamPacketConstructor_of = ReflectionUtils.getOnlyMethod(TeamPacketClass, TeamPacketClass, scoreboardTeam);
|
||||
@@ -189,27 +213,50 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
} else {
|
||||
newTeamPacket = TeamPacketClass.getConstructor(scoreboardTeam, int.class);
|
||||
}
|
||||
if (BukkitReflection.isMojangMapped()) {
|
||||
ScoreboardScore_setScore = scoreboardScoreClass.getMethod("setScore", int.class);
|
||||
ScoreboardTeam_setAllowFriendlyFire = scoreboardTeam.getMethod("setAllowFriendlyFire", boolean.class);
|
||||
ScoreboardTeam_setCanSeeFriendlyInvisibles = scoreboardTeam.getMethod("setSeeFriendlyInvisibles", boolean.class);
|
||||
ScoreboardTeam_setPrefix = scoreboardTeam.getMethod("setPlayerPrefix", IChatBaseComponent);
|
||||
ScoreboardTeam_setSuffix = scoreboardTeam.getMethod("setPlayerSuffix", IChatBaseComponent);
|
||||
ScoreboardTeam_setNameTagVisibility = scoreboardTeam.getMethod("setNameTagVisibility", EnumNameTagVisibility);
|
||||
ScoreboardScore_setScore = ReflectionUtils.getMethod(
|
||||
scoreboardScoreClass,
|
||||
new String[] {"func_96647_c", "setScore", "b", "c", "m_83402_"}, // {Thermos, 1.5.1 - 1.17.1 & 1.20.2+, 1.18 - 1.20.1, 1.5, Mohist 1.18.2}
|
||||
int.class
|
||||
);
|
||||
ScoreboardTeam_setAllowFriendlyFire = ReflectionUtils.getMethod(
|
||||
scoreboardTeam,
|
||||
new String[] {"func_96660_a", "setAllowFriendlyFire", "a", "m_83355_"}, // {Thermos, 1.5.1+, 1.5 & 1.18+, Mohist 1.18.2}
|
||||
boolean.class
|
||||
);
|
||||
ScoreboardTeam_setCanSeeFriendlyInvisibles = ReflectionUtils.getMethod(
|
||||
scoreboardTeam,
|
||||
new String[] {"func_98300_b", "setCanSeeFriendlyInvisibles", "b", "m_83362_", "setSeeFriendlyInvisibles"}, // {Thermos, 1.5.1+, 1.5 & 1.18+, Mohist 1.18.2, 1.20.2+}
|
||||
boolean.class
|
||||
);
|
||||
if (minorVersion >= 13) {
|
||||
ScoreboardTeam_setPrefix = ReflectionUtils.getMethod(
|
||||
scoreboardTeam,
|
||||
new String[]{"setPrefix", "b", "m_83360_", "setPlayerPrefix"}, // {1.17.1-, 1.18 - 1.20.1, Mohist 1.18.2, 1.20.2+}
|
||||
IChatBaseComponent
|
||||
);
|
||||
ScoreboardTeam_setSuffix = ReflectionUtils.getMethod(
|
||||
scoreboardTeam,
|
||||
new String[]{"setSuffix", "c", "m_83365_", "setPlayerSuffix"}, // {1.17.1-, 1.18 - 1.20.1, Mohist 1.18.2, 1.20.2+}
|
||||
IChatBaseComponent
|
||||
);
|
||||
} else {
|
||||
ScoreboardScore_setScore = ReflectionUtils.getMethod(scoreboardScoreClass, new String[] {"func_96647_c", "setScore", "b", "c", "m_83402_"}, int.class); // {Thermos, 1.5.1 - 1.17.1, 1.18+, 1.5, Mohist 1.18.2}
|
||||
ScoreboardTeam_setAllowFriendlyFire = ReflectionUtils.getMethod(scoreboardTeam, new String[] {"func_96660_a", "setAllowFriendlyFire", "a", "m_83355_"}, boolean.class); // {Thermos, 1.5.1+, 1.5 & 1.18+, Mohist 1.18.2}
|
||||
ScoreboardTeam_setCanSeeFriendlyInvisibles = ReflectionUtils.getMethod(scoreboardTeam, new String[] {"func_98300_b", "setCanSeeFriendlyInvisibles", "b", "m_83362_"}, boolean.class); // {Thermos, 1.5.1+, 1.5 & 1.18+, Mohist 1.18.2}
|
||||
if (minorVersion >= 13) {
|
||||
ScoreboardTeam_setPrefix = ReflectionUtils.getMethod(scoreboardTeam, new String[]{"setPrefix", "b", "m_83360_"}, IChatBaseComponent); // {1.17.1-, 1.18+, Mohist 1.18.2}
|
||||
ScoreboardTeam_setSuffix = ReflectionUtils.getMethod(scoreboardTeam, new String[]{"setSuffix", "c", "m_83365_"}, IChatBaseComponent); // {1.17.1-, 1.18+, Mohist 1.18.2}
|
||||
} else {
|
||||
ScoreboardTeam_setPrefix = ReflectionUtils.getMethod(scoreboardTeam, new String[] {"func_96666_b", "setPrefix", "b"}, String.class); // {Thermos, 1.5.1+, 1.5}
|
||||
ScoreboardTeam_setSuffix = ReflectionUtils.getMethod(scoreboardTeam, new String[] {"func_96662_c", "setSuffix", "c"}, String.class); // {Thermos, 1.5.1+, 1.5}
|
||||
}
|
||||
if (minorVersion >= 8) {
|
||||
ScoreboardTeam_setNameTagVisibility = ReflectionUtils.getMethod(scoreboardTeam, new String[] {"setNameTagVisibility", "a", "m_83346_"}, EnumNameTagVisibility); // {1.8.1+, 1.8 & 1.18+, Mohist 1.18.2}
|
||||
}
|
||||
ScoreboardTeam_setPrefix = ReflectionUtils.getMethod(
|
||||
scoreboardTeam,
|
||||
new String[] {"func_96666_b", "setPrefix", "b"}, // {Thermos, 1.5.1+, 1.5}
|
||||
String.class
|
||||
);
|
||||
ScoreboardTeam_setSuffix = ReflectionUtils.getMethod(
|
||||
scoreboardTeam,
|
||||
new String[] {"func_96662_c", "setSuffix", "c"}, // {Thermos, 1.5.1+, 1.5}
|
||||
String.class
|
||||
);
|
||||
}
|
||||
if (minorVersion >= 8) {
|
||||
ScoreboardTeam_setNameTagVisibility = ReflectionUtils.getMethod(
|
||||
scoreboardTeam,
|
||||
new String[] {"setNameTagVisibility", "a", "m_83346_"}, // {1.8.1+, 1.8 & 1.18+, Mohist 1.18.2}
|
||||
EnumNameTagVisibility
|
||||
);
|
||||
}
|
||||
available = true;
|
||||
}
|
||||
@@ -223,7 +270,7 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
public void setDisplaySlot(@NotNull DisplaySlot slot, @NotNull String objective) {
|
||||
Object displaySlot;
|
||||
if (BukkitReflection.is1_20_2Plus()) {
|
||||
displaySlot = DisplaySlot_values[slot.ordinal()];
|
||||
displaySlot = displaySlots[slot.ordinal()];
|
||||
} else {
|
||||
displaySlot = slot.ordinal();
|
||||
}
|
||||
@@ -250,9 +297,13 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
private Object buildObjective(int action, String objectiveName, String title, @NotNull HealthDisplay display) {
|
||||
if (BukkitReflection.getMinorVersion() >= 13) {
|
||||
return newObjectivePacket.newInstance(
|
||||
newScoreboardObjective.newInstance(null, objectiveName, null,
|
||||
toComponent(IChatBaseComponent.optimizedComponent(title)),
|
||||
Enum.valueOf(EnumScoreboardHealthDisplay, display.name())),
|
||||
newScoreboardObjective.newInstance(
|
||||
null,
|
||||
objectiveName,
|
||||
null,
|
||||
toComponent(title),
|
||||
healthDisplays[display.ordinal()]
|
||||
),
|
||||
action
|
||||
);
|
||||
}
|
||||
@@ -260,7 +311,7 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
Objective_OBJECTIVE_NAME.set(nmsPacket, objectiveName);
|
||||
Objective_DISPLAY_NAME.set(nmsPacket, title);
|
||||
if (BukkitReflection.getMinorVersion() >= 8) {
|
||||
Objective_RENDER_TYPE.set(nmsPacket, Enum.valueOf(EnumScoreboardHealthDisplay, display.name()));
|
||||
Objective_RENDER_TYPE.set(nmsPacket, healthDisplays[display.ordinal()]);
|
||||
}
|
||||
Objective_METHOD.set(nmsPacket, action);
|
||||
return nmsPacket;
|
||||
@@ -310,15 +361,17 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
ScoreboardTeam_setAllowFriendlyFire.invoke(team, (options & 0x1) > 0);
|
||||
ScoreboardTeam_setCanSeeFriendlyInvisibles.invoke(team, (options & 0x2) > 0);
|
||||
if (BukkitReflection.getMinorVersion() >= 13) {
|
||||
ScoreboardTeam_setPrefix.invoke(team, toComponent(IChatBaseComponent.optimizedComponent(prefix)));
|
||||
ScoreboardTeam_setSuffix.invoke(team, toComponent(IChatBaseComponent.optimizedComponent(suffix)));
|
||||
ScoreboardTeam_setColor.invoke(team, Enum.valueOf(EnumChatFormatClass, EnumChatFormat.lastColorsOf(prefix).toString()));
|
||||
ScoreboardTeam_setPrefix.invoke(team, toComponent(prefix));
|
||||
ScoreboardTeam_setSuffix.invoke(team, toComponent(suffix));
|
||||
ScoreboardTeam_setColor.invoke(team, chatFormats[EnumChatFormat.lastColorsOf(prefix).ordinal()]);
|
||||
} else {
|
||||
ScoreboardTeam_setPrefix.invoke(team, prefix);
|
||||
ScoreboardTeam_setSuffix.invoke(team, suffix);
|
||||
}
|
||||
if (BukkitReflection.getMinorVersion() >= 8) ScoreboardTeam_setNameTagVisibility.invoke(team, Enum.valueOf(EnumNameTagVisibility, visibility.name()));
|
||||
if (BukkitReflection.getMinorVersion() >= 9) ScoreboardTeam_setCollisionRule.invoke(team, Enum.valueOf(EnumTeamPush, collision.name()));
|
||||
if (BukkitReflection.getMinorVersion() >= 8)
|
||||
ScoreboardTeam_setNameTagVisibility.invoke(team, nameVisibilities[visibility.ordinal()]);
|
||||
if (BukkitReflection.getMinorVersion() >= 9)
|
||||
ScoreboardTeam_setCollisionRule.invoke(team, collisionRules[collision.ordinal()]);
|
||||
return team;
|
||||
}
|
||||
|
||||
@@ -326,7 +379,7 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
@SneakyThrows
|
||||
public void setScore0(@NotNull String objective, @NotNull String playerName, int score) {
|
||||
if (BukkitReflection.getMinorVersion() >= 13) {
|
||||
player.sendPacket(newScorePacket_1_13.newInstance(Enum.valueOf(EnumScoreboardAction, "CHANGE"), objective, playerName, score));
|
||||
player.sendPacket(newScorePacket_1_13.newInstance(scoreboardActions[0], objective, playerName, score));
|
||||
} else {
|
||||
Object scoreboardScore = newScoreboardScore.newInstance(emptyScoreboard, newScoreboardObjective(objective), playerName);
|
||||
ScoreboardScore_setScore.invoke(scoreboardScore, score);
|
||||
@@ -342,7 +395,7 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
@SneakyThrows
|
||||
public void removeScore0(@NotNull String objective, @NotNull String playerName) {
|
||||
if (BukkitReflection.getMinorVersion() >= 13) {
|
||||
player.sendPacket(newScorePacket_1_13.newInstance(Enum.valueOf(EnumScoreboardAction, "REMOVE"), objective, playerName, 0));
|
||||
player.sendPacket(newScorePacket_1_13.newInstance(scoreboardActions[1], objective, playerName, 0));
|
||||
} else {
|
||||
player.sendPacket(newScorePacket_String.newInstance(playerName));
|
||||
}
|
||||
@@ -362,7 +415,7 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
null,
|
||||
objectiveName,
|
||||
null,
|
||||
toComponent(new IChatBaseComponent("")),
|
||||
toComponent(""),
|
||||
null
|
||||
);
|
||||
}
|
||||
@@ -373,7 +426,7 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
);
|
||||
}
|
||||
|
||||
private Object toComponent(IChatBaseComponent component) {
|
||||
return player.getPlatform().toComponent(component, player.getVersion());
|
||||
private Object toComponent(String text) {
|
||||
return player.getPlatform().toComponent(IChatBaseComponent.optimizedComponent(text), player.getVersion());
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ public class BungeeBossBar implements BossBar {
|
||||
packet.setTitle(IChatBaseComponent.optimizedComponent(title).toString(player.getVersion()));
|
||||
packet.setColor(color.ordinal());
|
||||
packet.setDivision(style.ordinal());
|
||||
player.getPlayer().unsafe().sendPacket(packet);
|
||||
player.sendPacket(packet);
|
||||
|
||||
colors.put(id, color.ordinal());
|
||||
styles.put(id, style.ordinal());
|
||||
@@ -50,7 +50,7 @@ public class BungeeBossBar implements BossBar {
|
||||
|
||||
net.md_5.bungee.protocol.packet.BossBar packet = new net.md_5.bungee.protocol.packet.BossBar(id, 3);
|
||||
packet.setTitle(IChatBaseComponent.optimizedComponent(title).toString(player.getVersion()));
|
||||
player.getPlayer().unsafe().sendPacket(packet);
|
||||
player.sendPacket(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,7 +59,7 @@ public class BungeeBossBar implements BossBar {
|
||||
|
||||
net.md_5.bungee.protocol.packet.BossBar packet = new net.md_5.bungee.protocol.packet.BossBar(id, 2);
|
||||
packet.setHealth(progress);
|
||||
player.getPlayer().unsafe().sendPacket(packet);
|
||||
player.sendPacket(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,7 +69,7 @@ public class BungeeBossBar implements BossBar {
|
||||
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));
|
||||
player.getPlayer().unsafe().sendPacket(packet);
|
||||
player.sendPacket(packet);
|
||||
|
||||
styles.put(id, style.ordinal());
|
||||
}
|
||||
@@ -81,7 +81,7 @@ public class BungeeBossBar implements BossBar {
|
||||
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());
|
||||
player.getPlayer().unsafe().sendPacket(packet);
|
||||
player.sendPacket(packet);
|
||||
|
||||
colors.put(id, color.ordinal());
|
||||
}
|
||||
@@ -90,7 +90,7 @@ public class BungeeBossBar implements BossBar {
|
||||
public void remove(@NotNull UUID id) {
|
||||
if (player.getVersion().getMinorVersion() < 9) return;
|
||||
|
||||
player.getPlayer().unsafe().sendPacket(new net.md_5.bungee.protocol.packet.BossBar(id, 1));
|
||||
player.sendPacket(new net.md_5.bungee.protocol.packet.BossBar(id, 1));
|
||||
|
||||
colors.remove(id);
|
||||
styles.remove(id);
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public class BungeeEventListener extends EventListener<ProxiedPlayer> implements
|
||||
|
||||
@EventHandler
|
||||
public void onSwitch(ServerSwitchEvent e) {
|
||||
serverChange(e.getPlayer(), e.getPlayer().getUniqueId(), e.getPlayer().getServer().getInfo().getName());
|
||||
serverChange(e.getPlayer(), e.getPlayer().getUniqueId(), e.getPlayer().getServer().getInfo().getName(), false);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
|
||||
+5
@@ -189,6 +189,11 @@ public class BungeePipelineInjector extends NettyPipelineInjector {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLogin(@NotNull Object packet) {
|
||||
return packet instanceof Login;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new instance of the feature
|
||||
*/
|
||||
|
||||
@@ -3,22 +3,16 @@ package me.neznamy.tab.platforms.bungeecord;
|
||||
import com.imaginarycode.minecraft.redisbungee.RedisBungeeAPI;
|
||||
import lombok.AllArgsConstructor;
|
||||
import me.neznamy.tab.platforms.bungeecord.features.BungeeRedisSupport;
|
||||
import me.neznamy.tab.shared.ProtocolVersion;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.chat.ChatModifier;
|
||||
import me.neznamy.tab.shared.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.features.injection.PipelineInjector;
|
||||
import me.neznamy.tab.shared.features.redis.RedisSupport;
|
||||
import me.neznamy.tab.shared.hook.ViaVersionHook;
|
||||
import me.neznamy.tab.shared.proxy.ProxyPlatform;
|
||||
import me.neznamy.tab.shared.util.ComponentCache;
|
||||
import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import org.bstats.bungeecord.Metrics;
|
||||
import org.bstats.charts.SimplePie;
|
||||
@@ -26,22 +20,16 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* BungeeCord implementation of Platform
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public class BungeePlatform extends ProxyPlatform<BaseComponent> {
|
||||
public class BungeePlatform extends ProxyPlatform {
|
||||
|
||||
@NotNull
|
||||
private final BungeeTAB plugin;
|
||||
|
||||
/** Component cache for BungeeCord components */
|
||||
@NotNull
|
||||
private final ComponentCache<IChatBaseComponent, BaseComponent> bungeeCache =
|
||||
new ComponentCache<>(1000, this::toComponent0);
|
||||
|
||||
@Override
|
||||
public void loadPlayers() {
|
||||
ViaVersionHook.getInstance().printProxyWarn();
|
||||
@@ -98,27 +86,6 @@ public class BungeePlatform extends ProxyPlatform<BaseComponent> {
|
||||
return plugin.getDataFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseComponent toComponent(@NotNull IChatBaseComponent component, @NotNull ProtocolVersion version) {
|
||||
return bungeeCache.get(component, version);
|
||||
}
|
||||
|
||||
private BaseComponent toComponent0(IChatBaseComponent component, ProtocolVersion version) {
|
||||
ChatModifier modifier = component.getModifier();
|
||||
TextComponent textComponent = new TextComponent(component.getText());
|
||||
if (modifier.getColor() != null) textComponent.setColor(ChatColor.of(
|
||||
modifier.getColor().toString(version.getMinorVersion() >= 16)));
|
||||
if (modifier.isBold()) textComponent.setBold(true);
|
||||
if (modifier.isItalic()) textComponent.setItalic(true);
|
||||
if (modifier.isObfuscated()) textComponent.setObfuscated(true);
|
||||
if (modifier.isStrikethrough()) textComponent.setStrikethrough(true);
|
||||
if (modifier.isUnderlined()) textComponent.setUnderlined(true);
|
||||
if (modifier.getFont() != null) textComponent.setFont(modifier.getFont());
|
||||
if (!component.getExtra().isEmpty()) textComponent.setExtra(
|
||||
component.getExtra().stream().map(c -> toComponent0(c, version)).collect(Collectors.toList()));
|
||||
return textComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PipelineInjector createPipelineInjector() {
|
||||
|
||||
@@ -33,12 +33,12 @@ public class BungeeScoreboard extends Scoreboard<BungeeTabPlayer> {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void setDisplaySlot(@NotNull DisplaySlot slot, @NotNull String objective) {
|
||||
player.getPlayer().unsafe().sendPacket(newScoreboardDisplay.newInstance((byte)slot.ordinal(), objective));
|
||||
player.sendPacket(newScoreboardDisplay.newInstance((byte)slot.ordinal(), objective));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerObjective0(@NotNull String objectiveName, @NotNull String title, @NotNull HealthDisplay display) {
|
||||
player.getPlayer().unsafe().sendPacket(new ScoreboardObjective(
|
||||
player.sendPacket(new ScoreboardObjective(
|
||||
objectiveName,
|
||||
jsonOrRaw(title),
|
||||
ScoreboardObjective.HealthDisplay.valueOf(display.name()),
|
||||
@@ -48,7 +48,7 @@ public class BungeeScoreboard extends Scoreboard<BungeeTabPlayer> {
|
||||
|
||||
@Override
|
||||
public void unregisterObjective0(@NotNull String objectiveName) {
|
||||
player.getPlayer().unsafe().sendPacket(new ScoreboardObjective(
|
||||
player.sendPacket(new ScoreboardObjective(
|
||||
objectiveName,
|
||||
"", // Empty string to prevent kick on 1.7
|
||||
null,
|
||||
@@ -58,7 +58,7 @@ public class BungeeScoreboard extends Scoreboard<BungeeTabPlayer> {
|
||||
|
||||
@Override
|
||||
public void updateObjective0(@NotNull String objectiveName, @NotNull String title, @NotNull HealthDisplay display) {
|
||||
player.getPlayer().unsafe().sendPacket(new ScoreboardObjective(
|
||||
player.sendPacket(new ScoreboardObjective(
|
||||
objectiveName,
|
||||
jsonOrRaw(title),
|
||||
ScoreboardObjective.HealthDisplay.valueOf(display.name()),
|
||||
@@ -74,13 +74,13 @@ public class BungeeScoreboard extends Scoreboard<BungeeTabPlayer> {
|
||||
if (player.getVersion().getMinorVersion() >= 13) {
|
||||
color = EnumChatFormat.lastColorsOf(prefix).ordinal();
|
||||
}
|
||||
player.getPlayer().unsafe().sendPacket(new Team(name, (byte) 0, jsonOrRaw(name), jsonOrRaw(prefix), jsonOrRaw(suffix),
|
||||
player.sendPacket(new Team(name, (byte) 0, jsonOrRaw(name), jsonOrRaw(prefix), jsonOrRaw(suffix),
|
||||
visibility.toString(), collision.toString(), color, (byte)options, players.toArray(new String[0])));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterTeam0(@NotNull String name) {
|
||||
player.getPlayer().unsafe().sendPacket(new Team(name));
|
||||
player.sendPacket(new Team(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -90,18 +90,18 @@ public class BungeeScoreboard extends Scoreboard<BungeeTabPlayer> {
|
||||
if (player.getVersion().getMinorVersion() >= 13) {
|
||||
color = EnumChatFormat.lastColorsOf(prefix).ordinal();
|
||||
}
|
||||
player.getPlayer().unsafe().sendPacket(new Team(name, (byte) 2, jsonOrRaw(name), jsonOrRaw(prefix),
|
||||
player.sendPacket(new Team(name, (byte) 2, jsonOrRaw(name), jsonOrRaw(prefix),
|
||||
jsonOrRaw(suffix), visibility.toString(), collision.toString(), color, (byte)options, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScore0(@NotNull String objective, @NotNull String playerName, int score) {
|
||||
player.getPlayer().unsafe().sendPacket(new ScoreboardScore(playerName, (byte) 0, objective, score));
|
||||
player.sendPacket(new ScoreboardScore(playerName, (byte) 0, objective, score));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeScore0(@NotNull String objective, @NotNull String playerName) {
|
||||
player.getPlayer().unsafe().sendPacket(new ScoreboardScore(playerName, (byte) 1, objective, 0));
|
||||
player.sendPacket(new ScoreboardScore(playerName, (byte) 1, objective, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,24 +2,32 @@ package me.neznamy.tab.platforms.bungeecord;
|
||||
|
||||
import de.myzelyam.api.vanish.BungeeVanishAPI;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import me.neznamy.tab.shared.ProtocolVersion;
|
||||
import me.neznamy.tab.platforms.bungeecord.tablist.BungeeTabList1193;
|
||||
import me.neznamy.tab.platforms.bungeecord.tablist.BungeeTabList17;
|
||||
import me.neznamy.tab.platforms.bungeecord.tablist.BungeeTabList18;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.platform.Scoreboard;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
import me.neznamy.tab.shared.platform.bossbar.BossBar;
|
||||
import me.neznamy.tab.shared.proxy.ProxyTabPlayer;
|
||||
import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
import net.md_5.bungee.UserConnection;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.chat.ComponentSerializer;
|
||||
import net.md_5.bungee.connection.InitialHandler;
|
||||
import net.md_5.bungee.connection.LoginResult;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.Property;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* TabPlayer implementation for BungeeCord
|
||||
*/
|
||||
@@ -29,6 +37,9 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
|
||||
/** Flag tracking plugin presence */
|
||||
private static final boolean premiumVanish = ProxyServer.getInstance().getPluginManager().getPlugin("PremiumVanish") != null;
|
||||
|
||||
/** Flag tracking version of bungeecord with packet queue due to configuration phase */
|
||||
private static final boolean packetQueue = ReflectionUtils.methodExists(UserConnection.class, "sendPacketQueued", DefinedPacket.class);
|
||||
|
||||
/** Player's scoreboard */
|
||||
@NotNull
|
||||
private final Scoreboard<BungeeTabPlayer> scoreboard = new BungeeScoreboard(this);
|
||||
@@ -71,7 +82,7 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
|
||||
|
||||
@Override
|
||||
public void sendMessage(@NotNull IChatBaseComponent message) {
|
||||
getPlayer().sendMessage(getPlatform().toComponent(message, getVersion()));
|
||||
getPlayer().sendMessage(ComponentSerializer.parse(message.toString(getVersion())));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,11 +113,18 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
|
||||
|
||||
@Override
|
||||
public void sendPluginMessage(byte[] message) {
|
||||
if (getPlayer().getServer() == null) {
|
||||
errorNoServer(message);
|
||||
return;
|
||||
try {
|
||||
getPlayer().getServer().sendData(TabConstants.PLUGIN_MESSAGE_CHANNEL_NAME, message);
|
||||
} 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.ServerConnection.sendPacketQueued(ServerConnection.java:48)
|
||||
// at net.md_5.bungee.ServerConnection.sendData(ServerConnection.java:70)
|
||||
if (TAB.getInstance().getConfiguration().isDebugMode()) {
|
||||
TAB.getInstance().getErrorManager().printError("Failed to deliver plugin message to player " + getName() +
|
||||
" (online = " + getPlayer().isConnected() + ")", BungeeCordBug);
|
||||
}
|
||||
}
|
||||
getPlayer().getServer().sendData(TabConstants.PLUGIN_MESSAGE_CHANNEL_NAME, message);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,4 +159,30 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
|
||||
if (version >= ProtocolVersion.V1_8.getNetworkId()) return tabList1_8;
|
||||
return tabList1_7;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends packet to the player. If BungeeCord supports 1.20.2+, new packet queue method is used
|
||||
* to avoid error when sending packet in configuration phase.
|
||||
*
|
||||
* @param packet
|
||||
* Packet to send
|
||||
*/
|
||||
@SneakyThrows
|
||||
public void sendPacket(@NotNull DefinedPacket packet) {
|
||||
if (packetQueue) {
|
||||
try {
|
||||
UserConnection.class.getDeclaredMethod("sendPacketQueued", DefinedPacket.class).invoke(player, packet);
|
||||
} catch (InvocationTargetException BungeeCordBug) { // Since we use reflection we must catch this one
|
||||
// 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:194)
|
||||
if (TAB.getInstance().getConfiguration().isDebugMode()) {
|
||||
TAB.getInstance().getErrorManager().printError("Failed to deliver packet to player " + getName() +
|
||||
" (online = " + getPlayer().isConnected() + "): " + packet, BungeeCordBug);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
getPlayer().unsafe().sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package me.neznamy.tab.platforms.bungeecord.tablist;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import me.neznamy.tab.platforms.bungeecord.BungeeTabPlayer;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
import net.md_5.bungee.UserConnection;
|
||||
import net.md_5.bungee.protocol.Property;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListHeaderFooter;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItem.Item;
|
||||
import net.md_5.bungee.tab.ServerUnique;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class BungeeTabList implements TabList {
|
||||
|
||||
/** Player this TabList belongs to */
|
||||
@NotNull
|
||||
protected final BungeeTabPlayer player;
|
||||
|
||||
/** Pointer to UUIDs in player's TabList */
|
||||
private final Collection<UUID> uuids;
|
||||
|
||||
@SneakyThrows
|
||||
@SuppressWarnings("unchecked")
|
||||
public BungeeTabList(@NotNull BungeeTabPlayer player) {
|
||||
this.player = player;
|
||||
uuids = (Collection<UUID>) ReflectionUtils.getField(ServerUnique.class, "uuids").get(((UserConnection)player.getPlayer()).getTabListHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerListHeaderFooter(@NotNull IChatBaseComponent header, @NotNull IChatBaseComponent footer) {
|
||||
player.sendPacket(new PlayerListHeaderFooter(
|
||||
header.toString(player.getVersion()),
|
||||
footer.toString(player.getVersion())
|
||||
));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Item item(@NotNull UUID id) {
|
||||
Item item = new Item();
|
||||
item.setUuid(id);
|
||||
return item;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Item entryToItem(Entry entry) {
|
||||
Item item = item(entry.getUniqueId());
|
||||
if (entry.getDisplayName() != null) item.setDisplayName(entry.getDisplayName().toString(player.getVersion()));
|
||||
item.setGamemode(entry.getGameMode());
|
||||
item.setListed(true);
|
||||
item.setPing(entry.getLatency());
|
||||
if (entry.getSkin() != null) {
|
||||
item.setProperties(new Property[]{new Property(TEXTURES_PROPERTY, entry.getSkin().getValue(), entry.getSkin().getSignature())});
|
||||
} else {
|
||||
item.setProperties(new Property[0]);
|
||||
}
|
||||
item.setUsername(entry.getName());
|
||||
return item;
|
||||
}
|
||||
|
||||
public void addUuid(UUID id) {
|
||||
uuids.add(id);
|
||||
}
|
||||
|
||||
public void removeUuid(UUID id) {
|
||||
uuids.remove(id);
|
||||
}
|
||||
}
|
||||
+9
-40
@@ -1,11 +1,7 @@
|
||||
package me.neznamy.tab.platforms.bungeecord.tablist;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.neznamy.tab.platforms.bungeecord.BungeeTabPlayer;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
import net.md_5.bungee.UserConnection;
|
||||
import net.md_5.bungee.protocol.Property;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItem.Item;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItemRemove;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItemUpdate;
|
||||
@@ -18,21 +14,19 @@ import java.util.UUID;
|
||||
/**
|
||||
* TabList handler for 1.19.3+ players using the new tab list packets.
|
||||
* Because BungeeCord does not have a TabList API, we need to use packets.
|
||||
* They are sent using an internal BungeeCord method that keeps track of them,
|
||||
* so they are removed on server switch to secure parity with Velocity.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class BungeeTabList1193 implements TabList {
|
||||
public class BungeeTabList1193 extends BungeeTabList {
|
||||
|
||||
/** Player this TabList belongs to */
|
||||
@NotNull
|
||||
private final BungeeTabPlayer player;
|
||||
public BungeeTabList1193(@NotNull BungeeTabPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEntry(@NotNull UUID entry) {
|
||||
removeUuid(entry);
|
||||
PlayerListItemRemove remove = new PlayerListItemRemove();
|
||||
remove.setUuids(new UUID[]{entry});
|
||||
((UserConnection)player.getPlayer()).getTabListHandler().onUpdate(remove);
|
||||
player.sendPacket(remove);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,39 +52,14 @@ public class BungeeTabList1193 implements TabList {
|
||||
|
||||
@Override
|
||||
public void addEntry(@NotNull Entry entry) {
|
||||
Item item = item(entry.getUniqueId());
|
||||
if (entry.getDisplayName() != null) item.setDisplayName(entry.getDisplayName().toString(player.getVersion()));
|
||||
item.setGamemode(entry.getGameMode());
|
||||
item.setListed(true);
|
||||
item.setPing(entry.getLatency());
|
||||
if (entry.getSkin() != null) {
|
||||
item.setProperties(new Property[]{new Property(TEXTURES_PROPERTY, entry.getSkin().getValue(), entry.getSkin().getSignature())});
|
||||
} else {
|
||||
item.setProperties(new Property[0]);
|
||||
}
|
||||
item.setUsername(entry.getName());
|
||||
sendPacket(EnumSet.allOf(PlayerListItemUpdate.Action.class), item);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Item item(@NotNull UUID id) {
|
||||
Item item = new Item();
|
||||
item.setUuid(id);
|
||||
return item;
|
||||
addUuid(entry.getUniqueId());
|
||||
sendPacket(EnumSet.allOf(PlayerListItemUpdate.Action.class), entryToItem(entry));
|
||||
}
|
||||
|
||||
private void sendPacket(@NotNull EnumSet<PlayerListItemUpdate.Action> actions, @NotNull Item item) {
|
||||
PlayerListItemUpdate packet = new PlayerListItemUpdate();
|
||||
packet.setActions(actions);
|
||||
packet.setItems(new Item[]{item});
|
||||
((UserConnection)player.getPlayer()).getTabListHandler().onUpdate(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerListHeaderFooter(@NotNull IChatBaseComponent header, @NotNull IChatBaseComponent footer) {
|
||||
player.getPlayer().setTabHeader(
|
||||
player.getPlatform().toComponent(header, player.getVersion()),
|
||||
player.getPlatform().toComponent(footer, player.getVersion())
|
||||
);
|
||||
player.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
+8
-17
@@ -1,10 +1,7 @@
|
||||
package me.neznamy.tab.platforms.bungeecord.tablist;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.neznamy.tab.platforms.bungeecord.BungeeTabPlayer;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
import net.md_5.bungee.UserConnection;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItem;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -19,17 +16,10 @@ import java.util.UUID;
|
||||
* names are changed by removing old entry and adding a new one, which
|
||||
* requires further tracking than just the UUID.<p>
|
||||
* Because BungeeCord does not have a TabList API, we need to use packets.
|
||||
* They are sent using an internal BungeeCord method that keeps track of them,
|
||||
* so they are removed on server switch to secure parity with Velocity.
|
||||
* While BungeeCord itself does not support 1.7, some of its forks do.
|
||||
* This was tested on FlameCord fork.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class BungeeTabList17 implements TabList {
|
||||
|
||||
/** Player this TabList belongs to */
|
||||
@NotNull
|
||||
private final BungeeTabPlayer player;
|
||||
public class BungeeTabList17 extends BungeeTabList {
|
||||
|
||||
/** Because entries are identified by names and not uuids on 1.7 */
|
||||
@NotNull
|
||||
@@ -38,9 +28,14 @@ public class BungeeTabList17 implements TabList {
|
||||
@NotNull
|
||||
private final Map<UUID, String> displayNames = new HashMap<>();
|
||||
|
||||
public BungeeTabList17(@NotNull BungeeTabPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEntry(@NotNull UUID entry) {
|
||||
if (!displayNames.containsKey(entry)) return; // Entry not tracked by TAB
|
||||
removeUuid(entry);
|
||||
update(PlayerListItem.Action.REMOVE_PLAYER, createItem(null, displayNames.get(entry), 0));
|
||||
|
||||
// Remove from map
|
||||
@@ -66,6 +61,7 @@ public class BungeeTabList17 implements TabList {
|
||||
|
||||
@Override
|
||||
public void addEntry(@NotNull Entry entry) {
|
||||
addUuid(entry.getUniqueId());
|
||||
String displayNameString = entry.getDisplayName() == null ? String.valueOf(entry.getName()) : entry.getDisplayName().toLegacyText();
|
||||
if (displayNameString.length() > 16) displayNameString = displayNameString.substring(0, 16); // 16 character limit
|
||||
update(PlayerListItem.Action.ADD_PLAYER, createItem(entry.getName(), displayNameString, entry.getLatency()));
|
||||
@@ -79,7 +75,7 @@ public class BungeeTabList17 implements TabList {
|
||||
PlayerListItem packet = new PlayerListItem();
|
||||
packet.setAction(action);
|
||||
packet.setItems(new PlayerListItem.Item[]{item});
|
||||
((UserConnection)player.getPlayer()).getTabListHandler().onUpdate(packet);
|
||||
player.sendPacket(packet);
|
||||
}
|
||||
|
||||
private PlayerListItem.Item createItem(@Nullable String username, @NotNull String displayName, int latency) {
|
||||
@@ -89,9 +85,4 @@ public class BungeeTabList17 implements TabList {
|
||||
item.setPing(latency);
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerListHeaderFooter(@NotNull IChatBaseComponent header, @NotNull IChatBaseComponent footer) {
|
||||
// Added in 1.8
|
||||
}
|
||||
}
|
||||
+8
-38
@@ -1,11 +1,7 @@
|
||||
package me.neznamy.tab.platforms.bungeecord.tablist;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.neznamy.tab.platforms.bungeecord.BungeeTabPlayer;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
import net.md_5.bungee.UserConnection;
|
||||
import net.md_5.bungee.protocol.Property;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItem;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItem.Item;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -16,18 +12,16 @@ import java.util.UUID;
|
||||
/**
|
||||
* TabList handler for players between 1.8 and 1.19.2.<p>
|
||||
* Because BungeeCord does not have a TabList API, we need to use packets.
|
||||
* They are sent using an internal BungeeCord method that keeps track of them,
|
||||
* so they are removed on server switch to secure parity with Velocity.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class BungeeTabList18 implements TabList {
|
||||
public class BungeeTabList18 extends BungeeTabList {
|
||||
|
||||
/** Player this TabList belongs to */
|
||||
@NotNull
|
||||
private final BungeeTabPlayer player;
|
||||
public BungeeTabList18(@NotNull BungeeTabPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEntry(@NotNull UUID entry) {
|
||||
removeUuid(entry);
|
||||
sendPacket(PlayerListItem.Action.REMOVE_PLAYER, item(entry));
|
||||
}
|
||||
|
||||
@@ -54,38 +48,14 @@ public class BungeeTabList18 implements TabList {
|
||||
|
||||
@Override
|
||||
public void addEntry(@NotNull Entry entry) {
|
||||
Item item = item(entry.getUniqueId());
|
||||
if (entry.getDisplayName() != null) item.setDisplayName(entry.getDisplayName().toString(player.getVersion()));
|
||||
item.setGamemode(entry.getGameMode());
|
||||
item.setPing(entry.getLatency());
|
||||
if (entry.getSkin() != null) {
|
||||
item.setProperties(new Property[]{new Property(TEXTURES_PROPERTY, entry.getSkin().getValue(), entry.getSkin().getSignature())});
|
||||
} else {
|
||||
item.setProperties(new Property[0]);
|
||||
}
|
||||
item.setUsername(entry.getName());
|
||||
sendPacket(PlayerListItem.Action.ADD_PLAYER, item);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Item item(@NotNull UUID id) {
|
||||
Item item = new Item();
|
||||
item.setUuid(id);
|
||||
return item;
|
||||
addUuid(entry.getUniqueId());
|
||||
sendPacket(PlayerListItem.Action.ADD_PLAYER, entryToItem(entry));
|
||||
}
|
||||
|
||||
private void sendPacket(@NotNull PlayerListItem.Action action, @NotNull Item item) {
|
||||
PlayerListItem packet = new PlayerListItem();
|
||||
packet.setAction(action);
|
||||
packet.setItems(new Item[]{item});
|
||||
((UserConnection)player.getPlayer()).getTabListHandler().onUpdate(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerListHeaderFooter(@NotNull IChatBaseComponent header, @NotNull IChatBaseComponent footer) {
|
||||
player.getPlayer().setTabHeader(
|
||||
player.getPlatform().toComponent(header, player.getVersion()),
|
||||
player.getPlatform().toComponent(footer, player.getVersion())
|
||||
);
|
||||
player.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
val minecraftVersion = "1.20.2"
|
||||
|
||||
val v114 = "0.28.5+1.14"
|
||||
val v115 = "0.28.5+1.15"
|
||||
val v116 = "0.42.0+1.16"
|
||||
|
||||
@@ -27,11 +26,7 @@ val fabricApiVersions = mapOf(
|
||||
"1.15.2" to v115,
|
||||
"1.15.1" to v115,
|
||||
"1.15" to v115,
|
||||
"1.14.4" to v114,
|
||||
"1.14.3" to v114,
|
||||
"1.14.2" to v114,
|
||||
"1.14.1" to v114,
|
||||
"1.14" to v114,
|
||||
"1.14.4" to "0.28.5+1.14",
|
||||
)
|
||||
|
||||
plugins {
|
||||
@@ -57,8 +52,10 @@ dependencies {
|
||||
modImplementation(fabricApi.module("fabric-api-base", fabricApiVersions[minecraftVersion]))
|
||||
modImplementation(fabricApi.module("fabric-lifecycle-events-v1", fabricApiVersions[minecraftVersion]))
|
||||
modImplementation(fabricApi.module("fabric-networking-api-v1", fabricApiVersions[minecraftVersion]))
|
||||
modImplementation(fabricApi.module("fabric-entity-events-v1", fabricApiVersions[minecraftVersion]))
|
||||
modImplementation(fabricApi.module("fabric-command-api-v${if (minecraftVersion.split(".")[1].toInt() >= 19) "2" else "1"}", fabricApiVersions[minecraftVersion]))
|
||||
if (minecraftVersion.split(".")[1].toInt() >= 16) {
|
||||
modImplementation(fabricApi.module("fabric-entity-events-v1", fabricApiVersions[minecraftVersion]))
|
||||
}
|
||||
}
|
||||
|
||||
loom {
|
||||
|
||||
@@ -9,12 +9,33 @@ import me.neznamy.tab.api.bossbar.BarStyle;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.platform.bossbar.BossBar;
|
||||
import net.minecraft.server.level.ServerBossEvent;
|
||||
import net.minecraft.world.BossEvent;
|
||||
import net.minecraft.world.BossEvent.BossBarColor;
|
||||
import net.minecraft.world.BossEvent.BossBarOverlay;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class FabricBossBar implements BossBar {
|
||||
|
||||
/** Color array for fast access */
|
||||
private static final BossBarColor[] colors = new BossBarColor[] {
|
||||
BossBarColor.PINK,
|
||||
BossBarColor.BLUE,
|
||||
BossBarColor.RED,
|
||||
BossBarColor.GREEN,
|
||||
BossBarColor.YELLOW,
|
||||
BossBarColor.PURPLE,
|
||||
BossBarColor.WHITE
|
||||
};
|
||||
|
||||
/** Overlay array for fast access */
|
||||
private static final BossBarOverlay[] overlays = new BossBarOverlay[] {
|
||||
BossBarOverlay.PROGRESS,
|
||||
BossBarOverlay.NOTCHED_6,
|
||||
BossBarOverlay.NOTCHED_10,
|
||||
BossBarOverlay.NOTCHED_12,
|
||||
BossBarOverlay.NOTCHED_20
|
||||
};
|
||||
|
||||
@NotNull
|
||||
private final FabricTabPlayer player;
|
||||
|
||||
@@ -25,10 +46,10 @@ public class FabricBossBar implements BossBar {
|
||||
public void create(@NotNull UUID id, @NotNull String title, float progress, @NotNull BarColor color, @NotNull BarStyle style) {
|
||||
ServerBossEvent bar = new ServerBossEvent(
|
||||
player.getPlatform().toComponent(IChatBaseComponent.optimizedComponent(title), player.getVersion()),
|
||||
BossEvent.BossBarColor.valueOf(color.name()),
|
||||
BossEvent.BossBarOverlay.valueOf(style.name())
|
||||
colors[color.ordinal()],
|
||||
overlays[style.ordinal()]
|
||||
);
|
||||
bar.setProgress(progress);
|
||||
FabricMultiVersion.setProgress(bar, progress);
|
||||
bars.put(id, bar);
|
||||
bar.addPlayer(player.getPlayer());
|
||||
}
|
||||
@@ -40,17 +61,17 @@ public class FabricBossBar implements BossBar {
|
||||
|
||||
@Override
|
||||
public void update(@NotNull UUID id, float progress) {
|
||||
bars.get(id).setProgress(progress);
|
||||
FabricMultiVersion.setProgress(bars.get(id), progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull UUID id, @NotNull BarStyle style) {
|
||||
bars.get(id).setOverlay(BossEvent.BossBarOverlay.valueOf(style.name()));
|
||||
bars.get(id).setOverlay(overlays[style.ordinal()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull UUID id, @NotNull BarColor color) {
|
||||
bars.get(id).setColor(BossEvent.BossBarColor.valueOf(color.name()));
|
||||
bars.get(id).setColor(colors[color.ordinal()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,14 +4,10 @@ import me.neznamy.tab.shared.backend.EntityData;
|
||||
import me.neznamy.tab.shared.backend.Location;
|
||||
import me.neznamy.tab.shared.backend.entityview.EntityView;
|
||||
import net.minecraft.network.protocol.game.*;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.decoration.ArmorStand;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public record FabricEntityView(FabricTabPlayer player) implements EntityView {
|
||||
@@ -22,16 +18,13 @@ public record FabricEntityView(FabricTabPlayer player) implements EntityView {
|
||||
@Override
|
||||
public void spawnEntity(int entityId, @NotNull UUID id, @NotNull Object entityType, @NotNull Location location,
|
||||
@NotNull EntityData data) {
|
||||
player.sendPacket(new ClientboundAddEntityPacket(entityId, id,
|
||||
location.getX(), location.getY(), location.getZ(), 0, 0,
|
||||
(EntityType<?>) entityType, 0, Vec3.ZERO, 0));
|
||||
player.sendPacket(FabricMultiVersion.addEntity(entityId, id, entityType, location, data));
|
||||
updateEntityMetadata(entityId, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void updateEntityMetadata(int entityId, @NotNull EntityData data) {
|
||||
player.sendPacket(new ClientboundSetEntityDataPacket(entityId, (List<SynchedEntityData.DataValue<?>>) data.build()));
|
||||
player.sendPacket(FabricMultiVersion.newEntityMetadata(entityId, data));
|
||||
|
||||
}
|
||||
|
||||
@@ -44,12 +37,12 @@ public record FabricEntityView(FabricTabPlayer player) implements EntityView {
|
||||
|
||||
@Override
|
||||
public void destroyEntities(int... entities) {
|
||||
player.sendPacket(new ClientboundRemoveEntitiesPacket(entities));
|
||||
FabricMultiVersion.destroyEntities(player, entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDestroyPacket(@NotNull Object packet) {
|
||||
return packet instanceof ClientboundRemoveEntitiesPacket;
|
||||
return FabricMultiVersion.isEntityDestroyPacket(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -89,6 +82,6 @@ public record FabricEntityView(FabricTabPlayer player) implements EntityView {
|
||||
|
||||
@Override
|
||||
public int[] getDestroyedEntities(@NotNull Object destroyPacket) {
|
||||
return ((ClientboundRemoveEntitiesPacket) destroyPacket).getEntityIds().toIntArray();
|
||||
return FabricMultiVersion.getDestroyedEntities(destroyPacket);
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,6 @@ package me.neznamy.tab.platforms.fabric;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.platform.EventListener;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.ServerEntityWorldChangeEvents;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -14,10 +12,8 @@ public class FabricEventListener extends EventListener<ServerPlayer> {
|
||||
public void register() {
|
||||
ServerPlayConnectionEvents.DISCONNECT.register((connection, $) -> quit(connection.player.getUUID()));
|
||||
ServerPlayConnectionEvents.JOIN.register((connection, $, $$) -> join(connection.player));
|
||||
ServerEntityWorldChangeEvents.AFTER_PLAYER_CHANGE_WORLD.register((player, origin, destination) ->
|
||||
worldChange(player.getUUID(), destination.dimension().location().toString()));
|
||||
//TODO command
|
||||
ServerPlayerEvents.AFTER_RESPAWN.register((oldPlayer, newPlayer, alive) -> replacePlayer(oldPlayer.getUUID(), newPlayer));
|
||||
FabricMultiVersion.registerEntityEvents(this::replacePlayer);
|
||||
//TODO command preprocess
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
package me.neznamy.tab.platforms.fabric;
|
||||
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import me.neznamy.tab.platforms.fabric.features.FabricNameTagX;
|
||||
import me.neznamy.tab.shared.ProtocolVersion;
|
||||
import me.neznamy.tab.shared.backend.EntityData;
|
||||
import me.neznamy.tab.shared.backend.Location;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.*;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.server.level.ServerBossEvent;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.level.GameType;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.scores.Objective;
|
||||
import net.minecraft.world.scores.PlayerTeam;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Class that contains (almost) all code that needs to be changed
|
||||
* to set compatibility with any MC version that fabric supports (1.14.4+).
|
||||
*/
|
||||
public class FabricMultiVersion {
|
||||
|
||||
private static final int armorStandFlagsPosition = getArmorStandFlagsPosition();
|
||||
|
||||
private static int getArmorStandFlagsPosition() {
|
||||
int minorVersion = ProtocolVersion.fromFriendlyName(SharedConstants.getCurrentVersion().getName()).getMinorVersion();
|
||||
if (minorVersion >= 17) {
|
||||
//1.17.x, 1.18.x, 1.19.x, 1.20.x
|
||||
return 15;
|
||||
} else if (minorVersion >= 15) {
|
||||
//1.15.x, 1.16.x
|
||||
return 14;
|
||||
} else {
|
||||
//1.14.x
|
||||
return 13;
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendSystemMessage(CommandSourceStack source, Component message) {
|
||||
// 1.19.4-
|
||||
// source.sendSuccess(message, false);
|
||||
|
||||
// 1.19.1+
|
||||
source.sendSystemMessage(message);
|
||||
}
|
||||
|
||||
public static boolean isSneaking(ServerPlayer player) {
|
||||
// 1.14.4-
|
||||
// return player.isSneaking();
|
||||
|
||||
// 1.15+
|
||||
return player.isCrouching();
|
||||
}
|
||||
|
||||
public static void registerNameTagXEvents(FabricNameTagX nameTagX) {
|
||||
// 1.16+
|
||||
net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents.AFTER_RESPAWN.register((oldPlayer, newPlayer, alive) -> {
|
||||
if (nameTagX.enabled) nameTagX.respawn(oldPlayer.getUUID());
|
||||
});
|
||||
// TODO sneaking
|
||||
}
|
||||
|
||||
public static void registerEntityEvents(BiConsumer<UUID, ServerPlayer> action) {
|
||||
// 1.16+
|
||||
net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents.AFTER_RESPAWN.register((oldPlayer, newPlayer, alive) ->
|
||||
action.accept(oldPlayer.getUUID(), newPlayer));
|
||||
// TODO world switch with proper world name
|
||||
}
|
||||
|
||||
public static ClientboundTabListPacket setHeaderFooter(Component header, Component footer) {
|
||||
// 1.16.5-
|
||||
/*ClientboundTabListPacket packet = new ClientboundTabListPacket();
|
||||
packet.header = header;
|
||||
packet.footer = footer;
|
||||
return packet;*/
|
||||
|
||||
// 1.17+
|
||||
return new ClientboundTabListPacket(header, footer);
|
||||
}
|
||||
|
||||
public static ClientboundSetPlayerTeamPacket createTeam(PlayerTeam team) {
|
||||
// 1.16.5-
|
||||
// return new ClientboundSetPlayerTeamPacket(team, 0);
|
||||
|
||||
// 1.17+
|
||||
return ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true);
|
||||
}
|
||||
|
||||
public static ClientboundSetPlayerTeamPacket removeTeam(PlayerTeam team) {
|
||||
// 1.16.5-
|
||||
// return new ClientboundSetPlayerTeamPacket(team, 1);
|
||||
|
||||
// 1.17+
|
||||
return ClientboundSetPlayerTeamPacket.createRemovePacket(team);
|
||||
}
|
||||
|
||||
public static ClientboundSetPlayerTeamPacket updateTeam(PlayerTeam team) {
|
||||
// 1.16.5-
|
||||
// return new ClientboundSetPlayerTeamPacket(team, 2);
|
||||
|
||||
// 1.17+
|
||||
return ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, false);
|
||||
}
|
||||
|
||||
public static void setProgress(ServerBossEvent bar, float progress) {
|
||||
// 1.16.5-
|
||||
// bar.setPercent(progress);
|
||||
|
||||
// 1.17+
|
||||
bar.setProgress(progress);
|
||||
}
|
||||
|
||||
public static int[] getDestroyedEntities(Object destroyPacket) {
|
||||
// 1.16.5-
|
||||
// return ((ClientboundRemoveEntitiesPacket) destroyPacket).getEntityIds();
|
||||
|
||||
// 1.17
|
||||
// return new int[]{((ClientboundRemoveEntityPacket)destroyPacket).getEntityId()};
|
||||
|
||||
// 1.17.1+
|
||||
return ((ClientboundRemoveEntitiesPacket) destroyPacket).getEntityIds().toIntArray();
|
||||
}
|
||||
|
||||
public static void destroyEntities(FabricTabPlayer player, int... entities) {
|
||||
// 1.17
|
||||
/*for (int i : entities) {
|
||||
player.sendPacket(new ClientboundRemoveEntityPacket(i));
|
||||
}*/
|
||||
|
||||
// every other version
|
||||
player.sendPacket(new ClientboundRemoveEntitiesPacket(entities));
|
||||
}
|
||||
|
||||
public static boolean isEntityDestroyPacket(Object packet) {
|
||||
// 1.17
|
||||
// return packet instanceof ClientboundRemoveEntityPacket;
|
||||
|
||||
// every other version
|
||||
return packet instanceof ClientboundRemoveEntitiesPacket;
|
||||
}
|
||||
|
||||
public static void registerCommand() {
|
||||
// 1.18.2-
|
||||
// net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback.EVENT.register((dispatcher, $) -> new FabricTabCommand().onRegisterCommands(dispatcher));
|
||||
|
||||
// 1.19+
|
||||
net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback.EVENT.register((dispatcher, $, $$) -> new FabricTabCommand().onRegisterCommands(dispatcher));
|
||||
}
|
||||
|
||||
public static void sendMessage(FabricTabPlayer player, Component message) {
|
||||
// 1.15.2-
|
||||
// player.getPlayer().sendMessage(message);
|
||||
|
||||
// 1.16 - 1.18.2
|
||||
// player.getPlayer().sendMessage(message, new UUID(0, 0));
|
||||
|
||||
// 1.19+
|
||||
player.getPlayer().sendSystemMessage(message);
|
||||
}
|
||||
|
||||
public static ClientboundAddEntityPacket addEntity(int entityId, @NotNull UUID id, @NotNull Object entityType,
|
||||
@NotNull Location location, @NotNull EntityData data) {
|
||||
// 1.18.2-
|
||||
// return new ClientboundAddEntityPacket(entityId, id, location.getX(), location.getY(), location.getZ(), 0, 0, (EntityType<?>) entityType, 0, Vec3.ZERO);
|
||||
|
||||
// 1.19+
|
||||
return new ClientboundAddEntityPacket(entityId, id, location.getX(), location.getY(), location.getZ(), 0, 0, (EntityType<?>) entityType, 0, Vec3.ZERO, 0);
|
||||
}
|
||||
|
||||
public static boolean isPlayerInfo(Object packet) {
|
||||
// 1.19.2-
|
||||
// return packet instanceof ClientboundPlayerInfoPacket;
|
||||
|
||||
// 1.19.3+
|
||||
return packet instanceof ClientboundPlayerInfoUpdatePacket;
|
||||
}
|
||||
|
||||
public static Packet<?> build(FabricTabList.Action action, FabricTabList.Builder entry) {
|
||||
// 1.16.5-
|
||||
/*ClientboundPlayerInfoPacket packet = new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.valueOf(action.name()), Collections.emptyList());
|
||||
packet.entries = Collections.singletonList(new ClientboundPlayerInfoPacket().new PlayerUpdate(
|
||||
entry.createProfile(), entry.getLatency(), GameType.byId(entry.getGameMode()), entry.getDisplayName()
|
||||
));
|
||||
return packet;*/
|
||||
|
||||
// 1.17 - 1.18.2
|
||||
/*ClientboundPlayerInfoPacket packet = new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.valueOf(action.name()), Collections.emptyList());
|
||||
packet.entries = Collections.singletonList(new ClientboundPlayerInfoPacket.PlayerUpdate(
|
||||
entry.createProfile(), entry.getLatency(), GameType.byId(entry.getGameMode()), entry.getDisplayName()
|
||||
));
|
||||
return packet;*/
|
||||
|
||||
// 1.19 - 1.19.2
|
||||
/*ClientboundPlayerInfoPacket packet = new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.valueOf(action.name()), Collections.emptyList());
|
||||
packet.entries = Collections.singletonList(new ClientboundPlayerInfoPacket.PlayerUpdate(
|
||||
entry.createProfile(), entry.getLatency(), GameType.byId(entry.getGameMode()), entry.getDisplayName(), null
|
||||
));
|
||||
return packet;*/
|
||||
|
||||
// 1.19.3+
|
||||
if (action == FabricTabList.Action.REMOVE_PLAYER) {
|
||||
return new ClientboundPlayerInfoRemovePacket(Collections.singletonList(entry.getId()));
|
||||
}
|
||||
EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = action == FabricTabList.Action.ADD_PLAYER ?
|
||||
EnumSet.allOf(ClientboundPlayerInfoUpdatePacket.Action.class) :
|
||||
EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.valueOf(action.name()));
|
||||
ClientboundPlayerInfoUpdatePacket packet = new ClientboundPlayerInfoUpdatePacket(actions, Collections.emptyList());
|
||||
packet.entries = Collections.singletonList(new ClientboundPlayerInfoUpdatePacket.Entry(
|
||||
entry.getId(),
|
||||
entry.createProfile(),
|
||||
true,
|
||||
entry.getLatency(),
|
||||
GameType.byId(entry.getGameMode()),
|
||||
entry.getDisplayName(),
|
||||
null
|
||||
));
|
||||
return packet;
|
||||
}
|
||||
|
||||
public static EntityData createDataWatcher(@NotNull TabPlayer viewer, byte flags, @NotNull String displayName, boolean nameVisible) {
|
||||
// 1.19.2-
|
||||
/*SynchedEntityData data = new SynchedEntityData(null);
|
||||
data.define(new EntityDataAccessor<>(0, EntityDataSerializers.BYTE), flags);
|
||||
data.define(new EntityDataAccessor<>(2, EntityDataSerializers.OPTIONAL_COMPONENT),
|
||||
Optional.of(((FabricTabPlayer)viewer).getPlatform().toComponent(IChatBaseComponent.optimizedComponent(displayName), viewer.getVersion())));
|
||||
data.define(new EntityDataAccessor<>(3, EntityDataSerializers.BOOLEAN), nameVisible);
|
||||
data.define(new EntityDataAccessor<>(15, EntityDataSerializers.BYTE), (byte)16);
|
||||
return () -> data;*/
|
||||
|
||||
// 1.19.3+
|
||||
return () -> java.util.Arrays.asList(
|
||||
new SynchedEntityData.DataValue<>(0, EntityDataSerializers.BYTE, flags),
|
||||
new SynchedEntityData.DataValue<>(2, EntityDataSerializers.OPTIONAL_COMPONENT,
|
||||
Optional.of(((FabricTabPlayer)viewer).getPlatform().toComponent(IChatBaseComponent.optimizedComponent(displayName), viewer.getVersion()))),
|
||||
new SynchedEntityData.DataValue<>(3, EntityDataSerializers.BOOLEAN, nameVisible),
|
||||
new SynchedEntityData.DataValue<>(armorStandFlagsPosition, EntityDataSerializers.BYTE, (byte)16)
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static ClientboundSetEntityDataPacket newEntityMetadata(int entityId, EntityData data) {
|
||||
// 1.19.2-
|
||||
// return new ClientboundSetEntityDataPacket(entityId, (SynchedEntityData) data.build(), true);
|
||||
|
||||
// 1.19.3+
|
||||
return new ClientboundSetEntityDataPacket(entityId, (List<SynchedEntityData.DataValue<?>>) data.build());
|
||||
}
|
||||
|
||||
public static ClientboundSetDisplayObjectivePacket newDisplayObjective(int slot, Objective objective) {
|
||||
// 1.20.1-
|
||||
// return new ClientboundSetDisplayObjectivePacket(slot, objective);
|
||||
|
||||
// 1.20.2+
|
||||
return new ClientboundSetDisplayObjectivePacket(net.minecraft.world.scores.DisplaySlot.values()[slot], objective);
|
||||
}
|
||||
|
||||
public static int getSlot(ClientboundSetDisplayObjectivePacket packet) {
|
||||
// 1.20.1-
|
||||
// return packet.getSlot();
|
||||
|
||||
// 1.20.2+
|
||||
return packet.getSlot().ordinal();
|
||||
}
|
||||
|
||||
public static int getPing(FabricTabPlayer player) {
|
||||
// 1.20.1-
|
||||
// return player.getPlayer().latency;
|
||||
|
||||
// 1.20.2+
|
||||
return player.getPlayer().connection.latency();
|
||||
}
|
||||
|
||||
public static TabList.Skin propertyToSkin(Property property) {
|
||||
// 1.20.1-
|
||||
// return new TabList.Skin(property.getValue(), property.getSignature());
|
||||
|
||||
// 1.20.2+
|
||||
return new TabList.Skin(property.value(), property.signature());
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,6 @@ import me.neznamy.tab.shared.features.sorting.Sorting;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket.Action;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket.Entry;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetObjectivePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket;
|
||||
@@ -39,7 +37,7 @@ public class FabricPipelineInjector extends NettyPipelineInjector {
|
||||
@Override
|
||||
public void onDisplayObjective(@NotNull TabPlayer player, @NotNull Object packet) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(player,
|
||||
((ClientboundSetDisplayObjectivePacket)packet).getSlot().ordinal(),
|
||||
FabricMultiVersion.getSlot((ClientboundSetDisplayObjectivePacket) packet),
|
||||
String.valueOf(((ClientboundSetDisplayObjectivePacket)packet).getObjectiveName()));
|
||||
}
|
||||
|
||||
@@ -67,33 +65,41 @@ public class FabricPipelineInjector extends NettyPipelineInjector {
|
||||
|
||||
@Override
|
||||
public boolean isPlayerInfo(@NotNull Object packet) {
|
||||
return packet instanceof ClientboundPlayerInfoUpdatePacket;
|
||||
return FabricMultiVersion.isPlayerInfo(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerInfo(@NotNull TabPlayer receiver, @NotNull Object packet0) {
|
||||
// Comment this entire method out when compiling with 1.19.2-, adding compatibility would be tough and not worth,
|
||||
// as nobody needs these features on Fabric anyway
|
||||
|
||||
ClientboundPlayerInfoUpdatePacket packet = (ClientboundPlayerInfoUpdatePacket) packet0;
|
||||
EnumSet<Action> actions = packet.actions();
|
||||
List<Entry> updatedList = new ArrayList<>();
|
||||
for (Entry nmsData : packet.entries()) {
|
||||
EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = packet.actions();
|
||||
List<ClientboundPlayerInfoUpdatePacket.Entry> updatedList = new ArrayList<>();
|
||||
for (ClientboundPlayerInfoUpdatePacket.Entry nmsData : packet.entries()) {
|
||||
GameProfile profile = nmsData.profile();
|
||||
Component displayName = nmsData.displayName();
|
||||
int latency = nmsData.latency();
|
||||
if (actions.contains(Action.UPDATE_DISPLAY_NAME)) {
|
||||
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) {
|
||||
IChatBaseComponent newDisplayName = TAB.getInstance().getFeatureManager().onDisplayNameChange(receiver, nmsData.profileId());
|
||||
if (newDisplayName != null) displayName = ((FabricTabPlayer)receiver).getPlatform().toComponent(newDisplayName, receiver.getVersion());
|
||||
}
|
||||
if (actions.contains(Action.UPDATE_LATENCY)) {
|
||||
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY)) {
|
||||
latency = TAB.getInstance().getFeatureManager().onLatencyChange(receiver, nmsData.profileId(), latency);
|
||||
}
|
||||
if (actions.contains(Action.ADD_PLAYER)) {
|
||||
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER)) {
|
||||
TAB.getInstance().getFeatureManager().onEntryAdd(receiver, nmsData.profileId(), profile.getName());
|
||||
}
|
||||
updatedList.add(new Entry(nmsData.profileId(), profile, nmsData.listed(), latency, nmsData.gameMode(), displayName, nmsData.chatSession()));
|
||||
updatedList.add(new ClientboundPlayerInfoUpdatePacket.Entry(nmsData.profileId(), profile, nmsData.listed(), latency, nmsData.gameMode(), displayName, nmsData.chatSession()));
|
||||
}
|
||||
packet.entries = updatedList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLogin(@NotNull Object packet) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyPlayers(@NotNull Object teamPacket) {
|
||||
if (TAB.getInstance().getNameTagManager() == null) return;
|
||||
|
||||
@@ -13,26 +13,19 @@ import me.neznamy.tab.shared.placeholders.expansion.EmptyTabExpansion;
|
||||
import me.neznamy.tab.shared.placeholders.expansion.TabExpansion;
|
||||
import net.fabricmc.fabric.api.networking.v1.PlayerLookup;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.network.chat.Style;
|
||||
import net.minecraft.network.chat.contents.LiteralContents;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Platform implementation for Fabric
|
||||
*/
|
||||
public record FabricPlatform(MinecraftServer server) implements BackendPlatform<Component> {
|
||||
public record FabricPlatform(MinecraftServer server) implements BackendPlatform {
|
||||
|
||||
@Override
|
||||
public void registerUnknownPlaceholder(@NotNull String identifier) {
|
||||
@@ -113,34 +106,17 @@ public record FabricPlatform(MinecraftServer server) implements BackendPlatform<
|
||||
return FabricLoader.getInstance().getConfigDir().resolve(TabConstants.PLUGIN_ID).toFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Converts internal component class to platform's component class
|
||||
*
|
||||
* @param component
|
||||
* Component to convert
|
||||
* @param version
|
||||
* Game version to convert component for
|
||||
* @return Converted component
|
||||
*/
|
||||
public Component toComponent(@NotNull IChatBaseComponent component, @NotNull ProtocolVersion version) {
|
||||
// Text
|
||||
MutableComponent comp = MutableComponent.create(new LiteralContents(component.getText()));
|
||||
|
||||
// Color and style
|
||||
List<ChatFormatting> formats = new ArrayList<>();
|
||||
if (component.getModifier().isUnderlined()) formats.add(ChatFormatting.UNDERLINE);
|
||||
if (component.getModifier().isObfuscated()) formats.add(ChatFormatting.OBFUSCATED);
|
||||
if (component.getModifier().isStrikethrough()) formats.add(ChatFormatting.STRIKETHROUGH);
|
||||
if (component.getModifier().isItalic()) formats.add(ChatFormatting.ITALIC);
|
||||
if (component.getModifier().isBold()) formats.add(ChatFormatting.BOLD);
|
||||
Style style = comp.getStyle().applyFormats(formats.toArray(new ChatFormatting[0]));
|
||||
if (component.getModifier().getColor() != null) {
|
||||
if (version.getMinorVersion() >= 16) {
|
||||
style = style.withColor(component.getModifier().getColor().getRgb());
|
||||
} else {
|
||||
style = style.withColor(ChatFormatting.valueOf(component.getModifier().getColor().getLegacyColor().name()));
|
||||
}
|
||||
}
|
||||
if (component.getModifier().getFont() != null)
|
||||
style = style.withFont(new ResourceLocation(component.getModifier().getFont()));
|
||||
comp.withStyle(style);
|
||||
|
||||
// Extra
|
||||
comp.getSiblings().addAll(component.getExtra().stream().map(c -> toComponent(c, version)).toList());
|
||||
|
||||
return comp;
|
||||
return Component.Serializer.fromJson(component.toString(version));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package me.neznamy.tab.platforms.fabric;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
import me.neznamy.tab.shared.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.platform.Scoreboard;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetObjectivePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetScorePacket;
|
||||
import net.minecraft.server.ServerScoreboard;
|
||||
import net.minecraft.world.scores.Objective;
|
||||
@@ -23,6 +22,9 @@ public class FabricScoreboard extends Scoreboard<FabricTabPlayer> {
|
||||
@NotNull
|
||||
private static final net.minecraft.world.scores.Scoreboard dummyScoreboard = new net.minecraft.world.scores.Scoreboard();
|
||||
|
||||
@NotNull
|
||||
private static final Component EMPTY_COMPONENT = Objects.requireNonNull(Component.Serializer.fromJson(IChatBaseComponent.EMPTY_COMPONENT));
|
||||
|
||||
public FabricScoreboard(FabricTabPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
@@ -30,13 +32,13 @@ public class FabricScoreboard extends Scoreboard<FabricTabPlayer> {
|
||||
@Override
|
||||
public void setDisplaySlot(@NotNull DisplaySlot slot, @NotNull String objective) {
|
||||
player.sendPacket(
|
||||
new ClientboundSetDisplayObjectivePacket(
|
||||
net.minecraft.world.scores.DisplaySlot.values()[slot.ordinal()],
|
||||
FabricMultiVersion.newDisplayObjective(
|
||||
slot.ordinal(),
|
||||
new Objective(
|
||||
dummyScoreboard,
|
||||
objective,
|
||||
ObjectiveCriteria.DUMMY,
|
||||
Component.empty(),
|
||||
EMPTY_COMPONENT,
|
||||
ObjectiveCriteria.RenderType.INTEGER
|
||||
)
|
||||
)
|
||||
@@ -67,7 +69,7 @@ public class FabricScoreboard extends Scoreboard<FabricTabPlayer> {
|
||||
dummyScoreboard,
|
||||
objectiveName,
|
||||
ObjectiveCriteria.DUMMY,
|
||||
Component.empty(),
|
||||
EMPTY_COMPONENT,
|
||||
ObjectiveCriteria.RenderType.INTEGER
|
||||
),
|
||||
1
|
||||
@@ -104,12 +106,12 @@ public class FabricScoreboard extends Scoreboard<FabricTabPlayer> {
|
||||
team.setPlayerPrefix(player.getPlatform().toComponent(IChatBaseComponent.optimizedComponent(prefix), player.getVersion()));
|
||||
team.setPlayerSuffix(player.getPlatform().toComponent(IChatBaseComponent.optimizedComponent(suffix), player.getVersion()));
|
||||
team.getPlayers().addAll(players);
|
||||
player.sendPacket(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true));
|
||||
player.sendPacket(FabricMultiVersion.createTeam(team));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterTeam0(@NotNull String name) {
|
||||
player.sendPacket(ClientboundSetPlayerTeamPacket.createRemovePacket(new PlayerTeam(dummyScoreboard, name)));
|
||||
player.sendPacket(FabricMultiVersion.removeTeam(new PlayerTeam(dummyScoreboard, name)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,7 +125,7 @@ public class FabricScoreboard extends Scoreboard<FabricTabPlayer> {
|
||||
team.setNameTagVisibility(Team.Visibility.valueOf(visibility.name()));
|
||||
team.setPlayerPrefix(player.getPlatform().toComponent(IChatBaseComponent.optimizedComponent(prefix), player.getVersion()));
|
||||
team.setPlayerSuffix(player.getPlatform().toComponent(IChatBaseComponent.optimizedComponent(suffix), player.getVersion()));
|
||||
player.sendPacket(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, false));
|
||||
player.sendPacket(FabricMultiVersion.updateTeam(team));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,7 +3,6 @@ package me.neznamy.tab.platforms.fabric;
|
||||
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import net.fabricmc.api.DedicatedServerModInitializer;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
@@ -15,7 +14,7 @@ public class FabricTAB implements DedicatedServerModInitializer {
|
||||
|
||||
@Override
|
||||
public void onInitializeServer() {
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, $, $$) -> new FabricTabCommand().onRegisterCommands(dispatcher));
|
||||
FabricMultiVersion.registerCommand();
|
||||
ServerLifecycleEvents.SERVER_STARTING.register(server -> TAB.create(new FabricPlatform(server)));
|
||||
ServerLifecycleEvents.SERVER_STOPPING.register($ -> TAB.getInstance().unload());
|
||||
}
|
||||
|
||||
@@ -51,7 +51,8 @@ public class FabricTabCommand {
|
||||
boolean hasReloadPermission = FabricTAB.hasPermission(source, TabConstants.Permission.COMMAND_RELOAD);
|
||||
boolean hasAdminPermission = FabricTAB.hasPermission(source, TabConstants.Permission.COMMAND_ALL);
|
||||
for (String message : TAB.getInstance().getDisabledCommand().execute(args, hasReloadPermission, hasAdminPermission)) {
|
||||
source.sendSystemMessage(((FabricPlatform)TAB.getInstance().getPlatform()).toComponent(IChatBaseComponent.optimizedComponent(message), TAB.getInstance().getServerVersion()));
|
||||
FabricMultiVersion.sendSystemMessage(source, ((FabricPlatform)TAB.getInstance().getPlatform()).toComponent(
|
||||
IChatBaseComponent.optimizedComponent(message), TAB.getInstance().getServerVersion()));
|
||||
}
|
||||
} else {
|
||||
if (source.getEntity() == null) {
|
||||
|
||||
@@ -7,11 +7,6 @@ import lombok.RequiredArgsConstructor;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundTabListPacket;
|
||||
import net.minecraft.world.level.GameType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -21,71 +16,58 @@ public record FabricTabList(@NotNull FabricTabPlayer player) implements TabList
|
||||
|
||||
@Override
|
||||
public void removeEntry(@NotNull UUID entry) {
|
||||
player.sendPacket(new ClientboundPlayerInfoRemovePacket(Collections.singletonList(entry)));
|
||||
player.sendPacket(FabricMultiVersion.build(Action.REMOVE_PLAYER, new Builder(entry)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDisplayName(@NotNull UUID entry, @Nullable IChatBaseComponent displayName) {
|
||||
player.sendPacket(build(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME),
|
||||
new Builder(entry).setDisplayName(displayName == null ? null : player.getPlatform().toComponent(displayName, player.getVersion()))));
|
||||
player.sendPacket(FabricMultiVersion.build(Action.UPDATE_DISPLAY_NAME,
|
||||
new Builder(entry).setDisplayName(displayName == null ? null : player.getPlatform().toComponent(displayName, player.getVersion()))
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLatency(@NotNull UUID entry, int latency) {
|
||||
player.sendPacket(build(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY), new Builder(entry).setLatency(latency)));
|
||||
player.sendPacket(FabricMultiVersion.build(Action.UPDATE_LATENCY, new Builder(entry).setLatency(latency)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateGameMode(@NotNull UUID entry, int gameMode) {
|
||||
player.sendPacket(build(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE), new Builder(entry).setGameMode(gameMode)));
|
||||
player.sendPacket(FabricMultiVersion.build(Action.UPDATE_GAME_MODE, new Builder(entry).setGameMode(gameMode)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntry(@NotNull Entry entry) {
|
||||
player.sendPacket(build(EnumSet.allOf(ClientboundPlayerInfoUpdatePacket.Action.class), new Builder(entry.getUniqueId())
|
||||
player.sendPacket(FabricMultiVersion.build(Action.ADD_PLAYER, new Builder(entry.getUniqueId())
|
||||
.setName(entry.getName())
|
||||
.setSkin(entry.getSkin())
|
||||
.setGameMode(entry.getGameMode())
|
||||
.setLatency(entry.getLatency())
|
||||
.setDisplayName(entry.getDisplayName() == null ? null : player.getPlatform().toComponent(entry.getDisplayName(), player.getVersion()))));
|
||||
.setDisplayName(entry.getDisplayName() == null ? null : player.getPlatform().toComponent(entry.getDisplayName(), player.getVersion()))
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerListHeaderFooter(@NotNull IChatBaseComponent header, @NotNull IChatBaseComponent footer) {
|
||||
player.getPlayer().connection.send(new ClientboundTabListPacket(
|
||||
player.getPlayer().connection.send(FabricMultiVersion.setHeaderFooter(
|
||||
player.getPlatform().toComponent(header, player.getVersion()),
|
||||
player.getPlatform().toComponent(footer, player.getVersion()))
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Packet<?> build(@NotNull EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions, @NotNull FabricTabList.Builder entry) {
|
||||
ClientboundPlayerInfoUpdatePacket packet = new ClientboundPlayerInfoUpdatePacket(actions, Collections.emptyList());
|
||||
packet.entries = Collections.singletonList(new ClientboundPlayerInfoUpdatePacket.Entry(
|
||||
entry.getId(),
|
||||
entry.createProfile(),
|
||||
true,
|
||||
entry.getLatency(),
|
||||
GameType.byId(entry.getGameMode()),
|
||||
entry.getDisplayName(),
|
||||
null
|
||||
));
|
||||
return packet;
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public static class Builder {
|
||||
|
||||
@NotNull private final UUID id;
|
||||
@Nullable private String name;
|
||||
@NotNull private String name = ""; // Avoid nullability issues as things are changing over versions
|
||||
@Nullable private Skin skin;
|
||||
private int latency;
|
||||
private int gameMode;
|
||||
@Nullable private Component displayName;
|
||||
|
||||
@NotNull
|
||||
public Builder setName(@Nullable String name) {
|
||||
public Builder setName(@NotNull String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
@@ -114,9 +96,8 @@ public record FabricTabList(@NotNull FabricTabPlayer player) implements TabList
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
public GameProfile createProfile() {
|
||||
if (name == null) return null;
|
||||
GameProfile profile = new GameProfile(id, name);
|
||||
if (skin != null) {
|
||||
profile.getProperties().put(TabList.TEXTURES_PROPERTY,
|
||||
|
||||
@@ -31,7 +31,7 @@ public class FabricTabPlayer extends BackendTabPlayer {
|
||||
private final EntityView entityView = new FabricEntityView(this);
|
||||
|
||||
public FabricTabPlayer(@NotNull FabricPlatform platform, @NotNull ServerPlayer player) {
|
||||
super(platform, player, player.getUUID(), player.getGameProfile().getName(), player.level().dimension().location().toString());
|
||||
super(platform, player, player.getUUID(), player.getGameProfile().getName(), "N/A");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -41,12 +41,12 @@ public class FabricTabPlayer extends BackendTabPlayer {
|
||||
|
||||
@Override
|
||||
public int getPing() {
|
||||
return getPlayer().connection.latency();
|
||||
return FabricMultiVersion.getPing(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(@NotNull IChatBaseComponent message) {
|
||||
getPlayer().sendSystemMessage(getPlatform().toComponent(message, getVersion()));
|
||||
FabricMultiVersion.sendMessage(this, getPlatform().toComponent(message, getVersion()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,7 +65,7 @@ public class FabricTabPlayer extends BackendTabPlayer {
|
||||
Collection<Property> properties = getPlayer().getGameProfile().getProperties().get(TabList.TEXTURES_PROPERTY);
|
||||
if (properties.isEmpty()) return null; // Offline mode
|
||||
Property skinProperty = properties.iterator().next();
|
||||
return new TabList.Skin(skinProperty.value(), skinProperty.signature());
|
||||
return FabricMultiVersion.propertyToSkin(skinProperty);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,33 +1,25 @@
|
||||
package me.neznamy.tab.platforms.fabric.features;
|
||||
|
||||
import me.neznamy.tab.platforms.fabric.FabricMultiVersion;
|
||||
import me.neznamy.tab.platforms.fabric.FabricTabPlayer;
|
||||
import me.neznamy.tab.shared.backend.EntityData;
|
||||
import me.neznamy.tab.shared.backend.features.unlimitedtags.BackendNameTagX;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class FabricNameTagX extends BackendNameTagX {
|
||||
|
||||
private boolean enabled = true;
|
||||
public boolean enabled = true;
|
||||
|
||||
public FabricNameTagX() {
|
||||
ServerPlayerEvents.AFTER_RESPAWN.register((oldPlayer, newPlayer, alive) -> {
|
||||
if (enabled) respawn(oldPlayer.getUUID());
|
||||
});
|
||||
// no sneaking for fabric //TODO
|
||||
FabricMultiVersion.registerNameTagXEvents(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,7 +31,7 @@ public class FabricNameTagX extends BackendNameTagX {
|
||||
|
||||
@Override
|
||||
public boolean areInSameWorld(@NotNull TabPlayer player1, @NotNull TabPlayer player2) {
|
||||
return ((FabricTabPlayer)player1).getPlayer().level() == ((FabricTabPlayer)player2).getPlayer().level();
|
||||
return ((FabricTabPlayer)player1).getPlayer().level == ((FabricTabPlayer)player2).getPlayer().level;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,7 +69,7 @@ public class FabricNameTagX extends BackendNameTagX {
|
||||
|
||||
@Override
|
||||
public boolean isSneaking(@NotNull TabPlayer player) {
|
||||
return ((FabricTabPlayer)player).getPlayer().isCrouching();
|
||||
return FabricMultiVersion.isSneaking(((FabricTabPlayer)player).getPlayer());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -119,13 +111,7 @@ public class FabricNameTagX extends BackendNameTagX {
|
||||
@Override
|
||||
@NotNull
|
||||
public EntityData createDataWatcher(@NotNull TabPlayer viewer, byte flags, @NotNull String displayName, boolean nameVisible) {
|
||||
return () -> Arrays.asList(
|
||||
new SynchedEntityData.DataValue<>(0, EntityDataSerializers.BYTE, flags),
|
||||
new SynchedEntityData.DataValue<>(2, EntityDataSerializers.OPTIONAL_COMPONENT,
|
||||
Optional.of(((FabricTabPlayer)viewer).getPlatform().toComponent(IChatBaseComponent.optimizedComponent(displayName), viewer.getVersion()))),
|
||||
new SynchedEntityData.DataValue<>(3, EntityDataSerializers.BOOLEAN, nameVisible),
|
||||
new SynchedEntityData.DataValue<>(15, EntityDataSerializers.BYTE, (byte)16)
|
||||
);
|
||||
return FabricMultiVersion.createDataWatcher(viewer, flags, displayName, nameVisible);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -8,6 +8,9 @@ accessible field net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPac
|
||||
mutable field net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket players Ljava/util/Collection;
|
||||
accessible field net/minecraft/server/network/ServerCommonPacketListenerImpl connection Lnet/minecraft/network/Connection;
|
||||
|
||||
# 1.20+
|
||||
accessible field net/minecraft/world/entity/Entity level Lnet/minecraft/world/level/Level;
|
||||
|
||||
# new
|
||||
accessible field net/minecraft/server/MinecraftServer LOGGER Lorg/slf4j/Logger;
|
||||
mutable field net/minecraft/server/MinecraftServer LOGGER Lorg/slf4j/Logger;
|
||||
|
||||
@@ -159,12 +159,11 @@ public class FeatureManager {
|
||||
((PlayerPlaceholder)TAB.getInstance().getPlaceholderManager().getPlaceholder(TabConstants.Placeholder.WORLD)).updateValue(changed, to);
|
||||
}
|
||||
|
||||
public void onServerChange(@NotNull UUID playerUUID, @NotNull String to) {
|
||||
public void onServerChange(@NotNull UUID playerUUID, @NotNull String to, boolean callOnLoginPacket) {
|
||||
TabPlayer changed = TAB.getInstance().getPlayer(playerUUID);
|
||||
if (changed == null) return;
|
||||
String from = changed.getServer();
|
||||
changed.setServer(to);
|
||||
changed.getScoreboard().clearRegisteredObjectives();
|
||||
((ProxyTabPlayer)changed).sendJoinPluginMessage();
|
||||
for (TabFeature f : values) {
|
||||
if (!(f instanceof ServerSwitchListener)) continue;
|
||||
@@ -173,6 +172,7 @@ public class FeatureManager {
|
||||
TAB.getInstance().getCPUManager().addTime(f, TabConstants.CpuUsageCategory.SERVER_SWITCH, System.nanoTime()-time);
|
||||
}
|
||||
((PlayerPlaceholder)TAB.getInstance().getPlaceholderManager().getPlaceholder(TabConstants.Placeholder.SERVER)).updateValue(changed, to);
|
||||
if (callOnLoginPacket) onLoginPacket(changed);
|
||||
}
|
||||
|
||||
public boolean onCommand(@Nullable TabPlayer sender, @NotNull String command) {
|
||||
@@ -271,6 +271,16 @@ public class FeatureManager {
|
||||
return newLatency;
|
||||
}
|
||||
|
||||
public void onLoginPacket(TabPlayer packetReceiver) {
|
||||
packetReceiver.getScoreboard().clearRegisteredObjectives();
|
||||
for (TabFeature f : values) {
|
||||
if (!(f instanceof LoginPacketListener)) continue;
|
||||
long time = System.nanoTime();
|
||||
((LoginPacketListener)f).onLoginPacket(packetReceiver);
|
||||
TAB.getInstance().getCPUManager().addTime(f, TabConstants.CpuUsageCategory.PACKET_LOGIN, System.nanoTime() - time);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerFeature(@NotNull String featureName, @NotNull TabFeature featureHandler) {
|
||||
features.put(featureName, featureHandler);
|
||||
values = features.values().toArray(new TabFeature[0]);
|
||||
@@ -304,51 +314,50 @@ public class FeatureManager {
|
||||
FeatureManager featureManager = TAB.getInstance().getFeatureManager();
|
||||
int minorVersion = TAB.getInstance().getServerVersion().getMinorVersion();
|
||||
|
||||
if (configuration.getConfig().getBoolean("ping-spoof.enabled", false))
|
||||
featureManager.registerFeature(TabConstants.Feature.PING_SPOOF, new PingSpoof());
|
||||
boolean pingSpoof = configuration.getConfig().getBoolean("ping-spoof.enabled", false);
|
||||
boolean bossbar = configuration.getConfig().getBoolean("bossbar.enabled", false);
|
||||
boolean headerFooter = configuration.getConfig().getBoolean("header-footer.enabled", true);
|
||||
boolean spectatorFix = configuration.getConfig().getBoolean("prevent-spectator-effect.enabled", false);
|
||||
boolean scoreboard = configuration.getConfig().getBoolean("scoreboard.enabled", false);
|
||||
boolean perWorldPlayerList = configuration.getConfig().getBoolean("per-world-playerlist.enabled", false);
|
||||
boolean layout = configuration.getConfig().getBoolean("layout.enabled", false);
|
||||
boolean yellowNumber = configuration.getConfig().getBoolean("yellow-number-in-tablist.enabled", true);
|
||||
boolean belowName = configuration.getConfig().getBoolean("belowname-objective.enabled", false);
|
||||
boolean teams = configuration.getConfig().getBoolean("scoreboard-teams.enabled", true);
|
||||
boolean unlimitedTags = configuration.getConfig().getBoolean("scoreboard-teams.unlimited-nametag-mode.enabled", false);
|
||||
boolean globalPlayerList = configuration.getConfig().getBoolean("global-playerlist.enabled", false);
|
||||
boolean tablistFormatting = configuration.getConfig().getBoolean("tablist-name-formatting.enabled", true);
|
||||
boolean alignedSuffix = configuration.getConfig().getBoolean("tablist-name-formatting.align-tabsuffix-on-the-right", false);
|
||||
|
||||
if (configuration.getConfig().getBoolean("bossbar.enabled", false)) {
|
||||
featureManager.registerFeature(TabConstants.Feature.BOSS_BAR,
|
||||
minorVersion >= 9 ? new BossBarManagerImpl() : TAB.getInstance().getPlatform().getLegacyBossBar());
|
||||
}
|
||||
|
||||
if (configuration.getConfig().getBoolean("header-footer.enabled", true))
|
||||
featureManager.registerFeature(TabConstants.Feature.HEADER_FOOTER, new HeaderFooter());
|
||||
|
||||
if (configuration.getConfig().getBoolean("prevent-spectator-effect.enabled", false))
|
||||
featureManager.registerFeature(TabConstants.Feature.SPECTATOR_FIX, new SpectatorFix());
|
||||
if (perWorldPlayerList && layout) TAB.getInstance().getMisconfigurationHelper().bothPerWorldPlayerListAndLayoutEnabled();
|
||||
if (yellowNumber && layout) TAB.getInstance().getMisconfigurationHelper().layoutBreaksYellowNumber();
|
||||
if (spectatorFix && layout) TAB.getInstance().getMisconfigurationHelper().layoutIncludesPreventSpectatorEffect();
|
||||
if (globalPlayerList && layout) TAB.getInstance().getMisconfigurationHelper().bothGlobalPlayerListAndLayoutEnabled();
|
||||
|
||||
if (configuration.isPipelineInjection()) {
|
||||
PipelineInjector inj = TAB.getInstance().getPlatform().createPipelineInjector();
|
||||
if (inj != null) featureManager.registerFeature(TabConstants.Feature.PIPELINE_INJECTION, inj);
|
||||
}
|
||||
|
||||
if (configuration.getConfig().getBoolean("scoreboard.enabled", false))
|
||||
featureManager.registerFeature(TabConstants.Feature.SCOREBOARD, new ScoreboardManagerImpl());
|
||||
|
||||
if (configuration.getConfig().getBoolean("per-world-playerlist.enabled", false)) {
|
||||
if (perWorldPlayerList) {
|
||||
TabFeature pwp = TAB.getInstance().getPlatform().getPerWorldPlayerList();
|
||||
if (pwp != null) featureManager.registerFeature(TabConstants.Feature.PER_WORLD_PLAYER_LIST, pwp);
|
||||
if (configuration.getConfig().getBoolean("layout.enabled", false)) {
|
||||
TAB.getInstance().getMisconfigurationHelper().bothPerWorldPlayerListAndLayoutEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
if (configuration.getConfig().getBoolean("yellow-number-in-tablist.enabled", true))
|
||||
featureManager.registerFeature(TabConstants.Feature.YELLOW_NUMBER, new YellowNumber());
|
||||
|
||||
if (configuration.getConfig().getBoolean("belowname-objective.enabled", true))
|
||||
featureManager.registerFeature(TabConstants.Feature.BELOW_NAME, new BelowName());
|
||||
|
||||
// No requirements, but due to chicken vs egg, the feature uses NameTags, Layout and RedisBungee
|
||||
if (configuration.getConfig().getBoolean("scoreboard-teams.enabled", true) ||
|
||||
configuration.getConfig().getBoolean("layout.enabled", false)) {
|
||||
featureManager.registerFeature(TabConstants.Feature.SORTING, new Sorting());
|
||||
if (bossbar) {
|
||||
featureManager.registerFeature(TabConstants.Feature.BOSS_BAR,
|
||||
minorVersion >= 9 ? new BossBarManagerImpl() : TAB.getInstance().getPlatform().getLegacyBossBar());
|
||||
}
|
||||
if (pingSpoof) featureManager.registerFeature(TabConstants.Feature.PING_SPOOF, new PingSpoof());
|
||||
if (headerFooter) featureManager.registerFeature(TabConstants.Feature.HEADER_FOOTER, new HeaderFooter());
|
||||
if (spectatorFix) featureManager.registerFeature(TabConstants.Feature.SPECTATOR_FIX, new SpectatorFix());
|
||||
if (scoreboard) featureManager.registerFeature(TabConstants.Feature.SCOREBOARD, new ScoreboardManagerImpl());
|
||||
if (yellowNumber) featureManager.registerFeature(TabConstants.Feature.YELLOW_NUMBER, new YellowNumber());
|
||||
if (belowName) featureManager.registerFeature(TabConstants.Feature.BELOW_NAME, new BelowName());
|
||||
if (teams || layout) featureManager.registerFeature(TabConstants.Feature.SORTING, new Sorting());
|
||||
|
||||
// Must be loaded after: Sorting
|
||||
if (configuration.getConfig().getBoolean("scoreboard-teams.enabled", true)) {
|
||||
if (configuration.getConfig().getBoolean("scoreboard-teams.unlimited-nametag-mode.enabled", false) && minorVersion >= 8) {
|
||||
if (teams) {
|
||||
if (unlimitedTags && minorVersion >= 8) {
|
||||
NameTag unlimited = TAB.getInstance().getPlatform().getUnlimitedNameTags();
|
||||
if (unlimited instanceof NameTagX) {
|
||||
featureManager.registerFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS, unlimited);
|
||||
@@ -361,19 +370,11 @@ public class FeatureManager {
|
||||
}
|
||||
|
||||
// Must be loaded after: Sorting
|
||||
if (minorVersion >= 8 && configuration.getConfig().getBoolean("layout.enabled", false)) {
|
||||
featureManager.registerFeature(TabConstants.Feature.LAYOUT, new LayoutManagerImpl());
|
||||
if (configuration.getConfig().getBoolean("yellow-number-in-tablist.enabled", true)) {
|
||||
TAB.getInstance().getMisconfigurationHelper().layoutBreaksYellowNumber();
|
||||
}
|
||||
if (configuration.getConfig().getBoolean("prevent-spectator-effect.enabled", false)) {
|
||||
TAB.getInstance().getMisconfigurationHelper().layoutIncludesPreventSpectatorEffect();
|
||||
}
|
||||
}
|
||||
if (layout) featureManager.registerFeature(TabConstants.Feature.LAYOUT, new LayoutManagerImpl());
|
||||
|
||||
// Must be loaded after: Layout
|
||||
if (minorVersion >= 8 && configuration.getConfig().getBoolean("tablist-name-formatting.enabled", true)) {
|
||||
if (configuration.getConfig().getBoolean("tablist-name-formatting.align-tabsuffix-on-the-right", false)) {
|
||||
if (tablistFormatting) {
|
||||
if (alignedSuffix) {
|
||||
featureManager.registerFeature(TabConstants.Feature.PLAYER_LIST, new AlignedPlayerList());
|
||||
} else {
|
||||
featureManager.registerFeature(TabConstants.Feature.PLAYER_LIST, new PlayerList());
|
||||
@@ -381,12 +382,8 @@ public class FeatureManager {
|
||||
}
|
||||
|
||||
// Must be loaded after: PlayerList
|
||||
if (configuration.getConfig().getBoolean("global-playerlist.enabled", false) &&
|
||||
TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY) {
|
||||
if (globalPlayerList && TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY) {
|
||||
featureManager.registerFeature(TabConstants.Feature.GLOBAL_PLAYER_LIST, new GlobalPlayerList());
|
||||
if (configuration.getConfig().getBoolean("layout.enabled", false)) {
|
||||
TAB.getInstance().getMisconfigurationHelper().bothGlobalPlayerListAndLayoutEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
// Must be loaded after: Global PlayerList, PlayerList, NameTags, YellowNumber, BelowName
|
||||
|
||||
@@ -9,6 +9,7 @@ import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.features.layout.LayoutManagerImpl;
|
||||
import me.neznamy.tab.shared.features.sorting.types.SortingType;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
import me.neznamy.tab.shared.proxy.ProxyTabPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -361,7 +362,10 @@ public class MisconfigurationHelper {
|
||||
// Runtime Errors
|
||||
// ------------------------
|
||||
|
||||
public void invalidNumberForBossBarProgress(@NotNull String bossBar, @NotNull String input, @NotNull String configuredValue) {
|
||||
public void invalidNumberForBossBarProgress(@NotNull String bossBar, @NotNull String input, @NotNull String configuredValue, TabPlayer player) {
|
||||
// Placeholders are not initialized, because bridge did not respond yet (typically on join)
|
||||
if (player instanceof ProxyTabPlayer && !((ProxyTabPlayer)player).isBridgeConnected()) return;
|
||||
|
||||
if (configuredValue.contains("%")) {
|
||||
TAB.getInstance().getPlatform().logWarn(new IChatBaseComponent("Placeholder \"" + configuredValue +
|
||||
"\" used in BossBar progress of \"" + bossBar + "\" returned value, which cannot be evaluated to a number between 0 and 100 (\"" + input + "\")"));
|
||||
@@ -373,6 +377,9 @@ public class MisconfigurationHelper {
|
||||
}
|
||||
|
||||
public void invalidInputForNumericSorting(SortingType type, String placeholder, String output, TabPlayer player) {
|
||||
// Placeholders are not initialized, because bridge did not respond yet (typically on join)
|
||||
if (player instanceof ProxyTabPlayer && !((ProxyTabPlayer)player).isBridgeConnected()) return;
|
||||
|
||||
TAB.getInstance().getPlatform().logWarn(new IChatBaseComponent("Placeholder " + placeholder + " used in sorting type " +
|
||||
type + " returned \"" + output + "\" for player " + player.getName() + ", which is not a valid number."));
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ public class Property {
|
||||
}
|
||||
String rawFormattedValue0 = value;
|
||||
for (String placeholder : placeholders0) {
|
||||
rawFormattedValue0 = rawFormattedValue0.replace(placeholder, "%s");
|
||||
rawFormattedValue0 = replaceFirst(rawFormattedValue0, placeholder, "%s");
|
||||
}
|
||||
if (placeholders0.size() > 0 && rawFormattedValue0.contains("%")) {
|
||||
int index = rawFormattedValue0.lastIndexOf('%');
|
||||
@@ -129,6 +129,15 @@ public class Property {
|
||||
}
|
||||
}
|
||||
|
||||
private String replaceFirst(String original, String searchString, String replacement) {
|
||||
int index = original.indexOf(searchString);
|
||||
if (index != -1) {
|
||||
return original.substring(0, index) + replacement + original.substring(index + searchString.length());
|
||||
} else {
|
||||
return original;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes raw value to new provided value and performs all
|
||||
* operations related to it. Changes source as well.
|
||||
|
||||
@@ -74,6 +74,9 @@ public enum ProtocolVersion {
|
||||
V1_5_1 (60),
|
||||
V1_5 (60);
|
||||
|
||||
/** Newest MC version this plugin jar knows */
|
||||
public static final ProtocolVersion LATEST_KNOWN_VERSION = ProtocolVersion.V1_20_2;
|
||||
|
||||
/** Version's network id found at https://wiki.vg/Protocol_version_numbers */
|
||||
private final int networkId;
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ public class TAB extends TabAPI {
|
||||
@Getter private final DisabledCommand disabledCommand = new DisabledCommand();
|
||||
|
||||
/** Implementation of platform the plugin is installed on for platform-specific calls */
|
||||
@Getter private final Platform<?> platform;
|
||||
@Getter private final Platform platform;
|
||||
|
||||
/**
|
||||
* CPU manager for thread and task management as well as
|
||||
@@ -107,7 +107,7 @@ public class TAB extends TabAPI {
|
||||
* @param platform
|
||||
* Platform interface
|
||||
*/
|
||||
public static void create(@NotNull Platform<?> platform) {
|
||||
public static void create(@NotNull Platform platform) {
|
||||
instance = new TAB(platform);
|
||||
instance.load();
|
||||
}
|
||||
@@ -119,7 +119,7 @@ public class TAB extends TabAPI {
|
||||
* @param platform
|
||||
* Platform interface
|
||||
*/
|
||||
private TAB(@NotNull Platform<?> platform) {
|
||||
private TAB(@NotNull Platform platform) {
|
||||
this.platform = platform;
|
||||
this.serverVersion = platform.getServerVersion();
|
||||
this.dataFolder = platform.getDataFolder();
|
||||
@@ -134,7 +134,7 @@ public class TAB extends TabAPI {
|
||||
platform.registerCommand();
|
||||
platform.startMetrics();
|
||||
if (platform instanceof ProxyPlatform) {
|
||||
((ProxyPlatform<?>) platform).registerChannel();
|
||||
((ProxyPlatform) platform).registerChannel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ public class TabConstants {
|
||||
public static final String PACKET_ENTITY_SPAWN = "PacketPlayOutNamedEntitySpawn";
|
||||
public static final String PACKET_ENTITY_DESTROY = "PacketPlayOutEntityDestroy";
|
||||
public static final String RAW_PACKET_OUT = "Packet reading (out)";
|
||||
public static final String PACKET_LOGIN = "Login packet";
|
||||
|
||||
public static final String PLACEHOLDER_REFRESHING = "Refreshing placeholders";
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import me.neznamy.tab.shared.platform.Platform;
|
||||
import me.neznamy.tab.shared.features.redis.RedisSupport;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface BackendPlatform<T> extends Platform<T> {
|
||||
public interface BackendPlatform extends Platform {
|
||||
|
||||
@Override
|
||||
@NotNull default GroupManager detectPermissionPlugin() {
|
||||
|
||||
@@ -26,7 +26,7 @@ public abstract class BackendTabPlayer extends TabPlayer {
|
||||
* @param world
|
||||
* Player's world
|
||||
*/
|
||||
protected BackendTabPlayer(@NotNull BackendPlatform<?> platform, @NotNull Object player, @NotNull UUID uniqueId,
|
||||
protected BackendTabPlayer(@NotNull BackendPlatform platform, @NotNull Object player, @NotNull UUID uniqueId,
|
||||
@NotNull String name, @NotNull String world) {
|
||||
super(platform, player, uniqueId, name, TAB.getInstance().getConfiguration().getServerName(),
|
||||
world, ViaVersionHook.getInstance().getPlayerVersion(uniqueId, name), true);
|
||||
|
||||
@@ -12,14 +12,11 @@ public class MiniMessageFormat implements RGBFormatter {
|
||||
|
||||
@Override
|
||||
public @NotNull String reformat(@NotNull String text) {
|
||||
if (
|
||||
!text.contains("<") // No MiniMessage syntax is used
|
||||
|| text.contains(EnumChatFormat.COLOR_STRING) // MiniMessage throws errors when using legacy color code
|
||||
) return text;
|
||||
try {
|
||||
return LegacyComponentSerializer.legacySection().serialize(MiniMessage.miniMessage().deserialize(text));
|
||||
} catch (Throwable ignored) {
|
||||
return text;
|
||||
if (text.contains("<") && !text.contains(EnumChatFormat.COLOR_STRING)) {
|
||||
try {
|
||||
return LegacyComponentSerializer.legacySection().serialize(MiniMessage.miniMessage().deserialize(text));
|
||||
} catch (Throwable ignored) {}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,8 @@ import java.util.concurrent.*;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
|
||||
import lombok.Getter;
|
||||
import me.neznamy.tab.shared.ProtocolVersion;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.features.types.TabFeature;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -52,11 +50,6 @@ public class CpuManager {
|
||||
lastReport = new CpuReport(UPDATE_RATE_SECONDS, featureUsageCurrent, placeholderUsageCurrent);
|
||||
featureUsageCurrent = new ConcurrentHashMap<>();
|
||||
placeholderUsageCurrent = new ConcurrentHashMap<>();
|
||||
if (lastReport.getPlaceholderUsageTotal() > 50) {
|
||||
TAB.getInstance().getPlatform().logWarn(new IChatBaseComponent("CPU usage of placeholders is " + (int) lastReport.getPlaceholderUsageTotal() +
|
||||
"%. See /" + (TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY ? TabConstants.COMMAND_PROXY : TabConstants.COMMAND_BACKEND) +
|
||||
" cpu for more info. Try increasing refresh intervals."));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import java.util.Map;
|
||||
* Feature handler for BelowName feature
|
||||
*/
|
||||
public class BelowName extends TabFeature implements JoinListener, Loadable, UnLoadable,
|
||||
ServerSwitchListener, Refreshable {
|
||||
Refreshable, LoginPacketListener {
|
||||
|
||||
public static final String OBJECTIVE_NAME = "TAB-BelowName";
|
||||
|
||||
@@ -98,20 +98,6 @@ public class BelowName extends TabFeature implements JoinListener, Loadable, UnL
|
||||
if (redis != null) redis.updateBelowName(connectedPlayer, number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerChange(@NotNull TabPlayer player, @NotNull String from, @NotNull String to) {
|
||||
if (disableChecker.isDisabledPlayer(player)) return;
|
||||
player.getScoreboard().registerObjective(
|
||||
OBJECTIVE_NAME,
|
||||
player.getProperty(TabConstants.Property.BELOWNAME_TEXT).updateAndGet(),
|
||||
Scoreboard.HealthDisplay.INTEGER
|
||||
);
|
||||
player.getScoreboard().setDisplaySlot(Scoreboard.DisplaySlot.BELOW_NAME, OBJECTIVE_NAME);
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
player.getScoreboard().setScore(OBJECTIVE_NAME, all.getNickname(), getValue(all));
|
||||
}
|
||||
}
|
||||
|
||||
public void onDisableConditionChange(TabPlayer p, boolean disabledNow) {
|
||||
if (disabledNow) {
|
||||
p.getScoreboard().unregisterObjective(OBJECTIVE_NAME);
|
||||
@@ -134,6 +120,16 @@ public class BelowName extends TabFeature implements JoinListener, Loadable, UnL
|
||||
if (redis != null) redis.updateBelowName(refreshed, number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginPacket(TabPlayer player) {
|
||||
if (disableChecker.isDisabledPlayer(player) || !player.isLoaded()) return;
|
||||
player.getScoreboard().registerObjective(OBJECTIVE_NAME, player.getProperty(TabConstants.Property.BELOWNAME_TEXT).updateAndGet(), Scoreboard.HealthDisplay.INTEGER);
|
||||
player.getScoreboard().setDisplaySlot(Scoreboard.DisplaySlot.BELOW_NAME, OBJECTIVE_NAME);
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (all.isLoaded()) player.getScoreboard().setScore(OBJECTIVE_NAME, all.getNickname(), getValue(all));
|
||||
}
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public static class TextRefresher extends TabFeature implements Refreshable {
|
||||
|
||||
|
||||
@@ -2,6 +2,11 @@ package me.neznamy.tab.shared.features;
|
||||
|
||||
import lombok.Getter;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.features.layout.LayoutManagerImpl;
|
||||
import me.neznamy.tab.shared.features.layout.LayoutView;
|
||||
import me.neznamy.tab.shared.features.layout.ParentGroup;
|
||||
import me.neznamy.tab.shared.features.layout.PlayerSlot;
|
||||
import me.neznamy.tab.shared.features.types.*;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -20,13 +25,26 @@ public class PingSpoof extends TabFeature implements JoinListener, LatencyListen
|
||||
/** Value to display as ping instead of real ping */
|
||||
private final int value = TAB.getInstance().getConfig().getInt("ping-spoof.value", 0);
|
||||
|
||||
private LayoutManagerImpl layoutManager;
|
||||
|
||||
@Override
|
||||
public int onLatencyChange(TabPlayer packetReceiver, UUID id, int latency) {
|
||||
return value;
|
||||
public int onLatencyChange(@NotNull TabPlayer packetReceiver, @NotNull UUID id, int latency) {
|
||||
if (layoutManager != null) {
|
||||
LayoutView layout = layoutManager.getViews().get(packetReceiver);
|
||||
if (layout != null) {
|
||||
for (ParentGroup group : layout.getGroups()) {
|
||||
PlayerSlot slot = group.getPlayerSlots().get((int) id.getLeastSignificantBits());
|
||||
if (slot != null && slot.getPlayer() != null) return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TAB.getInstance().getPlayer(id) != null) return value;
|
||||
return latency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
layoutManager = TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.LAYOUT);
|
||||
updateAll(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -295,4 +295,8 @@ public class PlaceholderManagerImpl extends TabFeature implements PlaceholderMan
|
||||
placeholderUsage.remove(identifier);
|
||||
recalculateUsedPlaceholders();
|
||||
}
|
||||
|
||||
public boolean isPlaceholderRegistered(@NotNull String identifier) {
|
||||
return registeredPlaceholders.containsKey(identifier);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
* PLAYER_LIST display slot (in tablist).
|
||||
*/
|
||||
public class YellowNumber extends TabFeature implements JoinListener, Loadable, UnLoadable,
|
||||
ServerSwitchListener, Refreshable {
|
||||
Refreshable, LoginPacketListener {
|
||||
|
||||
@Getter private final String featureName = "Yellow Number";
|
||||
@Getter private final String refreshDisplayName = "Updating value";
|
||||
@@ -107,16 +107,6 @@ public class YellowNumber extends TabFeature implements JoinListener, Loadable,
|
||||
if (redis != null) redis.updateYellowNumber(connectedPlayer, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerChange(@NotNull TabPlayer p, @NotNull String from, @NotNull String to) {
|
||||
if (disableChecker.isDisabledPlayer(p) || p.isBedrockPlayer()) return;
|
||||
p.getScoreboard().registerObjective(OBJECTIVE_NAME, TITLE, displayType);
|
||||
p.getScoreboard().setDisplaySlot(Scoreboard.DisplaySlot.PLAYER_LIST, OBJECTIVE_NAME);
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
p.getScoreboard().setScore(OBJECTIVE_NAME, all.getNickname(), getValue(all));
|
||||
}
|
||||
}
|
||||
|
||||
public void onDisableConditionChange(TabPlayer p, boolean disabledNow) {
|
||||
if (disabledNow) {
|
||||
p.getScoreboard().unregisterObjective(OBJECTIVE_NAME);
|
||||
@@ -134,4 +124,14 @@ public class YellowNumber extends TabFeature implements JoinListener, Loadable,
|
||||
}
|
||||
if (redis != null) redis.updateYellowNumber(refreshed, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginPacket(TabPlayer p) {
|
||||
if (disableChecker.isDisabledPlayer(p) || p.isBedrockPlayer() || !p.isLoaded()) return;
|
||||
p.getScoreboard().registerObjective(OBJECTIVE_NAME, TITLE, displayType);
|
||||
p.getScoreboard().setDisplaySlot(Scoreboard.DisplaySlot.PLAYER_LIST, OBJECTIVE_NAME);
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (all.isLoaded()) p.getScoreboard().setScore(OBJECTIVE_NAME, all.getNickname(), getValue(all));
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -102,8 +102,8 @@ public class AlignedPlayerList extends PlayerList implements QuitListener {
|
||||
|
||||
@Override
|
||||
public void onQuit(@NotNull TabPlayer p) {
|
||||
playerViews.values().forEach(v -> v.processPlayerQuit(p));
|
||||
playerViews.remove(p);
|
||||
playerViews.values().forEach(v -> v.processPlayerQuit(p));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -161,7 +161,12 @@ public class BossBarLine implements BossBar {
|
||||
if (value > 100) value = 100;
|
||||
return value;
|
||||
} catch (NumberFormatException e) {
|
||||
TAB.getInstance().getMisconfigurationHelper().invalidNumberForBossBarProgress(name, progress, player.getProperty(propertyProgress).getCurrentRawValue());
|
||||
TAB.getInstance().getMisconfigurationHelper().invalidNumberForBossBarProgress(
|
||||
name,
|
||||
progress,
|
||||
player.getProperty(propertyProgress).getCurrentRawValue(),
|
||||
player
|
||||
);
|
||||
return 100;
|
||||
}
|
||||
}
|
||||
@@ -230,6 +235,10 @@ public class BossBarLine implements BossBar {
|
||||
player.setProperty(progressRefresher, propertyProgress, progress);
|
||||
player.setProperty(colorRefresher, propertyColor, color);
|
||||
player.setProperty(styleRefresher, propertyStyle, style);
|
||||
sendToPlayerRaw(player);
|
||||
}
|
||||
|
||||
public void sendToPlayerRaw(TabPlayer player) {
|
||||
player.getBossBar().create(
|
||||
uniqueId,
|
||||
player.getProperty(propertyTitle).updateAndGet(),
|
||||
|
||||
+14
-1
@@ -2,6 +2,7 @@ package me.neznamy.tab.shared.features.bossbar;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import me.neznamy.tab.shared.ProtocolVersion;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.bossbar.BarColor;
|
||||
import me.neznamy.tab.api.bossbar.BarStyle;
|
||||
@@ -19,7 +20,7 @@ import java.util.stream.Collectors;
|
||||
* Class for handling BossBar feature
|
||||
*/
|
||||
public class BossBarManagerImpl extends TabFeature implements BossBarManager, JoinListener, CommandListener, Loadable,
|
||||
UnLoadable, Refreshable {
|
||||
UnLoadable, Refreshable, LoginPacketListener {
|
||||
|
||||
//default BossBars
|
||||
private final List<String> defaultBars = new ArrayList<>();
|
||||
@@ -255,4 +256,16 @@ public class BossBarManagerImpl extends TabFeature implements BossBarManager, Jo
|
||||
announcedBossBars.remove(line);
|
||||
});
|
||||
}
|
||||
|
||||
@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()) {
|
||||
for (BossBar bar : lineValues) {
|
||||
if (bar.containsPlayer(player)) {
|
||||
((BossBarLine)bar).sendToPlayerRaw(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-9
@@ -16,7 +16,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
* Feature handler for global PlayerList feature
|
||||
*/
|
||||
public class GlobalPlayerList extends TabFeature implements JoinListener, QuitListener, VanishListener, GameModeListener,
|
||||
Loadable, UnLoadable, ServerSwitchListener {
|
||||
Loadable, UnLoadable, ServerSwitchListener, LoginPacketListener {
|
||||
|
||||
// config options
|
||||
private final List<String> spyServers = TAB.getInstance().getConfiguration().getConfig().getStringList("global-playerlist.spy-servers", Collections.singletonList("spyserver1"));
|
||||
@@ -102,14 +102,6 @@ public class GlobalPlayerList extends TabFeature implements JoinListener, QuitLi
|
||||
|
||||
@Override
|
||||
public void onServerChange(@NotNull TabPlayer changed, @NotNull String from, @NotNull String to) {
|
||||
// Event is fired after all entries are removed from switched player's tablist, ready to re-add immediately
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
// Ignore players on the same server, since the server already sends add packet
|
||||
if (!all.getServer().equals(changed.getServer()) && shouldSee(changed, all)) {
|
||||
changed.getTabList().addEntry(getAddInfoData(all, changed));
|
||||
}
|
||||
}
|
||||
|
||||
// Player who switched server is removed from tablist of other players in ~70-110ms (depending on online count), re-add with a delay
|
||||
TAB.getInstance().getCPUManager().runTaskLater(200, featureName, TabConstants.CpuUsageCategory.SERVER_SWITCH, () -> {
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
@@ -125,6 +117,17 @@ public class GlobalPlayerList extends TabFeature implements JoinListener, QuitLi
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginPacket(TabPlayer player) {
|
||||
// Login packet itself does not clear this, but BungeeCord does when the packet is received
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
// Ignore players on the same server, since the server already sends add packet
|
||||
if (!all.getServer().equals(player.getServer()) && shouldSee(player, all)) {
|
||||
player.getTabList().addEntry(getAddInfoData(all, player));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public @NotNull TabList.Entry getAddInfoData(@NotNull TabPlayer p, @NotNull TabPlayer viewer) {
|
||||
IChatBaseComponent format = null;
|
||||
if (playerlist != null && !playerlist.getDisableChecker().isDisabledPlayer(p)) {
|
||||
|
||||
+9
@@ -84,6 +84,8 @@ public abstract class NettyPipelineInjector extends PipelineInjector {
|
||||
|
||||
public abstract void onPlayerInfo(@NotNull TabPlayer receiver, @NotNull Object packet);
|
||||
|
||||
public abstract boolean isLogin(@NotNull Object packet);
|
||||
|
||||
/**
|
||||
* Removes all real players from team if packet does not come from TAB and reports this to override log
|
||||
*
|
||||
@@ -110,6 +112,13 @@ public abstract class NettyPipelineInjector extends PipelineInjector {
|
||||
modifyPlayers(packet);
|
||||
TAB.getInstance().getCPUManager().addTime("NameTags", TabConstants.CpuUsageCategory.ANTI_OVERRIDE, System.nanoTime()-time);
|
||||
}
|
||||
if (isLogin(packet)) {
|
||||
// Logic must be processed after packet is actually sent
|
||||
super.write(context, packet, channelPromise);
|
||||
TAB.getInstance().getCPUManager().runTaskLater(200, getFeatureName(), TabConstants.CpuUsageCategory.PACKET_LOGIN,
|
||||
() -> TAB.getInstance().getFeatureManager().onLoginPacket(player));
|
||||
return;
|
||||
}
|
||||
TAB.getInstance().getFeatureManager().onPacketSend(player, packet);
|
||||
} catch (Throwable e) {
|
||||
TAB.getInstance().getErrorManager().printError("An error occurred when reading packets", e);
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@Getter
|
||||
public class LayoutManagerImpl extends TabFeature implements LayoutManager, JoinListener, QuitListener, VanishListener, Loadable,
|
||||
UnLoadable, Refreshable, ServerSwitchListener {
|
||||
UnLoadable, Refreshable, LoginPacketListener {
|
||||
|
||||
/** Config options */
|
||||
private final Direction direction = parseDirection(TAB.getInstance().getConfig().getString("layout.direction", "COLUMNS"));
|
||||
@@ -181,12 +181,6 @@ public class LayoutManagerImpl extends TabFeature implements LayoutManager, Join
|
||||
views.values().forEach(LayoutView::tick);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerChange(@NotNull TabPlayer changed, @NotNull String from, @NotNull String to) {
|
||||
LayoutView view = views.get(changed);
|
||||
if (view != null) view.send();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Layout createNewLayout(String name) {
|
||||
return new LayoutPattern(this, name, Collections.emptyMap());
|
||||
@@ -204,6 +198,12 @@ public class LayoutManagerImpl extends TabFeature implements LayoutManager, Join
|
||||
refresh((TabPlayer) player, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginPacket(TabPlayer player) {
|
||||
LayoutView view = views.get(player);
|
||||
if (view != null) view.send();
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public enum Direction {
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.*;
|
||||
|
||||
public class NameTag extends TabFeature implements NameTagManager, JoinListener, QuitListener,
|
||||
Loadable, UnLoadable, WorldSwitchListener, ServerSwitchListener, Refreshable {
|
||||
Loadable, UnLoadable, WorldSwitchListener, ServerSwitchListener, Refreshable, LoginPacketListener {
|
||||
|
||||
@Getter private final String featureName = "NameTags";
|
||||
@Getter private final String refreshDisplayName = "Updating prefix/suffix";
|
||||
@@ -100,7 +100,6 @@ public class NameTag extends TabFeature implements NameTagManager, JoinListener,
|
||||
|
||||
@Override
|
||||
public void onJoin(@NotNull TabPlayer connectedPlayer) {
|
||||
sorting.constructTeamNames(connectedPlayer);
|
||||
updateProperties(connectedPlayer);
|
||||
hiddenNameTagFor.put(connectedPlayer, new ArrayList<>());
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
@@ -135,9 +134,6 @@ public class NameTag extends TabFeature implements NameTagManager, JoinListener,
|
||||
@Override
|
||||
public void onServerChange(@NonNull TabPlayer p, @NonNull String from, @NonNull String to) {
|
||||
if (updateProperties(p) && !disableChecker.isDisabledPlayer(p)) updateTeamData(p);
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (!disableChecker.isDisabledPlayer(all)) registerTeam(all, p);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -341,4 +337,12 @@ public class NameTag extends TabFeature implements NameTagManager, JoinListener,
|
||||
public boolean hasHiddenNameTagVisibilityView(@NonNull me.neznamy.tab.api.TabPlayer player) {
|
||||
return playersWithInvisibleNameTagView.contains(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginPacket(TabPlayer player) {
|
||||
if (!player.isLoaded()) return;
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (!disableChecker.isDisabledPlayer(all) && all.isLoaded()) registerTeam(all, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ import java.util.function.Supplier;
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
@Getter
|
||||
public abstract class RedisSupport extends TabFeature implements JoinListener, QuitListener,
|
||||
DisplayNameListener, Loadable, UnLoadable, ServerSwitchListener {
|
||||
DisplayNameListener, Loadable, UnLoadable, ServerSwitchListener, LoginPacketListener {
|
||||
|
||||
@NotNull private final String featureName = "RedisSupport";
|
||||
|
||||
@@ -207,4 +207,9 @@ public abstract class RedisSupport extends TabFeature implements JoinListener, Q
|
||||
messages.put(name, supplier);
|
||||
classStringMap.put(clazz, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginPacket(TabPlayer player) {
|
||||
features.forEach(f -> f.onLoginPacket(player));
|
||||
}
|
||||
}
|
||||
+5
-15
@@ -42,21 +42,6 @@ public class RedisBelowName extends RedisFeature {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerSwitch(@NotNull TabPlayer player) {
|
||||
onJoin(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerSwitch(@NotNull RedisPlayer player) {
|
||||
// No action is needed
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQuit(@NotNull RedisPlayer player) {
|
||||
// No action is needed
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull ByteArrayDataOutput out, @NotNull TabPlayer player) {
|
||||
out.writeInt(TAB.getInstance().getErrorManager().parseInteger(
|
||||
@@ -68,6 +53,11 @@ public class RedisBelowName extends RedisFeature {
|
||||
values.put(player, in.readInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginPacket(@NotNull TabPlayer player) {
|
||||
onJoin(player);
|
||||
}
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Update extends RedisMessage {
|
||||
|
||||
@@ -12,13 +12,15 @@ public abstract class RedisFeature {
|
||||
|
||||
public abstract void onJoin(@NotNull RedisPlayer player);
|
||||
|
||||
public abstract void onServerSwitch(@NotNull TabPlayer player);
|
||||
public void onServerSwitch(@NotNull TabPlayer player) {/* Do nothing by default */}
|
||||
|
||||
public abstract void onServerSwitch(@NotNull RedisPlayer player);
|
||||
public void onServerSwitch(@NotNull RedisPlayer player) {/* Do nothing by default */}
|
||||
|
||||
public abstract void onQuit(@NotNull RedisPlayer player);
|
||||
public void onQuit(@NotNull RedisPlayer player) {/* Do nothing by default */}
|
||||
|
||||
public abstract void write(@NotNull ByteArrayDataOutput out, @NotNull TabPlayer player);
|
||||
|
||||
public abstract void read(@NotNull ByteArrayDataInput in, @NotNull RedisPlayer player);
|
||||
|
||||
public void onLoginPacket(@NotNull TabPlayer player) {/* Do nothing by default */}
|
||||
}
|
||||
+5
-5
@@ -41,11 +41,6 @@ public class RedisGlobalPlayerList extends RedisFeature {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerSwitch(@NotNull TabPlayer player) {
|
||||
onJoin(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerSwitch(@NotNull RedisPlayer player) {
|
||||
TAB.getInstance().getCPUManager().runTaskLater(200, redisSupport.getFeatureName(), TabConstants.CpuUsageCategory.SERVER_SWITCH, () -> {
|
||||
@@ -93,6 +88,11 @@ public class RedisGlobalPlayerList extends RedisFeature {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginPacket(@NotNull TabPlayer player) {
|
||||
onJoin(player);
|
||||
}
|
||||
|
||||
private boolean shouldSee(@NotNull TabPlayer viewer, @NotNull RedisPlayer target) {
|
||||
if (target.isVanished() && !viewer.hasPermission(TabConstants.Permission.SEE_VANISHED)) return false;
|
||||
if (globalPlayerList.isSpyServer(viewer.getServer())) return true;
|
||||
|
||||
-10
@@ -50,16 +50,6 @@ public class RedisPlayerList extends RedisFeature {
|
||||
onJoin(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerSwitch(@NotNull RedisPlayer player) {
|
||||
// No action is needed
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQuit(@NotNull RedisPlayer player) {
|
||||
// No action is needed
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull ByteArrayDataOutput out, @NotNull TabPlayer player) {
|
||||
out.writeUTF(player.getProperty(TabConstants.Property.TABPREFIX).get() +
|
||||
|
||||
@@ -52,16 +52,6 @@ public class RedisTeams extends RedisFeature {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerSwitch(@NotNull TabPlayer player) {
|
||||
onJoin(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerSwitch(@NotNull RedisPlayer player) {
|
||||
// No action is needed
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQuit(@NotNull RedisPlayer player) {
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
@@ -87,6 +77,11 @@ public class RedisTeams extends RedisFeature {
|
||||
nameVisibilities.put(player, NameVisibility.getByName(in.readUTF()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginPacket(@NotNull TabPlayer player) {
|
||||
onJoin(player);
|
||||
}
|
||||
|
||||
private @NotNull String checkTeamName(@NotNull RedisPlayer player, @NotNull String currentName15, int id) {
|
||||
String potentialTeamName = currentName15 + (char)id;
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
|
||||
+5
-15
@@ -42,21 +42,6 @@ public class RedisYellowNumber extends RedisFeature {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerSwitch(@NotNull TabPlayer player) {
|
||||
onJoin(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerSwitch(@NotNull RedisPlayer player) {
|
||||
// No action is needed
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQuit(@NotNull RedisPlayer player) {
|
||||
// No action is needed
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull ByteArrayDataOutput out, @NotNull TabPlayer player) {
|
||||
out.writeInt(TAB.getInstance().getErrorManager().parseInteger(
|
||||
@@ -68,6 +53,11 @@ public class RedisYellowNumber extends RedisFeature {
|
||||
values.put(player, in.readInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginPacket(@NotNull TabPlayer player) {
|
||||
onJoin(player);
|
||||
}
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Update extends RedisMessage {
|
||||
|
||||
+15
-6
@@ -19,7 +19,7 @@ import java.util.Map.Entry;
|
||||
*/
|
||||
public class ScoreboardManagerImpl extends TabFeature implements ScoreboardManager, JoinListener,
|
||||
CommandListener, DisplayObjectiveListener, ObjectiveListener, Loadable, UnLoadable, Refreshable,
|
||||
ServerSwitchListener {
|
||||
QuitListener, LoginPacketListener {
|
||||
|
||||
public static final String OBJECTIVE_NAME = "TAB-Scoreboard";
|
||||
|
||||
@@ -306,12 +306,21 @@ public class ScoreboardManagerImpl extends TabFeature implements ScoreboardManag
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerChange(@NotNull TabPlayer changed, @NotNull String from, @NotNull String to) {
|
||||
otherPluginScoreboards.remove(changed);
|
||||
ScoreboardImpl scoreboard = activeScoreboards.get(changed);
|
||||
public void onQuit(@NotNull TabPlayer disconnectedPlayer) {
|
||||
ScoreboardImpl sb = activeScoreboards.get(disconnectedPlayer);
|
||||
if (sb != null) {
|
||||
sb.removePlayerFromSet(disconnectedPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginPacket(TabPlayer player) {
|
||||
if (!player.isLoaded()) return;
|
||||
otherPluginScoreboards.remove(player);
|
||||
ScoreboardImpl scoreboard = activeScoreboards.get(player);
|
||||
if (scoreboard != null) {
|
||||
scoreboard.removePlayerFromSet(changed);
|
||||
scoreboard.addPlayer(changed);
|
||||
scoreboard.removePlayerFromSet(player);
|
||||
scoreboard.addPlayer(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ import java.util.function.BiConsumer;
|
||||
public class DisableChecker extends TabFeature implements Refreshable {
|
||||
|
||||
@Getter private final String featureName;
|
||||
@Getter private final String refreshDisplayName = "Updating display condition";
|
||||
@Getter private final String refreshDisplayName = "Refreshing disable condition";
|
||||
private final @Nullable Condition disableCondition;
|
||||
private final BiConsumer<TabPlayer, Boolean> action;
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package me.neznamy.tab.shared.features.types;
|
||||
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
|
||||
/**
|
||||
* Interface for features that resend content on Login packet.
|
||||
*/
|
||||
public interface LoginPacketListener {
|
||||
|
||||
/**
|
||||
* Called after Login packet is received by the player to resend all
|
||||
* scoreboard content as the packet has cleared it.
|
||||
*
|
||||
* @param player
|
||||
* Player who received the packet
|
||||
*/
|
||||
void onLoginPacket(TabPlayer player);
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import me.neznamy.tab.shared.chat.ChatModifier;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -29,9 +30,9 @@ public class AdventureHook {
|
||||
net.kyori.adventure.text.format.TextColor color = null;
|
||||
if (modifier.getColor() != null) {
|
||||
if (clientVersion.getMinorVersion() >= 16) {
|
||||
color = net.kyori.adventure.text.format.TextColor.color(modifier.getColor().getRgb());
|
||||
color = TextColor.color(modifier.getColor().getRgb());
|
||||
} else {
|
||||
color = net.kyori.adventure.text.format.TextColor.color(modifier.getColor().getLegacyColor().getHexCode());
|
||||
color = TextColor.color(modifier.getColor().getLegacyColor().getHexCode());
|
||||
}
|
||||
}
|
||||
Set<TextDecoration> decorations = new HashSet<>();
|
||||
@@ -40,8 +41,9 @@ public class AdventureHook {
|
||||
if (modifier.isObfuscated()) decorations.add(TextDecoration.OBFUSCATED);
|
||||
if (modifier.isStrikethrough()) decorations.add(TextDecoration.STRIKETHROUGH);
|
||||
if (modifier.isUnderlined()) decorations.add(TextDecoration.UNDERLINED);
|
||||
Component advComponent = Component.text(component.getText(), color, decorations);
|
||||
if (modifier.getFont() != null) advComponent = advComponent.font(Key.key(modifier.getFont()));
|
||||
return advComponent.children(component.getExtra().stream().map(c -> toAdventureComponent(c, clientVersion)).collect(Collectors.toList()));
|
||||
Key font = modifier.getFont() == null ? null : Key.key(modifier.getFont());
|
||||
return Component.text(component.getText(), color, decorations)
|
||||
.font(font)
|
||||
.children(component.getExtra().stream().map(c -> toAdventureComponent(c, clientVersion)).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
@@ -42,8 +42,11 @@ public class ViaVersionHook {
|
||||
}
|
||||
ProtocolVersion protocol = ProtocolVersion.fromNetworkId(version);
|
||||
if (protocol == ProtocolVersion.UNKNOWN_CLIENT_VERSION) {
|
||||
TAB.getInstance().getPlatform().logWarn(new IChatBaseComponent("ViaVersion returned unknown protocol version " + version +
|
||||
" for player " + playerName + ". This may result in plugin not working correctly for them."));
|
||||
TAB.getInstance().getPlatform().logWarn(new IChatBaseComponent(String.format(
|
||||
"ViaVersion returned unknown protocol version %d for player %s. " +
|
||||
"Latest version recognized by this plugin version is %d (%s). " +
|
||||
"Did a new MC version come out without you updating the plugin? This may result in plugin not working correctly for them.",
|
||||
version, playerName, ProtocolVersion.LATEST_KNOWN_VERSION.getNetworkId(), ProtocolVersion.LATEST_KNOWN_VERSION.getFriendlyName())));
|
||||
} else {
|
||||
TAB.getInstance().debug("ViaVersion returned protocol version " + version + " for " + playerName);
|
||||
}
|
||||
|
||||
@@ -59,14 +59,16 @@ public abstract class EventListener<T> {
|
||||
* UUID of the player
|
||||
* @param server
|
||||
* New server
|
||||
* @param callOnLoginPacket
|
||||
* Whether onLoginPacket method should be called as well or not
|
||||
*/
|
||||
public void serverChange(@NotNull T player, @NotNull UUID uuid, @NotNull String server) {
|
||||
public void serverChange(@NotNull T player, @NotNull UUID uuid, @NotNull String server, boolean callOnLoginPacket) {
|
||||
if (TAB.getInstance().isPluginDisabled()) return;
|
||||
TAB.getInstance().getCPUManager().runTask(() -> {
|
||||
if (TAB.getInstance().getPlayer(uuid) == null) {
|
||||
TAB.getInstance().getFeatureManager().onJoin(createPlayer(player));
|
||||
} else {
|
||||
TAB.getInstance().getFeatureManager().onServerChange(uuid, server);
|
||||
TAB.getInstance().getFeatureManager().onServerChange(uuid, server, callOnLoginPacket);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -82,7 +84,7 @@ public abstract class EventListener<T> {
|
||||
public void pluginMessage(@NotNull UUID player, byte[] message) {
|
||||
TAB.getInstance().getCPUManager().runMeasuredTask("Plugin message handling",
|
||||
TabConstants.CpuUsageCategory.PLUGIN_MESSAGE, () ->
|
||||
((ProxyPlatform<?>)TAB.getInstance().getPlatform()).getPluginMessageHandler().onPluginMessage(player, message));
|
||||
((ProxyPlatform)TAB.getInstance().getPlatform()).getPluginMessageHandler().onPluginMessage(player, message));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,7 @@ import java.io.File;
|
||||
* An interface with methods that are called in universal code,
|
||||
* but require platform-specific API calls
|
||||
*/
|
||||
public interface Platform<T> {
|
||||
public interface Platform {
|
||||
|
||||
/**
|
||||
* Detects permission plugin and returns its representing object
|
||||
@@ -144,15 +144,4 @@ public interface Platform<T> {
|
||||
* @return plugin's data folder
|
||||
*/
|
||||
File getDataFolder();
|
||||
|
||||
/**
|
||||
* Converts internal component class to platform's component class
|
||||
*
|
||||
* @param component
|
||||
* Component to convert
|
||||
* @param version
|
||||
* Game version to convert component for
|
||||
* @return Converted component
|
||||
*/
|
||||
T toComponent(@NotNull IChatBaseComponent component, @NotNull ProtocolVersion version);
|
||||
}
|
||||
@@ -90,7 +90,7 @@ public abstract class Scoreboard<T extends TabPlayer> {
|
||||
}
|
||||
|
||||
private void error(@NotNull String format, @NotNull Object... args) {
|
||||
TAB.getInstance().getErrorManager().printError(String.format(format, args) + player.getName());
|
||||
TAB.getInstance().debug(String.format(format, args) + player.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.*;
|
||||
public abstract class TabPlayer implements me.neznamy.tab.api.TabPlayer {
|
||||
|
||||
/** Platform reference */
|
||||
protected final Platform<?> platform;
|
||||
protected final Platform platform;
|
||||
|
||||
/** Platform-specific player object instance */
|
||||
@Setter protected Object player;
|
||||
@@ -86,7 +86,7 @@ public abstract class TabPlayer implements me.neznamy.tab.api.TabPlayer {
|
||||
* @param useRealId
|
||||
* Whether tablist uses real uuid or offline
|
||||
*/
|
||||
protected TabPlayer(@NotNull Platform<?> platform, @NotNull Object player, @NotNull UUID uniqueId, @NotNull String name,
|
||||
protected TabPlayer(@NotNull Platform platform, @NotNull Object player, @NotNull UUID uniqueId, @NotNull String name,
|
||||
@NotNull String server, @NotNull String world, int protocolVersion, boolean useRealId) {
|
||||
this.platform = platform;
|
||||
this.player = player;
|
||||
@@ -345,5 +345,5 @@ public abstract class TabPlayer implements me.neznamy.tab.api.TabPlayer {
|
||||
*
|
||||
* @return Server platform
|
||||
*/
|
||||
public abstract Platform<?> getPlatform();
|
||||
public abstract Platform getPlatform();
|
||||
}
|
||||
@@ -10,23 +10,44 @@ import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.hook.AdventureHook;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.bossbar.BossBar.Color;
|
||||
import net.kyori.adventure.bossbar.BossBar.Overlay;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class AdventureBossBar implements BossBar {
|
||||
|
||||
/** Color array for fast access */
|
||||
private static final Color[] colors = new Color[] {
|
||||
Color.PINK,
|
||||
Color.BLUE,
|
||||
Color.RED,
|
||||
Color.GREEN,
|
||||
Color.YELLOW,
|
||||
Color.PURPLE,
|
||||
Color.WHITE
|
||||
};
|
||||
|
||||
/** Overlay array for fast access */
|
||||
private static final Overlay[] overlays = new Overlay[] {
|
||||
Overlay.PROGRESS,
|
||||
Overlay.NOTCHED_6,
|
||||
Overlay.NOTCHED_10,
|
||||
Overlay.NOTCHED_12,
|
||||
Overlay.NOTCHED_20
|
||||
};
|
||||
|
||||
private final TabPlayer player;
|
||||
|
||||
private final Map<UUID, net.kyori.adventure.bossbar.BossBar> bossBars = new LinkedHashMap<>();
|
||||
|
||||
@Override
|
||||
public void create(@NotNull UUID id, @NotNull String title, float progress, @NotNull BarColor color, @NotNull BarStyle style) {
|
||||
if (bossBars.containsKey(id)) return;
|
||||
net.kyori.adventure.bossbar.BossBar bar = net.kyori.adventure.bossbar.BossBar.bossBar(
|
||||
AdventureHook.toAdventureComponent(IChatBaseComponent.optimizedComponent(title), player.getVersion()),
|
||||
progress,
|
||||
net.kyori.adventure.bossbar.BossBar.Color.valueOf(color.toString()),
|
||||
net.kyori.adventure.bossbar.BossBar.Overlay.valueOf(style.toString())
|
||||
colors[color.ordinal()],
|
||||
overlays[style.ordinal()]
|
||||
);
|
||||
bossBars.put(id, bar);
|
||||
((Audience)player.getPlayer()).showBossBar(bar);
|
||||
@@ -44,12 +65,12 @@ public class AdventureBossBar implements BossBar {
|
||||
|
||||
@Override
|
||||
public void update(@NotNull UUID id, @NotNull BarStyle style) {
|
||||
bossBars.get(id).overlay(net.kyori.adventure.bossbar.BossBar.Overlay.valueOf(style.toString()));
|
||||
bossBars.get(id).overlay(overlays[style.ordinal()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull UUID id, @NotNull BarColor color) {
|
||||
bossBars.get(id).color(net.kyori.adventure.bossbar.BossBar.Color.valueOf(color.toString()));
|
||||
bossBars.get(id).color(colors[color.ordinal()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -56,7 +56,7 @@ public class PluginMessageHandler {
|
||||
|
||||
public void placeholder(@NotNull ProxyTabPlayer player, @NotNull ByteArrayDataInput in) {
|
||||
String identifier = in.readUTF();
|
||||
if (!TAB.getInstance().getPlaceholderManager().getRegisteredPlaceholders().containsKey(identifier)) return;
|
||||
if (!TAB.getInstance().getPlaceholderManager().isPlaceholderRegistered(identifier)) return;
|
||||
Placeholder placeholder = TAB.getInstance().getPlaceholderManager().getPlaceholder(identifier);
|
||||
if (placeholder instanceof RelationalPlaceholder) {
|
||||
TabPlayer other = TAB.getInstance().getPlayer(in.readUTF());
|
||||
@@ -100,6 +100,7 @@ public class PluginMessageHandler {
|
||||
}
|
||||
|
||||
public void playerJoinResponse(@NotNull ProxyTabPlayer player, @NotNull ByteArrayDataInput in) {
|
||||
TAB.getInstance().debug("Bridge took " + (System.currentTimeMillis()-player.getBridgeRequestTime()) + "ms to respond to join message of " + player.getName());
|
||||
TAB.getInstance().getFeatureManager().onWorldChange(player.getUniqueId(), in.readUTF());
|
||||
if (TAB.getInstance().getGroupManager().getPermissionPlugin().contains("Vault") &&
|
||||
!TAB.getInstance().getGroupManager().isGroupsByPermissions()) player.setGroup(in.readUTF());
|
||||
@@ -110,22 +111,25 @@ public class PluginMessageHandler {
|
||||
int placeholderCount = in.readInt();
|
||||
for (int i=0; i<placeholderCount; i++) {
|
||||
String identifier = in.readUTF();
|
||||
boolean registered = TAB.getInstance().getPlaceholderManager().isPlaceholderRegistered(identifier);
|
||||
if (identifier.startsWith("%rel_")) {
|
||||
int playerCount = in.readInt();
|
||||
for (int j=0; j<playerCount; j++) {
|
||||
TabPlayer other = TAB.getInstance().getPlayer(in.readUTF());
|
||||
String value = in.readUTF();
|
||||
if (other != null) { // Backend player did not connect via this proxy if null
|
||||
if (registered && other != null) { // Backend player did not connect via this proxy if null
|
||||
((RelationalPlaceholder)TAB.getInstance().getPlaceholderManager().getPlaceholder(identifier))
|
||||
.updateValue(player, other, value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String value = in.readUTF();
|
||||
if (!registered) continue;
|
||||
Placeholder pl = TAB.getInstance().getPlaceholderManager().getPlaceholder(identifier);
|
||||
if (pl instanceof PlayerPlaceholder) {
|
||||
((PlayerPlaceholder) pl).updateValue(player, in.readUTF());
|
||||
((PlayerPlaceholder) pl).updateValue(player, value);
|
||||
} else {
|
||||
((ServerPlaceholder) pl).updateValue(in.readUTF());
|
||||
((ServerPlaceholder) pl).updateValue(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* Abstract class containing common variables and methods
|
||||
* shared between proxies.
|
||||
*/
|
||||
public abstract class ProxyPlatform<T> implements Platform<T> {
|
||||
public abstract class ProxyPlatform implements Platform {
|
||||
|
||||
/** Plugin message handler for sending and receiving plugin messages */
|
||||
@Getter protected final PluginMessageHandler pluginMessageHandler = new PluginMessageHandler();
|
||||
|
||||
@@ -37,6 +37,9 @@ public abstract class ProxyTabPlayer extends TabPlayer {
|
||||
/** Player's boat vehicle status for unlimited NameTags */
|
||||
private boolean onBoat;
|
||||
|
||||
/** Timestamp when join plugin message was sent to track how long bridge took to respond */
|
||||
private long bridgeRequestTime;
|
||||
|
||||
/** Flag for marking if this player has received join response from bridge or not */
|
||||
private boolean bridgeConnected;
|
||||
|
||||
@@ -63,7 +66,7 @@ public abstract class ProxyTabPlayer extends TabPlayer {
|
||||
* @param protocolVersion
|
||||
* Player's protocol network id
|
||||
*/
|
||||
protected ProxyTabPlayer(@NotNull ProxyPlatform<?> platform, @NotNull Object player, @NotNull UUID uniqueId,
|
||||
protected ProxyTabPlayer(@NotNull ProxyPlatform platform, @NotNull Object player, @NotNull UUID uniqueId,
|
||||
@NotNull String name, @NotNull String server, int protocolVersion) {
|
||||
super(platform, player, uniqueId, name, server, "N/A", protocolVersion, TAB.getInstance().getConfiguration().isOnlineUuidInTabList());
|
||||
sendJoinPluginMessage();
|
||||
@@ -82,7 +85,7 @@ public abstract class ProxyTabPlayer extends TabPlayer {
|
||||
TAB.getInstance().getGroupManager().getPermissionPlugin().contains("Vault") &&
|
||||
!TAB.getInstance().getGroupManager().isGroupsByPermissions(),
|
||||
true);
|
||||
Map<String, Integer> placeholders = ((ProxyPlatform<?>) getPlatform()).getBridgePlaceholders();
|
||||
Map<String, Integer> placeholders = ((ProxyPlatform) getPlatform()).getBridgePlaceholders();
|
||||
args.add(placeholders.size());
|
||||
for (Map.Entry<String, Integer> entry : placeholders.entrySet()) {
|
||||
args.add(entry.getKey());
|
||||
@@ -115,6 +118,7 @@ public abstract class ProxyTabPlayer extends TabPlayer {
|
||||
}
|
||||
sendPluginMessage(args.toArray());
|
||||
if (expansion instanceof ProxyTabExpansion) ((ProxyTabExpansion) expansion).resendAllValues(this);
|
||||
bridgeRequestTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -108,7 +108,7 @@ scoreboard:
|
||||
scoreboards:
|
||||
admin:
|
||||
# Only players with tab.scoreboard.admin can see this scoreboard, others will see scoreboard1
|
||||
display-condition: "permission:tab.scoreboard.admin;%server%!=N/A"
|
||||
display-condition: "permission:tab.scoreboard.admin"
|
||||
title: "Admin scoreboard"
|
||||
lines:
|
||||
- "%animation:MyAnimation1%"
|
||||
@@ -118,7 +118,6 @@ scoreboard:
|
||||
- "* &eStaff&7: &f%staffonline%"
|
||||
- " "
|
||||
- "&6Server Info:"
|
||||
- "* &bTPS&7: %tps%"
|
||||
- "* &bMemory&7: &f%memory-used%&7/&4%memory-max%"
|
||||
- "%animation:MyAnimation1%"
|
||||
scoreboard1:
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package me.neznamy.tab.platforms.sponge7;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.platform.bossbar.BossBar;
|
||||
import me.neznamy.tab.api.bossbar.BarColor;
|
||||
import me.neznamy.tab.api.bossbar.BarStyle;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.spongepowered.api.boss.*;
|
||||
import org.spongepowered.api.text.Text;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -17,12 +17,22 @@ public class SpongeBossBar implements BossBar {
|
||||
|
||||
/** Color array for fast access */
|
||||
private static final BossBarColor[] colors = new BossBarColor[] {
|
||||
BossBarColors.PINK, BossBarColors.BLUE, BossBarColors.RED, BossBarColors.GREEN, BossBarColors.YELLOW, BossBarColors.PURPLE, BossBarColors.WHITE
|
||||
BossBarColors.PINK,
|
||||
BossBarColors.BLUE,
|
||||
BossBarColors.RED,
|
||||
BossBarColors.GREEN,
|
||||
BossBarColors.YELLOW,
|
||||
BossBarColors.PURPLE,
|
||||
BossBarColors.WHITE
|
||||
};
|
||||
|
||||
/** Style array for fast access */
|
||||
private static final BossBarOverlay[] styles = new BossBarOverlay[] {
|
||||
BossBarOverlays.PROGRESS, BossBarOverlays.NOTCHED_6, BossBarOverlays.NOTCHED_10, BossBarOverlays.NOTCHED_12, BossBarOverlays.NOTCHED_20
|
||||
BossBarOverlays.PROGRESS,
|
||||
BossBarOverlays.NOTCHED_6,
|
||||
BossBarOverlays.NOTCHED_10,
|
||||
BossBarOverlays.NOTCHED_12,
|
||||
BossBarOverlays.NOTCHED_20
|
||||
};
|
||||
|
||||
/** Player to send boss bars to */
|
||||
@@ -35,7 +45,7 @@ public class SpongeBossBar implements BossBar {
|
||||
@Override
|
||||
public void create(@NotNull UUID id, @NotNull String title, float progress, @NotNull BarColor color, @NotNull BarStyle style) {
|
||||
ServerBossBar bar = ServerBossBar.builder()
|
||||
.name(player.getPlatform().toComponent(IChatBaseComponent.optimizedComponent(title), player.getVersion()))
|
||||
.name(Text.of(title))
|
||||
.color(colors[color.ordinal()])
|
||||
.overlay(styles[style.ordinal()])
|
||||
.percent(progress)
|
||||
@@ -46,7 +56,7 @@ public class SpongeBossBar implements BossBar {
|
||||
|
||||
@Override
|
||||
public void update(@NotNull UUID id, @NotNull String title) {
|
||||
bossBars.get(id).setName(player.getPlatform().toComponent(IChatBaseComponent.optimizedComponent(title), player.getVersion()));
|
||||
bossBars.get(id).setName(Text.of(title));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,7 +26,7 @@ import java.io.File;
|
||||
* Platform implementation for Sponge 7 and lower
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class SpongePlatform implements BackendPlatform<Text> {
|
||||
public class SpongePlatform implements BackendPlatform {
|
||||
|
||||
/** Plugin reference */
|
||||
@NotNull
|
||||
@@ -115,11 +115,6 @@ public class SpongePlatform implements BackendPlatform<Text> {
|
||||
return plugin.getConfigDir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Text toComponent(@NotNull IChatBaseComponent component, @NotNull ProtocolVersion version) {
|
||||
return Text.of(component.toLegacyText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTPS() {
|
||||
return Sponge.getServer().getTicksPerSecond();
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.spongepowered.api.scoreboard.*;
|
||||
import org.spongepowered.api.scoreboard.critieria.Criteria;
|
||||
import org.spongepowered.api.scoreboard.displayslot.DisplaySlots;
|
||||
import org.spongepowered.api.scoreboard.objective.Objective;
|
||||
import org.spongepowered.api.scoreboard.objective.displaymode.ObjectiveDisplayMode;
|
||||
import org.spongepowered.api.scoreboard.objective.displaymode.ObjectiveDisplayModes;
|
||||
import org.spongepowered.api.text.Text;
|
||||
|
||||
@@ -15,17 +16,31 @@ public class SpongeScoreboard extends Scoreboard<SpongeTabPlayer> {
|
||||
|
||||
/** Collision rule array for fast access */
|
||||
private static final org.spongepowered.api.scoreboard.CollisionRule[] collisionRules = new org.spongepowered.api.scoreboard.CollisionRule[]{
|
||||
CollisionRules.ALWAYS, CollisionRules.NEVER, CollisionRules.PUSH_OTHER_TEAMS, CollisionRules.PUSH_OWN_TEAM
|
||||
CollisionRules.ALWAYS,
|
||||
CollisionRules.NEVER,
|
||||
CollisionRules.PUSH_OTHER_TEAMS,
|
||||
CollisionRules.PUSH_OWN_TEAM
|
||||
};
|
||||
|
||||
/** Visibility array for fast access */
|
||||
private static final Visibility[] visibilities = new Visibility[] {
|
||||
Visibilities.ALWAYS, Visibilities.NEVER, Visibilities.HIDE_FOR_OTHER_TEAMS, Visibilities.HIDE_FOR_OWN_TEAM
|
||||
Visibilities.ALWAYS,
|
||||
Visibilities.NEVER,
|
||||
Visibilities.HIDE_FOR_OTHER_TEAMS,
|
||||
Visibilities.HIDE_FOR_OWN_TEAM
|
||||
};
|
||||
|
||||
/** DisplaySlot array for fast access */
|
||||
private static final org.spongepowered.api.scoreboard.displayslot.DisplaySlot[] displaySlots = new org.spongepowered.api.scoreboard.displayslot.DisplaySlot[] {
|
||||
DisplaySlots.LIST, DisplaySlots.SIDEBAR, DisplaySlots.BELOW_NAME
|
||||
DisplaySlots.LIST,
|
||||
DisplaySlots.SIDEBAR,
|
||||
DisplaySlots.BELOW_NAME
|
||||
};
|
||||
|
||||
/** Health display array for fast access */
|
||||
private static final ObjectiveDisplayMode[] healthDisplays = new ObjectiveDisplayMode[] {
|
||||
ObjectiveDisplayModes.INTEGER,
|
||||
ObjectiveDisplayModes.HEARTS
|
||||
};
|
||||
|
||||
/** Scoreboard of the player */
|
||||
@@ -34,7 +49,8 @@ public class SpongeScoreboard extends Scoreboard<SpongeTabPlayer> {
|
||||
|
||||
public SpongeScoreboard(@NotNull SpongeTabPlayer player) {
|
||||
super(player);
|
||||
// Make sure each player is in different scoreboard for per-player view
|
||||
|
||||
// Make sure each player is in a different scoreboard for per-player view
|
||||
player.getPlayer().setScoreboard(sb);
|
||||
}
|
||||
|
||||
@@ -48,9 +64,10 @@ public class SpongeScoreboard extends Scoreboard<SpongeTabPlayer> {
|
||||
sb.addObjective(Objective.builder()
|
||||
.name(objectiveName)
|
||||
.displayName(Text.of(title))
|
||||
.objectiveDisplayMode(display == HealthDisplay.HEARTS ? ObjectiveDisplayModes.HEARTS : ObjectiveDisplayModes.INTEGER)
|
||||
.objectiveDisplayMode(healthDisplays[display.ordinal()])
|
||||
.criterion(Criteria.DUMMY)
|
||||
.build());
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,7 +79,7 @@ public class SpongeScoreboard extends Scoreboard<SpongeTabPlayer> {
|
||||
public void updateObjective0(@NotNull String objectiveName, @NotNull String title, @NotNull HealthDisplay display) {
|
||||
sb.getObjective(objectiveName).ifPresent(obj -> {
|
||||
obj.setDisplayName(Text.of(title));
|
||||
obj.setDisplayMode(display == HealthDisplay.HEARTS ? ObjectiveDisplayModes.HEARTS : ObjectiveDisplayModes.INTEGER);
|
||||
obj.setDisplayMode(healthDisplays[display.ordinal()]);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ public class SpongeTabList implements TabList {
|
||||
@Override
|
||||
public void updateDisplayName(@NotNull UUID entry, @Nullable IChatBaseComponent displayName) {
|
||||
player.getPlayer().getTabList().getEntry(entry).ifPresent(e -> {
|
||||
Text component = displayName == null ? null : player.getPlatform().toComponent(displayName, player.getVersion());
|
||||
Text component = displayName == null ? null : Text.of(displayName.toLegacyText());
|
||||
e.setDisplayName(component);
|
||||
expectedDisplayNames.put(e, component);
|
||||
});
|
||||
@@ -60,7 +60,7 @@ public class SpongeTabList implements TabList {
|
||||
|
||||
@Override
|
||||
public void addEntry(@NotNull Entry entry) {
|
||||
Text displayName = entry.getDisplayName() == null ? null : player.getPlatform().toComponent(entry.getDisplayName(), player.getVersion());
|
||||
Text displayName = entry.getDisplayName() == null ? null : Text.of(entry.getDisplayName().toLegacyText());
|
||||
GameProfile profile = GameProfile.of(entry.getUniqueId(), entry.getName());
|
||||
if (entry.getSkin() != null) profile.getPropertyMap().put(TEXTURES_PROPERTY, ProfileProperty.of(
|
||||
TEXTURES_PROPERTY, entry.getSkin().getValue(), entry.getSkin().getSignature()));
|
||||
@@ -78,8 +78,8 @@ public class SpongeTabList implements TabList {
|
||||
@Override
|
||||
public void setPlayerListHeaderFooter(@NotNull IChatBaseComponent header, @NotNull IChatBaseComponent footer) {
|
||||
player.getPlayer().getTabList().setHeaderAndFooter(
|
||||
player.getPlatform().toComponent(header, player.getVersion()),
|
||||
player.getPlatform().toComponent(footer, player.getVersion())
|
||||
Text.of(header.toLegacyText()),
|
||||
Text.of(footer.toLegacyText())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import java.io.File;
|
||||
* Platform implementation for Sponge 8 and up
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class SpongePlatform implements BackendPlatform<Component> {
|
||||
public class SpongePlatform implements BackendPlatform {
|
||||
|
||||
/** Main class reference */
|
||||
@NotNull
|
||||
@@ -71,13 +71,13 @@ public class SpongePlatform implements BackendPlatform<Component> {
|
||||
@Override
|
||||
public void logInfo(@NotNull IChatBaseComponent message) {
|
||||
Sponge.systemSubject().sendMessage(Component.text("[TAB] ").append(
|
||||
toComponent(message, TAB.getInstance().getServerVersion())));
|
||||
AdventureHook.toAdventureComponent(message, TAB.getInstance().getServerVersion())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logWarn(@NotNull IChatBaseComponent message) {
|
||||
Sponge.systemSubject().sendMessage(Component.text("[TAB] [WARN] ").append(
|
||||
toComponent(message, TAB.getInstance().getServerVersion()))); // Sponge console does not support colors
|
||||
AdventureHook.toAdventureComponent(message, TAB.getInstance().getServerVersion()))); // Sponge console does not support colors
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -116,11 +116,6 @@ public class SpongePlatform implements BackendPlatform<Component> {
|
||||
return plugin.getConfigDir().toFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component toComponent(@NotNull IChatBaseComponent component, @NotNull ProtocolVersion version) {
|
||||
return AdventureHook.toAdventureComponent(component, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTPS() {
|
||||
return Sponge.server().ticksPerSecond();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package me.neznamy.tab.platforms.sponge8;
|
||||
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.hook.AdventureHook;
|
||||
import me.neznamy.tab.shared.platform.Scoreboard;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -11,6 +12,7 @@ import org.spongepowered.api.scoreboard.Visibility;
|
||||
import org.spongepowered.api.scoreboard.criteria.Criteria;
|
||||
import org.spongepowered.api.scoreboard.displayslot.DisplaySlots;
|
||||
import org.spongepowered.api.scoreboard.objective.Objective;
|
||||
import org.spongepowered.api.scoreboard.objective.displaymode.ObjectiveDisplayMode;
|
||||
import org.spongepowered.api.scoreboard.objective.displaymode.ObjectiveDisplayModes;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -19,17 +21,31 @@ public class SpongeScoreboard extends Scoreboard<SpongeTabPlayer> {
|
||||
|
||||
/** Collision rule array for fast access */
|
||||
private static final org.spongepowered.api.scoreboard.CollisionRule[] collisionRules = new org.spongepowered.api.scoreboard.CollisionRule[]{
|
||||
CollisionRules.ALWAYS.get(), CollisionRules.NEVER.get(), CollisionRules.PUSH_OTHER_TEAMS.get(), CollisionRules.PUSH_OWN_TEAM.get()
|
||||
CollisionRules.ALWAYS.get(),
|
||||
CollisionRules.NEVER.get(),
|
||||
CollisionRules.PUSH_OTHER_TEAMS.get(),
|
||||
CollisionRules.PUSH_OWN_TEAM.get()
|
||||
};
|
||||
|
||||
/** Visibility array for fast access */
|
||||
private static final Visibility[] visibilities = new Visibility[] {
|
||||
Visibilities.ALWAYS.get(), Visibilities.NEVER.get(), Visibilities.HIDE_FOR_OTHER_TEAMS.get(), Visibilities.HIDE_FOR_OWN_TEAM.get()
|
||||
Visibilities.ALWAYS.get(),
|
||||
Visibilities.NEVER.get(),
|
||||
Visibilities.HIDE_FOR_OTHER_TEAMS.get(),
|
||||
Visibilities.HIDE_FOR_OWN_TEAM.get()
|
||||
};
|
||||
|
||||
/** DisplaySlot array for fast access */
|
||||
private static final org.spongepowered.api.scoreboard.displayslot.DisplaySlot[] displaySlots = new org.spongepowered.api.scoreboard.displayslot.DisplaySlot[] {
|
||||
DisplaySlots.LIST.get(), DisplaySlots.SIDEBAR.get(), DisplaySlots.BELOW_NAME.get()
|
||||
DisplaySlots.LIST.get(),
|
||||
DisplaySlots.SIDEBAR.get(),
|
||||
DisplaySlots.BELOW_NAME.get()
|
||||
};
|
||||
|
||||
/** Health display array for fast access */
|
||||
private static final ObjectiveDisplayMode[] healthDisplays = new ObjectiveDisplayMode[] {
|
||||
ObjectiveDisplayModes.INTEGER.get(),
|
||||
ObjectiveDisplayModes.HEARTS.get()
|
||||
};
|
||||
|
||||
/** Scoreboard of the player */
|
||||
@@ -38,7 +54,8 @@ public class SpongeScoreboard extends Scoreboard<SpongeTabPlayer> {
|
||||
|
||||
public SpongeScoreboard(@NotNull SpongeTabPlayer player) {
|
||||
super(player);
|
||||
// Make sure each player is in different scoreboard for per-player view
|
||||
|
||||
// Make sure each player is in a different scoreboard for per-player view
|
||||
player.getPlayer().setScoreboard(sb);
|
||||
}
|
||||
|
||||
@@ -52,9 +69,10 @@ public class SpongeScoreboard extends Scoreboard<SpongeTabPlayer> {
|
||||
sb.addObjective(Objective.builder()
|
||||
.name(objectiveName)
|
||||
.displayName(adventure(title))
|
||||
.objectiveDisplayMode(display == HealthDisplay.HEARTS ? ObjectiveDisplayModes.HEARTS : ObjectiveDisplayModes.INTEGER)
|
||||
.objectiveDisplayMode(healthDisplays[display.ordinal()])
|
||||
.criterion(Criteria.DUMMY)
|
||||
.build());
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,7 +84,7 @@ public class SpongeScoreboard extends Scoreboard<SpongeTabPlayer> {
|
||||
public void updateObjective0(@NotNull String objectiveName, @NotNull String title, @NotNull HealthDisplay display) {
|
||||
sb.objective(objectiveName).ifPresent(obj -> {
|
||||
obj.setDisplayName(adventure(title));
|
||||
obj.setDisplayMode(display == HealthDisplay.HEARTS ? ObjectiveDisplayModes.HEARTS.get() : ObjectiveDisplayModes.INTEGER.get());
|
||||
obj.setDisplayMode(healthDisplays[display.ordinal()]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -128,6 +146,6 @@ public class SpongeScoreboard extends Scoreboard<SpongeTabPlayer> {
|
||||
*/
|
||||
@NotNull
|
||||
private Component adventure(@NotNull String text) {
|
||||
return player.getPlatform().toComponent(IChatBaseComponent.optimizedComponent(text), player.getVersion());
|
||||
return AdventureHook.toAdventureComponent(IChatBaseComponent.optimizedComponent(text), player.getVersion());
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package me.neznamy.tab.platforms.sponge8;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.hook.AdventureHook;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -42,7 +43,7 @@ public class SpongeTabList implements TabList {
|
||||
@Override
|
||||
public void updateDisplayName(@NotNull UUID entry, @Nullable IChatBaseComponent displayName) {
|
||||
player.getPlayer().tabList().entry(entry).ifPresent(e -> {
|
||||
Component component = displayName == null ? null : player.getPlatform().toComponent(displayName, player.getVersion());
|
||||
Component component = displayName == null ? null : AdventureHook.toAdventureComponent(displayName, player.getVersion());
|
||||
e.setDisplayName(component);
|
||||
expectedDisplayNames.put(e, component);
|
||||
});
|
||||
@@ -60,7 +61,7 @@ public class SpongeTabList implements TabList {
|
||||
|
||||
@Override
|
||||
public void addEntry(@NotNull Entry entry) {
|
||||
Component displayName = entry.getDisplayName() == null ? null : player.getPlatform().toComponent(entry.getDisplayName(), player.getVersion());
|
||||
Component displayName = entry.getDisplayName() == null ? null : AdventureHook.toAdventureComponent(entry.getDisplayName(), player.getVersion());
|
||||
GameProfile profile = GameProfile.of(entry.getUniqueId(), entry.getName());
|
||||
if (entry.getSkin() != null) profile = profile.withProperty(ProfileProperty.of(
|
||||
TEXTURES_PROPERTY, entry.getSkin().getValue(), entry.getSkin().getSignature()));
|
||||
@@ -78,8 +79,8 @@ public class SpongeTabList implements TabList {
|
||||
@Override
|
||||
public void setPlayerListHeaderFooter(@NotNull IChatBaseComponent header, @NotNull IChatBaseComponent footer) {
|
||||
player.getPlayer().tabList().setHeaderAndFooter(
|
||||
player.getPlatform().toComponent(header, player.getVersion()),
|
||||
player.getPlatform().toComponent(footer, player.getVersion())
|
||||
AdventureHook.toAdventureComponent(header, player.getVersion()),
|
||||
AdventureHook.toAdventureComponent(footer, player.getVersion())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import lombok.Getter;
|
||||
import me.neznamy.tab.shared.backend.BackendTabPlayer;
|
||||
import me.neznamy.tab.shared.backend.entityview.DummyEntityView;
|
||||
import me.neznamy.tab.shared.backend.entityview.EntityView;
|
||||
import me.neznamy.tab.shared.hook.AdventureHook;
|
||||
import me.neznamy.tab.shared.platform.bossbar.AdventureBossBar;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
@@ -53,7 +54,7 @@ public class SpongeTabPlayer extends BackendTabPlayer {
|
||||
|
||||
@Override
|
||||
public void sendMessage(@NotNull IChatBaseComponent message) {
|
||||
getPlayer().sendMessage(getPlatform().toComponent(message, getVersion()));
|
||||
getPlayer().sendMessage(AdventureHook.toAdventureComponent(message, getVersion()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -30,7 +30,8 @@ public class VelocityEventListener extends EventListener<Player> {
|
||||
public void onConnect(@NotNull ServerPostConnectEvent e) {
|
||||
serverChange(
|
||||
e.getPlayer(), e.getPlayer().getUniqueId(),
|
||||
e.getPlayer().getCurrentServer().map(s -> s.getServerInfo().getName()).orElse("null")
|
||||
e.getPlayer().getCurrentServer().map(s -> s.getServerInfo().getName()).orElse("null"),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,17 +7,14 @@ import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.neznamy.tab.platforms.velocity.features.VelocityRedisSupport;
|
||||
import me.neznamy.tab.shared.ProtocolVersion;
|
||||
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.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.features.injection.PipelineInjector;
|
||||
import me.neznamy.tab.shared.features.redis.RedisSupport;
|
||||
import me.neznamy.tab.shared.hook.AdventureHook;
|
||||
import me.neznamy.tab.shared.proxy.ProxyPlatform;
|
||||
import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bstats.charts.SimplePie;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -28,7 +25,7 @@ import java.io.File;
|
||||
* Velocity implementation of Platform
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class VelocityPlatform extends ProxyPlatform<Component> {
|
||||
public class VelocityPlatform extends ProxyPlatform {
|
||||
|
||||
@NotNull
|
||||
private final VelocityTAB plugin;
|
||||
@@ -94,11 +91,6 @@ public class VelocityPlatform extends ProxyPlatform<Component> {
|
||||
return plugin.getDataFolder().toFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component toComponent(@NotNull IChatBaseComponent component, @NotNull ProtocolVersion version) {
|
||||
return AdventureHook.toAdventureComponent(component, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PipelineInjector createPipelineInjector() {
|
||||
|
||||
@@ -10,7 +10,6 @@ import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import lombok.Getter;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import org.bstats.velocity.Metrics;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
@@ -52,9 +51,6 @@ public class VelocityTAB {
|
||||
@Subscribe
|
||||
public void onProxyInitialization(@Nullable ProxyInitializeEvent event) {
|
||||
TAB.create(new VelocityPlatform(this));
|
||||
TAB.getInstance().getPlatform().logWarn(new IChatBaseComponent("Velocity compatibility is very experimental and should not be used in production! " +
|
||||
"If you use it, you WILL run into issues and they WILL NOT be fixed. Any bug reports featuring Velocity installation " +
|
||||
"will be immediately closed."));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.velocitypowered.api.proxy.player.TabListEntry;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.hook.AdventureHook;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -39,7 +40,7 @@ public class VelocityTabList implements TabList {
|
||||
public void updateDisplayName(@NotNull UUID entry, @Nullable IChatBaseComponent displayName) {
|
||||
getEntry(entry).ifPresent(e -> {
|
||||
if (player.getVersion().getMinorVersion() >= 8) {
|
||||
Component component = displayName == null ? null : player.getPlatform().toComponent(displayName, player.getVersion());
|
||||
Component component = displayName == null ? null : AdventureHook.toAdventureComponent(displayName, player.getVersion());
|
||||
e.setDisplayName(component);
|
||||
expectedDisplayNames.put(e, component);
|
||||
} else {
|
||||
@@ -62,7 +63,8 @@ public class VelocityTabList implements TabList {
|
||||
|
||||
@Override
|
||||
public void addEntry(@NotNull Entry entry) {
|
||||
Component displayName = entry.getDisplayName() == null ? null : player.getPlatform().toComponent(entry.getDisplayName(), player.getVersion());
|
||||
if (player.getPlayer().getTabList().containsEntry(entry.getUniqueId())) return;
|
||||
Component displayName = entry.getDisplayName() == null ? null : AdventureHook.toAdventureComponent(entry.getDisplayName(), player.getVersion());
|
||||
TabListEntry e = TabListEntry.builder()
|
||||
.tabList(player.getPlayer().getTabList())
|
||||
.profile(new GameProfile(
|
||||
@@ -82,8 +84,8 @@ public class VelocityTabList implements TabList {
|
||||
@Override
|
||||
public void setPlayerListHeaderFooter(@NotNull IChatBaseComponent header, @NotNull IChatBaseComponent footer) {
|
||||
player.getPlayer().sendPlayerListHeaderAndFooter(
|
||||
player.getPlatform().toComponent(header, player.getVersion()),
|
||||
player.getPlatform().toComponent(footer, player.getVersion())
|
||||
AdventureHook.toAdventureComponent(header, player.getVersion()),
|
||||
AdventureHook.toAdventureComponent(footer, player.getVersion())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package me.neznamy.tab.platforms.velocity;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import lombok.Getter;
|
||||
import me.neznamy.tab.shared.hook.AdventureHook;
|
||||
import me.neznamy.tab.shared.platform.bossbar.AdventureBossBar;
|
||||
import me.neznamy.tab.shared.platform.bossbar.BossBar;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
@@ -57,7 +58,7 @@ public class VelocityTabPlayer extends ProxyTabPlayer {
|
||||
|
||||
@Override
|
||||
public void sendMessage(@NotNull IChatBaseComponent message) {
|
||||
getPlayer().sendMessage(getPlatform().toComponent(message, getVersion()));
|
||||
getPlayer().sendMessage(AdventureHook.toAdventureComponent(message, getVersion()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in new issue
Block a user