Compare commits

...
22 Commits
Author SHA1 Message Date
NEZNAMY 6f2b92e044 5.2.4 2025-07-01 20:38:47 +02:00
NEZNAMY 5da16e8055 Update to 1.21.7 2025-07-01 20:33:36 +02:00
NEZNAMY a522ea9902 [Proxy Support] Add try/catch for message decoding 2025-07-01 20:32:55 +02:00
NEZNAMY 36801184a5 5.2.4-SNAPSHOT 2025-06-30 16:39:37 +02:00
NEZNAMY d212eb108d [Bukkit] Remove unused empty lists from plugin.yml to avoid Polymart bug breaking them 2025-06-26 18:32:51 +02:00
NEZNAMY cbc1de0f33 [Description] Update badges 2025-06-23 18:49:25 +02:00
NEZNAMY fcdc04e228 5.2.3 2025-06-23 18:36:49 +02:00
NEZNAMY 890f1ee131 [Velocity] Improve message telling users to install VelocityScoreboardAPI 2025-06-23 18:36:37 +02:00
NEZNAMY f3aec47ac3 [BungeeCord] Send header/footer using API since it no longer throws an error 2025-06-22 10:48:31 +02:00
NEZNAMY bcf1c828b5 [BungeeCord] Update to build 1980 (older versions are no longer supported) 2025-06-22 10:40:34 +02:00
NEZNAMY 5fd319a152 [BossBar] Fix %tab_bossbar_visible% not loading on join when player has bossbar disabled and toggling is saved 2025-06-22 10:04:38 +02:00
NEZNAMY abecb58a8d [API] Add methods for removing bossbars and scoreboards (#1507) 2025-06-21 20:35:22 +02:00
NEZNAMY 135166b01e [Bukkit] Remove ViaVersion hook for sending packets due to many unfixable problems 2025-06-21 18:13:46 +02:00
NEZNAMY 0770293452 [Placeholders] Fix placeholder updating when placeholder returned its identifier not being skipped properly (#1502) 2025-06-21 13:57:16 +02:00
NEZNAMY f3c40ad582 [Bukkit] Disable ViaVersion hook for sending raw packets to newer players due to issues 2025-06-21 13:09:44 +02:00
NEZNAMY aacc115a36 [API] Add functions for getting original prefix/suffix values with placeholders parsed 2025-06-21 12:51:03 +02:00
NEZNAMY b7ba07b78d [Bukkit] Remove redundant SneakyThrows annotations 2025-06-21 10:45:27 +02:00
NEZNAMY e13445f55d [Bukkit] Fix skin writing in ViaVersion hook 2025-06-21 10:41:11 +02:00
NEZNAMY bd527d3868 [Configuration] Fix false positive in configuration checking (#1506) 2025-06-20 18:34:24 +02:00
NEZNAMY f288112eb2 [Bukkit] Fix error in ViaVersion hook 2025-06-20 16:18:03 +02:00
NEZNAMY 6b415e64a8 5.2.3-SNAPSHOT 2025-06-19 17:29:10 +02:00
NEZNAMY cfb2cb6b0a [Description] Update badges 2025-06-18 19:20:23 +02:00
82 changed files with 1002 additions and 2062 deletions

No files matched your search

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="138" height="20" role="img" aria-label="Minecraft: 1.5 - 1.21.5"><title>Minecraft: 1.5 - 1.21.5</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="138" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="61" height="20" fill="#555"/><rect x="61" width="77" height="20" fill="#007ec6"/><rect width="138" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="315" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="510">Minecraft</text><text x="315" y="140" transform="scale(.1)" fill="#fff" textLength="510">Minecraft</text><text aria-hidden="true" x="985" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="670">1.5 - 1.21.5</text><text x="985" y="140" transform="scale(.1)" fill="#fff" textLength="670">1.5 - 1.21.5</text></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="138" height="20" role="img" aria-label="Minecraft: 1.5 - 1.21.6"><title>Minecraft: 1.5 - 1.21.6</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="138" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="61" height="20" fill="#555"/><rect x="61" width="77" height="20" fill="#007ec6"/><rect width="138" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="315" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="510">Minecraft</text><text x="315" y="140" transform="scale(.1)" fill="#fff" textLength="510">Minecraft</text><text aria-hidden="true" x="985" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="670">1.5 - 1.21.6</text><text x="985" y="140" transform="scale(.1)" fill="#fff" textLength="670">1.5 - 1.21.6</text></g></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="92" height="20" role="img" aria-label="Release: 5.2.1"><title>Release: 5.2.1</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="92" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="53" height="20" fill="#555"/><rect x="53" width="39" height="20" fill="#007ec6"/><rect width="92" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="275" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">Release</text><text x="275" y="140" transform="scale(.1)" fill="#fff" textLength="430">Release</text><text aria-hidden="true" x="715" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="290">5.2.1</text><text x="715" y="140" transform="scale(.1)" fill="#fff" textLength="290">5.2.1</text></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="92" height="20" role="img" aria-label="Release: 5.2.3"><title>Release: 5.2.3</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="92" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="53" height="20" fill="#555"/><rect x="53" width="39" height="20" fill="#007ec6"/><rect width="92" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="275" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">Release</text><text x="275" y="140" transform="scale(.1)" fill="#fff" textLength="430">Release</text><text aria-hidden="true" x="715" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="290">5.2.3</text><text x="715" y="140" transform="scale(.1)" fill="#fff" textLength="290">5.2.3</text></g></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

+2 -2
View File
@@ -274,10 +274,10 @@ if __name__ == "__main__":
]
)
release = "5.2.1"
release = "5.2.3"
download_image(f"https://img.shields.io/badge/Release-{release}-blue.svg", "Badge_Release.svg")
minecraft = "1.5 - 1.21.5".replace(" ", "%20").replace("-", "--")
minecraft = "1.5 - 1.21.6".replace(" ", "%20").replace("-", "--")
download_image(f"https://img.shields.io/badge/Minecraft-{minecraft}-blue.svg", "Badge_Minecraft.svg")
java = "8+"
@@ -1,14 +1,14 @@
package me.neznamy.tab.api.bossbar;
import java.util.List;
import java.util.Map;
import lombok.NonNull;
import me.neznamy.tab.api.TabAPI;
import me.neznamy.tab.api.TabPlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
/**
* An interface allowing work with BossBars such as creating, sending
* and toggling.
@@ -78,6 +78,28 @@ public interface BossBarManager {
*/
@NotNull Map<String, BossBar> getRegisteredBossBars();
/**
* Removes BossBar with specified name from the manager, making it no longer available.
* If BossBar was displayed to any players, it is removed.
*
* @param name
* Name of registered BossBar to remove
* @throws IllegalArgumentException
* if no BossBar with specified name exists
*/
void removeBossBar(@NonNull String name);
/**
* Removes BossBar from the manager, making it no longer available.
* If BossBar was displayed to any players, it is removed.
*
* @param bossBar
* BossBar to remove
* @throws IllegalArgumentException
* if specified BossBar is not registered
*/
void removeBossBar(@NonNull BossBar bossBar);
/**
* Toggles BossBar for this player and sends toggle message if {@code sendToggleMessage} is true.
*
@@ -134,7 +134,7 @@ public interface NameTagManager {
* @param prefix
* new prefix value
* @see #getCustomPrefix(TabPlayer)
* @see #getOriginalPrefix(TabPlayer)
* @see #getOriginalRawPrefix(TabPlayer)
*/
void setPrefix(@NonNull TabPlayer player, @Nullable String prefix);
@@ -148,7 +148,7 @@ public interface NameTagManager {
* @param suffix
* new suffix value
* @see #getCustomSuffix(TabPlayer)
* @see #getOriginalSuffix(TabPlayer)
* @see #getOriginalRawSuffix(TabPlayer)
*/
void setSuffix(@NonNull TabPlayer player, @Nullable String suffix);
@@ -160,7 +160,7 @@ public interface NameTagManager {
* Player to get custom prefix of
* @return Custom prefix assigned using the API.
* @see #setPrefix(TabPlayer, String)
* @see #getOriginalPrefix(TabPlayer)
* @see #getOriginalRawPrefix(TabPlayer)
*/
@Nullable
String getCustomPrefix(@NonNull TabPlayer player);
@@ -173,7 +173,7 @@ public interface NameTagManager {
* Player to get custom suffix of
* @return Custom suffix assigned using the API.
* @see #setSuffix(TabPlayer, String)
* @see #getOriginalSuffix(TabPlayer)
* @see #getOriginalRawSuffix(TabPlayer)
*/
@Nullable
String getCustomSuffix(@NonNull TabPlayer player);
@@ -186,7 +186,7 @@ public interface NameTagManager {
* @see #getCustomPrefix(TabPlayer)
*/
@NotNull
String getOriginalPrefix(@NonNull TabPlayer player);
String getOriginalRawPrefix(@NonNull TabPlayer player);
/**
* Returns original suffix assigned by the plugin using internal logic.
@@ -196,6 +196,50 @@ public interface NameTagManager {
* @see #getCustomSuffix(TabPlayer)
*/
@NotNull
String getOriginalRawSuffix(@NonNull TabPlayer player);
/**
* Returns original prefix assigned by the plugin using internal logic with all placeholders replaced.
* @param player
* Player to get replaced original prefix of
* @return Original prefix assigned by the plugin's internal logic.
* @see #getCustomPrefix(TabPlayer)
*/
@NotNull
String getOriginalReplacedPrefix(@NonNull TabPlayer player);
/**
* Returns original suffix assigned by the plugin using internal logic with all placeholders replaced.
* @param player
* Player to get replaced original suffix of
* @return Original suffix assigned by the plugin's internal logic.
* @see #getCustomSuffix(TabPlayer)
*/
@NotNull
String getOriginalReplacedSuffix(@NonNull TabPlayer player);
/**
* Returns original suffix assigned by the plugin using internal logic.
* @param player
* Player to get replaced original prefix of
* @return Original prefix assigned by the plugin's internal logic.
* @see #getCustomPrefix(TabPlayer)
* @deprecated Use {@link #getOriginalRawPrefix(TabPlayer)} instead.
*/
@Deprecated
@NotNull
String getOriginalPrefix(@NonNull TabPlayer player);
/**
* Returns original suffix assigned by the plugin using internal logic.
* @param player
* Player to get replaced original suffix of
* @return Original suffix assigned by the plugin's internal logic.
* @see #getCustomSuffix(TabPlayer)
* @deprecated Use {@link #getOriginalRawSuffix(TabPlayer)} instead.
*/
@Deprecated
@NotNull
String getOriginalSuffix(@NonNull TabPlayer player);
/**
@@ -1,13 +1,13 @@
package me.neznamy.tab.api.scoreboard;
import java.util.List;
import java.util.Map;
import lombok.NonNull;
import me.neznamy.tab.api.TabPlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
/**
* Interface allowing work with scoreboards, such as creating,
* sending, toggling and modifying.
@@ -54,6 +54,29 @@ public interface ScoreboardManager {
* @return map of registered scoreboards
*/
@NotNull Map<String, Scoreboard> getRegisteredScoreboards();
/**
* Removes scoreboard with specified name from list of scoreboards. If it was displayed to anyone,
* it will be removed from their display as well. Then, those players will receive a new scoreboard based
* on configuration.
*
* @param name Name of scoreboard to remove
* @throws IllegalArgumentException
* if scoreboard with such name does not exist
*/
void removeScoreboard(@NonNull String name);
/**
* Removes scoreboard from list of scoreboards. If it was displayed to anyone,
* it will be removed from their display as well. Then, those players will receive a new scoreboard based
* on configuration.
*
* @param scoreboard
* Scoreboard to remove
* @throws IllegalArgumentException
* if specified scoreboard is not registered
*/
void removeScoreboard(@NonNull Scoreboard scoreboard);
/**
* Displays scoreboard to defined player. This will disable all display
@@ -27,7 +27,7 @@ public interface TabListFormatManager {
* @param prefix
* new prefix value
* @see #getCustomPrefix(TabPlayer)
* @see #getOriginalPrefix(TabPlayer)
* @see #getOriginalRawPrefix(TabPlayer)
*/
void setPrefix(@NonNull TabPlayer player, @Nullable String prefix);
@@ -41,7 +41,7 @@ public interface TabListFormatManager {
* @param customName
* new customName value
* @see #getCustomName(TabPlayer)
* @see #getOriginalName(TabPlayer)
* @see #getOriginalRawName(TabPlayer)
*/
void setName(@NonNull TabPlayer player, @Nullable String customName);
@@ -55,7 +55,7 @@ public interface TabListFormatManager {
* @param suffix
* new suffix value
* @see #getCustomSuffix(TabPlayer)
* @see #getOriginalSuffix(TabPlayer)
* @see #getOriginalRawSuffix(TabPlayer)
*/
void setSuffix(@NonNull TabPlayer player, @Nullable String suffix);
@@ -67,7 +67,7 @@ public interface TabListFormatManager {
* player to get custom prefix of
* @return player's custom prefix or {@code null} if not defined
* @see #setPrefix(TabPlayer, String)
* @see #getOriginalPrefix(TabPlayer)
* @see #getOriginalRawPrefix(TabPlayer)
*/
@Nullable String getCustomPrefix(@NonNull TabPlayer player);
@@ -104,8 +104,11 @@ public interface TabListFormatManager {
* @return player's original prefix
* @see #setPrefix(TabPlayer, String)
* @see #getCustomPrefix(TabPlayer)
* @deprecated Use {@link #getOriginalRawPrefix(TabPlayer)} instead.
*/
@NotNull String getOriginalPrefix(@NonNull TabPlayer player);
@NotNull
@Deprecated
String getOriginalPrefix(@NonNull TabPlayer player);
/**
* Returns player's original name applied using plugin's internal logic.
@@ -116,8 +119,11 @@ public interface TabListFormatManager {
* @return player's original name
* @see #setName(TabPlayer, String)
* @see #getCustomName(TabPlayer)
* @deprecated Use {@link #getOriginalRawName(TabPlayer)} instead.
*/
@NotNull String getOriginalName(@NonNull TabPlayer player);
@NotNull
@Deprecated
String getOriginalName(@NonNull TabPlayer player);
/**
* Returns player's original suffix applied using plugin's internal logic.
@@ -128,6 +134,69 @@ public interface TabListFormatManager {
* @return player's original suffix
* @see #setSuffix(TabPlayer, String)
* @see #getCustomSuffix(TabPlayer)
* @deprecated Use {@link #getOriginalRawSuffix(TabPlayer)} instead.
*/
@NotNull String getOriginalSuffix(@NonNull TabPlayer player);
@NotNull
@Deprecated
String getOriginalSuffix(@NonNull TabPlayer player);
/**
* Returns original prefix assigned by the plugin using internal logic.
* @param player
* Player to get original prefix of
* @return Original prefix assigned by the plugin's internal logic.
* @see #getCustomPrefix(TabPlayer)
*/
@NotNull
String getOriginalRawPrefix(@NonNull TabPlayer player);
/**
* Returns original name assigned by the plugin using internal logic.
* @param player
* Player to get original name of
* @return Original name assigned by the plugin's internal logic.
* @see #getCustomName(TabPlayer)
*/
@NotNull
String getOriginalRawName(@NonNull TabPlayer player);
/**
* Returns original suffix assigned by the plugin using internal logic.
* @param player
* Player to get original suffix of
* @return Original suffix assigned by the plugin's internal logic.
* @see #getCustomSuffix(TabPlayer)
*/
@NotNull
String getOriginalRawSuffix(@NonNull TabPlayer player);
/**
* Returns original prefix assigned by the plugin using internal logic with all placeholders replaced.
* @param player
* Player to get replaced original prefix of
* @return Original prefix assigned by the plugin's internal logic.
* @see #getCustomPrefix(TabPlayer)
*/
@NotNull
String getOriginalReplacedPrefix(@NonNull TabPlayer player);
/**
* Returns original name assigned by the plugin using internal logic with all placeholders replaced.
* @param player
* Player to get replaced original name of
* @return Original name assigned by the plugin's internal logic.
* @see #getCustomName(TabPlayer)
*/
@NotNull
String getOriginalReplacedName(@NonNull TabPlayer player);
/**
* Returns original suffix assigned by the plugin using internal logic with all placeholders replaced.
* @param player
* Player to get replaced original suffix of
* @return Original suffix assigned by the plugin's internal logic.
* @see #getCustomSuffix(TabPlayer)
*/
@NotNull
String getOriginalReplacedSuffix(@NonNull TabPlayer player);
}
+1 -1
View File
@@ -4,7 +4,7 @@ plugins {
allprojects {
group = "me.neznamy"
version = "5.2.2"
version = "5.2.4"
description = "An all-in-one solution that works"
ext.set("id", "tab")
-2
View File
@@ -15,6 +15,4 @@ dependencies {
exclude("net.md-5", "bungeecord-chat")
}
compileOnly("com.github.LeonMangler:PremiumVanishAPI:2.8.8")
compileOnlyApi("com.viaversion:viaversion-api:5.2.1")
compileOnly("com.viaversion:viaversion-common:5.2.1")
}
@@ -2,12 +2,9 @@ package me.neznamy.tab.platforms.paper_1_20_5;
import io.netty.channel.Channel;
import lombok.Getter;
import lombok.NonNull;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.platforms.bukkit.provider.ComponentConverter;
import me.neznamy.tab.platforms.bukkit.provider.ImplementationProvider;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaScoreboard;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaTabList;
import me.neznamy.tab.shared.platform.Scoreboard;
import me.neznamy.tab.shared.platform.TabList;
import me.neznamy.tab.shared.util.function.FunctionWithException;
@@ -29,16 +26,6 @@ public class PaperImplementationProvider implements ImplementationProvider {
return new PaperPacketScoreboard(player);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaScoreboard scoreboard) {
PaperPacketScoreboard.onPacketSend(packet, scoreboard);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaTabList tabList) {
PaperPacketTabList.onPacketSend(packet, tabList);
}
@Override
@NotNull
public TabList newTabList(@NotNull BukkitTabPlayer player) {
@@ -33,35 +33,6 @@ public class PaperPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
private static final Scoreboard dummyScoreboard = new Scoreboard();
private static final Field players = ReflectionUtils.getOnlyField(ClientboundSetPlayerTeamPacket.class, Collection.class);
@SneakyThrows
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
if (packet instanceof ClientboundSetDisplayObjectivePacket display) {
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), display.getSlot().ordinal(), display.getObjectiveName());
}
if (packet instanceof ClientboundSetObjectivePacket objective) {
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(), objective.getMethod(), objective.getObjectiveName());
}
if (packet instanceof ClientboundSetPlayerTeamPacket team) {
int action = getMethod(team);
if (action == TeamAction.UPDATE) return;
players.set(team, scoreboard.onTeamPacket(action, team.getName(), team.getPlayers() == null ? Collections.emptyList() : team.getPlayers()));
}
}
private static int getMethod(@NonNull ClientboundSetPlayerTeamPacket team) {
if (team.getTeamAction() == ClientboundSetPlayerTeamPacket.Action.ADD) {
return 0;
} else if (team.getTeamAction() == ClientboundSetPlayerTeamPacket.Action.REMOVE) {
return 1;
} else if (team.getPlayerAction() == ClientboundSetPlayerTeamPacket.Action.ADD) {
return 3;
} else if (team.getPlayerAction() == ClientboundSetPlayerTeamPacket.Action.REMOVE) {
return 4;
} else {
return 2;
}
}
/**
* Constructs new instance with given player.
*
@@ -161,8 +132,33 @@ public class PaperPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
}
@Override
@SneakyThrows
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (packet instanceof ClientboundSetDisplayObjectivePacket display) {
TAB.getInstance().getFeatureManager().onDisplayObjective(player, display.getSlot().ordinal(), display.getObjectiveName());
}
if (packet instanceof ClientboundSetObjectivePacket objective) {
TAB.getInstance().getFeatureManager().onObjective(player, objective.getMethod(), objective.getObjectiveName());
}
if (packet instanceof ClientboundSetPlayerTeamPacket team) {
int action = getMethod(team);
if (action == TeamAction.UPDATE) return;
players.set(team, onTeamPacket(action, team.getName(), team.getPlayers() == null ? Collections.emptyList() : team.getPlayers()));
}
}
private int getMethod(@NonNull ClientboundSetPlayerTeamPacket team) {
if (team.getTeamAction() == ClientboundSetPlayerTeamPacket.Action.ADD) {
return 0;
} else if (team.getTeamAction() == ClientboundSetPlayerTeamPacket.Action.REMOVE) {
return 1;
} else if (team.getPlayerAction() == ClientboundSetPlayerTeamPacket.Action.ADD) {
return 3;
} else if (team.getPlayerAction() == ClientboundSetPlayerTeamPacket.Action.REMOVE) {
return 4;
} else {
return 2;
}
}
/**
@@ -36,42 +36,6 @@ public class PaperPacketTabList extends TrackedTabList<BukkitTabPlayer> {
private static final Field entries = ReflectionUtils.getOnlyField(ClientboundPlayerInfoUpdatePacket.class, List.class);
@SneakyThrows
public static void onPacketSend(@NonNull Object packet, TrackedTabList<BukkitTabPlayer> tabList) {
if (packet instanceof ClientboundPlayerInfoUpdatePacket info) {
EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = info.actions();
List<ClientboundPlayerInfoUpdatePacket.Entry> updatedList = new ArrayList<>();
boolean rewritePacket = false;
for (ClientboundPlayerInfoUpdatePacket.Entry nmsData : info.entries()) {
boolean rewriteEntry = false;
Component displayName = nmsData.displayName();
int latency = nmsData.latency();
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) {
TabComponent expectedDisplayName = tabList.getExpectedDisplayNames().get(nmsData.profileId());
if (expectedDisplayName != null && expectedDisplayName.convert() != displayName) {
displayName = expectedDisplayName.convert();
rewriteEntry = rewritePacket = true;
}
}
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY)) {
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(tabList.getPlayer(), nmsData.profileId(), latency);
if (newLatency != latency) {
latency = newLatency;
rewriteEntry = rewritePacket = true;
}
}
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER)) {
TAB.getInstance().getFeatureManager().onEntryAdd(tabList.getPlayer(), nmsData.profileId(), nmsData.profile().getName());
}
updatedList.add(rewriteEntry ? new ClientboundPlayerInfoUpdatePacket.Entry(
nmsData.profileId(), nmsData.profile(), nmsData.listed(), latency, nmsData.gameMode(), displayName,
nmsData.chatSession()
) : nmsData);
}
if (rewritePacket) entries.set(info, updatedList);
}
}
/**
* Constructs new instance.
*
@@ -143,8 +107,40 @@ public class PaperPacketTabList extends TrackedTabList<BukkitTabPlayer> {
}
@Override
@SneakyThrows
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (packet instanceof ClientboundPlayerInfoUpdatePacket info) {
EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = info.actions();
List<ClientboundPlayerInfoUpdatePacket.Entry> updatedList = new ArrayList<>();
boolean rewritePacket = false;
for (ClientboundPlayerInfoUpdatePacket.Entry nmsData : info.entries()) {
boolean rewriteEntry = false;
Component displayName = nmsData.displayName();
int latency = nmsData.latency();
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) {
TabComponent expectedDisplayName = getExpectedDisplayNames().get(nmsData.profileId());
if (expectedDisplayName != null && expectedDisplayName.convert() != displayName) {
displayName = expectedDisplayName.convert();
rewriteEntry = rewritePacket = true;
}
}
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY)) {
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(player, nmsData.profileId(), latency);
if (newLatency != latency) {
latency = newLatency;
rewriteEntry = rewritePacket = true;
}
}
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER)) {
TAB.getInstance().getFeatureManager().onEntryAdd(player, nmsData.profileId(), nmsData.profile().getName());
}
updatedList.add(rewriteEntry ? new ClientboundPlayerInfoUpdatePacket.Entry(
nmsData.profileId(), nmsData.profile(), nmsData.listed(), latency, nmsData.gameMode(), displayName,
nmsData.chatSession()
) : nmsData);
}
if (rewritePacket) entries.set(info, updatedList);
}
}
private void sendPacket(@NonNull EnumSet<ClientboundPlayerInfoUpdatePacket.Action> action, @NonNull UUID id, @NonNull String name, @Nullable Skin skin,
@@ -2,12 +2,9 @@ package me.neznamy.tab.platforms.paper_1_21_2;
import io.netty.channel.Channel;
import lombok.Getter;
import lombok.NonNull;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.platforms.bukkit.provider.ComponentConverter;
import me.neznamy.tab.platforms.bukkit.provider.ImplementationProvider;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaScoreboard;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaTabList;
import me.neznamy.tab.shared.platform.Scoreboard;
import me.neznamy.tab.shared.platform.TabList;
import me.neznamy.tab.shared.util.function.FunctionWithException;
@@ -29,16 +26,6 @@ public class PaperImplementationProvider implements ImplementationProvider {
return new PaperPacketScoreboard(player);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaScoreboard scoreboard) {
PaperPacketScoreboard.onPacketSend(packet, scoreboard);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaTabList tabList) {
PaperPacketTabList.onPacketSend(packet, tabList);
}
@Override
@NotNull
public TabList newTabList(@NotNull BukkitTabPlayer player) {
@@ -33,35 +33,6 @@ public class PaperPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
private static final Scoreboard dummyScoreboard = new Scoreboard();
private static final Field players = ReflectionUtils.getOnlyField(ClientboundSetPlayerTeamPacket.class, Collection.class);
@SneakyThrows
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
if (packet instanceof ClientboundSetDisplayObjectivePacket display) {
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), display.getSlot().ordinal(), display.getObjectiveName());
}
if (packet instanceof ClientboundSetObjectivePacket objective) {
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(), objective.getMethod(), objective.getObjectiveName());
}
if (packet instanceof ClientboundSetPlayerTeamPacket team) {
int action = getMethod(team);
if (action == TeamAction.UPDATE) return;
players.set(team, scoreboard.onTeamPacket(action, team.getName(), team.getPlayers() == null ? Collections.emptyList() : team.getPlayers()));
}
}
private static int getMethod(@NonNull ClientboundSetPlayerTeamPacket team) {
if (team.getTeamAction() == ClientboundSetPlayerTeamPacket.Action.ADD) {
return 0;
} else if (team.getTeamAction() == ClientboundSetPlayerTeamPacket.Action.REMOVE) {
return 1;
} else if (team.getPlayerAction() == ClientboundSetPlayerTeamPacket.Action.ADD) {
return 3;
} else if (team.getPlayerAction() == ClientboundSetPlayerTeamPacket.Action.REMOVE) {
return 4;
} else {
return 2;
}
}
/**
* Constructs new instance with given player.
*
@@ -161,8 +132,33 @@ public class PaperPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
}
@Override
@SneakyThrows
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (packet instanceof ClientboundSetDisplayObjectivePacket display) {
TAB.getInstance().getFeatureManager().onDisplayObjective(player, display.getSlot().ordinal(), display.getObjectiveName());
}
if (packet instanceof ClientboundSetObjectivePacket objective) {
TAB.getInstance().getFeatureManager().onObjective(player, objective.getMethod(), objective.getObjectiveName());
}
if (packet instanceof ClientboundSetPlayerTeamPacket team) {
int action = getMethod(team);
if (action == TeamAction.UPDATE) return;
players.set(team, onTeamPacket(action, team.getName(), team.getPlayers() == null ? Collections.emptyList() : team.getPlayers()));
}
}
private static int getMethod(@NonNull ClientboundSetPlayerTeamPacket team) {
if (team.getTeamAction() == ClientboundSetPlayerTeamPacket.Action.ADD) {
return 0;
} else if (team.getTeamAction() == ClientboundSetPlayerTeamPacket.Action.REMOVE) {
return 1;
} else if (team.getPlayerAction() == ClientboundSetPlayerTeamPacket.Action.ADD) {
return 3;
} else if (team.getPlayerAction() == ClientboundSetPlayerTeamPacket.Action.REMOVE) {
return 4;
} else {
return 2;
}
}
/**
@@ -37,42 +37,6 @@ public class PaperPacketTabList extends TrackedTabList<BukkitTabPlayer> {
private static final Field entries = ReflectionUtils.getOnlyField(ClientboundPlayerInfoUpdatePacket.class, List.class);
@SneakyThrows
public static void onPacketSend(@NonNull Object packet, TrackedTabList<BukkitTabPlayer> tabList) {
if (packet instanceof ClientboundPlayerInfoUpdatePacket info) {
EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = info.actions();
List<ClientboundPlayerInfoUpdatePacket.Entry> updatedList = new ArrayList<>();
boolean rewritePacket = false;
for (ClientboundPlayerInfoUpdatePacket.Entry nmsData : info.entries()) {
boolean rewriteEntry = false;
Component displayName = nmsData.displayName();
int latency = nmsData.latency();
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) {
TabComponent expectedDisplayName = tabList.getExpectedDisplayNames().get(nmsData.profileId());
if (expectedDisplayName != null && expectedDisplayName.convert() != displayName) {
displayName = expectedDisplayName.convert();
rewriteEntry = rewritePacket = true;
}
}
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY)) {
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(tabList.getPlayer(), nmsData.profileId(), latency);
if (newLatency != latency) {
latency = newLatency;
rewriteEntry = rewritePacket = true;
}
}
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER)) {
TAB.getInstance().getFeatureManager().onEntryAdd(tabList.getPlayer(), nmsData.profileId(), nmsData.profile().getName());
}
updatedList.add(rewriteEntry ? new ClientboundPlayerInfoUpdatePacket.Entry(
nmsData.profileId(), nmsData.profile(), nmsData.listed(), latency, nmsData.gameMode(), displayName,
nmsData.listOrder(), nmsData.chatSession()
) : nmsData);
}
if (rewritePacket) entries.set(info, updatedList);
}
}
/**
* Constructs new instance.
*
@@ -144,8 +108,40 @@ public class PaperPacketTabList extends TrackedTabList<BukkitTabPlayer> {
}
@Override
@SneakyThrows
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (packet instanceof ClientboundPlayerInfoUpdatePacket info) {
EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = info.actions();
List<ClientboundPlayerInfoUpdatePacket.Entry> updatedList = new ArrayList<>();
boolean rewritePacket = false;
for (ClientboundPlayerInfoUpdatePacket.Entry nmsData : info.entries()) {
boolean rewriteEntry = false;
Component displayName = nmsData.displayName();
int latency = nmsData.latency();
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) {
TabComponent expectedDisplayName = getExpectedDisplayNames().get(nmsData.profileId());
if (expectedDisplayName != null && expectedDisplayName.convert() != displayName) {
displayName = expectedDisplayName.convert();
rewriteEntry = rewritePacket = true;
}
}
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY)) {
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(player, nmsData.profileId(), latency);
if (newLatency != latency) {
latency = newLatency;
rewriteEntry = rewritePacket = true;
}
}
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER)) {
TAB.getInstance().getFeatureManager().onEntryAdd(player, nmsData.profileId(), nmsData.profile().getName());
}
updatedList.add(rewriteEntry ? new ClientboundPlayerInfoUpdatePacket.Entry(
nmsData.profileId(), nmsData.profile(), nmsData.listed(), latency, nmsData.gameMode(), displayName,
nmsData.listOrder(), nmsData.chatSession()
) : nmsData);
}
if (rewritePacket) entries.set(info, updatedList);
}
}
private void sendPacket(@NonNull EnumSet<ClientboundPlayerInfoUpdatePacket.Action> action, @NonNull UUID id, @NonNull String name, @Nullable Skin skin,
@@ -2,12 +2,9 @@ package me.neznamy.tab.platforms.paper_1_21_4;
import io.netty.channel.Channel;
import lombok.Getter;
import lombok.NonNull;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.platforms.bukkit.provider.ComponentConverter;
import me.neznamy.tab.platforms.bukkit.provider.ImplementationProvider;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaScoreboard;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaTabList;
import me.neznamy.tab.shared.platform.Scoreboard;
import me.neznamy.tab.shared.platform.TabList;
import me.neznamy.tab.shared.util.function.FunctionWithException;
@@ -15,7 +12,7 @@ import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.jetbrains.annotations.NotNull;
/**
* Implementation provider using direct Mojang-mapped NMS code for versions 1.21.4 - 1.21.6.
* Implementation provider using direct Mojang-mapped NMS code for versions 1.21.4 - 1.21.7.
*/
@Getter
public class PaperImplementationProvider implements ImplementationProvider {
@@ -29,16 +26,6 @@ public class PaperImplementationProvider implements ImplementationProvider {
return new PaperPacketScoreboard(player);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaScoreboard scoreboard) {
PaperPacketScoreboard.onPacketSend(packet, scoreboard);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaTabList tabList) {
PaperPacketTabList.onPacketSend(packet, tabList);
}
@Override
@NotNull
public TabList newTabList(@NotNull BukkitTabPlayer player) {
@@ -33,35 +33,6 @@ public class PaperPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
private static final Scoreboard dummyScoreboard = new Scoreboard();
private static final Field players = ReflectionUtils.getOnlyField(ClientboundSetPlayerTeamPacket.class, Collection.class);
@SneakyThrows
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
if (packet instanceof ClientboundSetDisplayObjectivePacket display) {
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), display.getSlot().ordinal(), display.getObjectiveName());
}
if (packet instanceof ClientboundSetObjectivePacket objective) {
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(), objective.getMethod(), objective.getObjectiveName());
}
if (packet instanceof ClientboundSetPlayerTeamPacket team) {
int action = getMethod(team);
if (action == TeamAction.UPDATE) return;
players.set(team, scoreboard.onTeamPacket(action, team.getName(), team.getPlayers() == null ? Collections.emptyList() : team.getPlayers()));
}
}
private static int getMethod(@NonNull ClientboundSetPlayerTeamPacket team) {
if (team.getTeamAction() == ClientboundSetPlayerTeamPacket.Action.ADD) {
return 0;
} else if (team.getTeamAction() == ClientboundSetPlayerTeamPacket.Action.REMOVE) {
return 1;
} else if (team.getPlayerAction() == ClientboundSetPlayerTeamPacket.Action.ADD) {
return 3;
} else if (team.getPlayerAction() == ClientboundSetPlayerTeamPacket.Action.REMOVE) {
return 4;
} else {
return 2;
}
}
/**
* Constructs new instance with given player.
*
@@ -161,8 +132,33 @@ public class PaperPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
}
@Override
@SneakyThrows
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (packet instanceof ClientboundSetDisplayObjectivePacket display) {
TAB.getInstance().getFeatureManager().onDisplayObjective(player, display.getSlot().ordinal(), display.getObjectiveName());
}
if (packet instanceof ClientboundSetObjectivePacket objective) {
TAB.getInstance().getFeatureManager().onObjective(player, objective.getMethod(), objective.getObjectiveName());
}
if (packet instanceof ClientboundSetPlayerTeamPacket team) {
int action = getMethod(team);
if (action == TeamAction.UPDATE) return;
players.set(team, onTeamPacket(action, team.getName(), team.getPlayers() == null ? Collections.emptyList() : team.getPlayers()));
}
}
private int getMethod(@NonNull ClientboundSetPlayerTeamPacket team) {
if (team.getTeamAction() == ClientboundSetPlayerTeamPacket.Action.ADD) {
return 0;
} else if (team.getTeamAction() == ClientboundSetPlayerTeamPacket.Action.REMOVE) {
return 1;
} else if (team.getPlayerAction() == ClientboundSetPlayerTeamPacket.Action.ADD) {
return 3;
} else if (team.getPlayerAction() == ClientboundSetPlayerTeamPacket.Action.REMOVE) {
return 4;
} else {
return 2;
}
}
/**
@@ -172,6 +168,6 @@ public class PaperPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
* Packet to send
*/
private void sendPacket(@NotNull Packet<?> packet) {
((CraftPlayer)player.getPlayer()).getHandle().connection.sendPacket(packet);
((CraftPlayer)player.getPlayer()).getHandle().connection.send(packet);
}
}
@@ -38,42 +38,6 @@ public class PaperPacketTabList extends TrackedTabList<BukkitTabPlayer> {
private static final Field entries = ReflectionUtils.getOnlyField(ClientboundPlayerInfoUpdatePacket.class, List.class);
@SneakyThrows
public static void onPacketSend(@NonNull Object packet, TrackedTabList<BukkitTabPlayer> tabList) {
if (packet instanceof ClientboundPlayerInfoUpdatePacket info) {
EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = info.actions();
List<ClientboundPlayerInfoUpdatePacket.Entry> updatedList = new ArrayList<>();
boolean rewritePacket = false;
for (ClientboundPlayerInfoUpdatePacket.Entry nmsData : info.entries()) {
boolean rewriteEntry = false;
Component displayName = nmsData.displayName();
int latency = nmsData.latency();
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) {
TabComponent expectedDisplayName = tabList.getExpectedDisplayNames().get(nmsData.profileId());
if (expectedDisplayName != null && expectedDisplayName.convert() != displayName) {
displayName = expectedDisplayName.convert();
rewriteEntry = rewritePacket = true;
}
}
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY)) {
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(tabList.getPlayer(), nmsData.profileId(), latency);
if (newLatency != latency) {
latency = newLatency;
rewriteEntry = rewritePacket = true;
}
}
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER)) {
TAB.getInstance().getFeatureManager().onEntryAdd(tabList.getPlayer(), nmsData.profileId(), nmsData.profile().getName());
}
updatedList.add(rewriteEntry ? new ClientboundPlayerInfoUpdatePacket.Entry(
nmsData.profileId(), nmsData.profile(), nmsData.listed(), latency, nmsData.gameMode(), displayName,
nmsData.showHat(), nmsData.listOrder(), nmsData.chatSession()
) : nmsData);
}
if (rewritePacket) entries.set(info, updatedList);
}
}
/**
* Constructs new instance.
*
@@ -145,8 +109,40 @@ public class PaperPacketTabList extends TrackedTabList<BukkitTabPlayer> {
}
@Override
@SneakyThrows
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (packet instanceof ClientboundPlayerInfoUpdatePacket info) {
EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = info.actions();
List<ClientboundPlayerInfoUpdatePacket.Entry> updatedList = new ArrayList<>();
boolean rewritePacket = false;
for (ClientboundPlayerInfoUpdatePacket.Entry nmsData : info.entries()) {
boolean rewriteEntry = false;
Component displayName = nmsData.displayName();
int latency = nmsData.latency();
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) {
TabComponent expectedDisplayName = getExpectedDisplayNames().get(nmsData.profileId());
if (expectedDisplayName != null && expectedDisplayName.convert() != displayName) {
displayName = expectedDisplayName.convert();
rewriteEntry = rewritePacket = true;
}
}
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY)) {
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(player, nmsData.profileId(), latency);
if (newLatency != latency) {
latency = newLatency;
rewriteEntry = rewritePacket = true;
}
}
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER)) {
TAB.getInstance().getFeatureManager().onEntryAdd(player, nmsData.profileId(), nmsData.profile().getName());
}
updatedList.add(rewriteEntry ? new ClientboundPlayerInfoUpdatePacket.Entry(
nmsData.profileId(), nmsData.profile(), nmsData.listed(), latency, nmsData.gameMode(), displayName,
nmsData.showHat(), nmsData.listOrder(), nmsData.chatSession()
) : nmsData);
}
if (rewritePacket) entries.set(info, updatedList);
}
}
private void sendPacket(@NonNull EnumSet<ClientboundPlayerInfoUpdatePacket.Action> action, @NonNull UUID id, @NonNull String name, @Nullable Skin skin,
@@ -23,6 +23,6 @@ public class BukkitPipelineInjector extends NettyPipelineInjector {
@NotNull
@SneakyThrows
protected Channel getChannel(@NotNull TabPlayer player) {
return ((BukkitPlatform)player.getPlatform()).getServerImplementationProvider().getChannelFunction().apply((BukkitTabPlayer) player);
return ((BukkitPlatform)player.getPlatform()).getImplementationProvider().getChannelFunction().apply((BukkitTabPlayer) player);
}
}
@@ -48,7 +48,7 @@ public class BukkitTabPlayer extends BackendTabPlayer {
@Override
public int getPing() {
return getPlatform().getServerImplementationProvider().getPing(this);
return getPlatform().getImplementationProvider().getPing(this);
}
@Override
@@ -1,6 +1,7 @@
package me.neznamy.tab.platforms.bukkit.platform;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import me.clip.placeholderapi.PlaceholderAPI;
import me.neznamy.chat.component.*;
@@ -14,7 +15,6 @@ import me.neznamy.tab.platforms.bukkit.provider.ImplementationProvider;
import me.neznamy.tab.platforms.bukkit.provider.bukkit.BukkitImplementationProvider;
import me.neznamy.tab.platforms.bukkit.provider.bukkit.PaperScoreboard;
import me.neznamy.tab.platforms.bukkit.provider.reflection.ReflectionImplementationProvider;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaVersionProvider;
import me.neznamy.tab.shared.GroupManager;
import me.neznamy.tab.shared.ProtocolVersion;
import me.neznamy.tab.shared.TAB;
@@ -67,7 +67,6 @@ public class BukkitPlatform implements BackendPlatform {
private final JavaPlugin plugin;
/** Server version */
@Getter
private final ProtocolVersion serverVersion = ProtocolVersion.fromFriendlyName(Bukkit.getBukkitVersion().split("-")[0]);
/** Variables checking presence of other plugins to hook into */
@@ -84,13 +83,8 @@ public class BukkitPlatform implements BackendPlatform {
/** Implementation for creating new instances using content available on the server */
@NotNull
private final ImplementationProvider serverImplementationProvider = findImplementationProvider();
/** Implementation for sending new content to new players on old servers */
@Nullable
private final ViaVersionProvider viaVersionProvider =
ReflectionUtils.classExists("com.viaversion.viaversion.protocols.v1_20_2to1_20_3.Protocol1_20_2To1_20_3") ?
new ViaVersionProvider(serverVersion) : null;
@Setter
private ImplementationProvider implementationProvider = findImplementationProvider();
private final boolean modernOnlinePlayers;
@@ -161,7 +155,7 @@ public class BukkitPlatform implements BackendPlatform {
}
Bukkit.getConsoleSender().sendMessage("§c[TAB] Please use " +
"a plugin version with full support for your server version for optimal experience. This plugin version " +
"has full support for 1.8.8, 1.12.x, 1.16.5, 1.17.x, 1.18.2 and 1.19.1 - 1.21.6.");
"has full support for 1.8.8, 1.12.x, 1.16.5, 1.17.x, 1.18.2 and 1.19.1 - 1.21.7.");
}
return new BukkitImplementationProvider();
}
@@ -189,6 +183,7 @@ public class BukkitPlatform implements BackendPlatform {
case V1_21_4:
case V1_21_5:
case V1_21_6:
case V1_21_7:
return "1_21_4";
default:
return null;
@@ -223,7 +218,7 @@ public class BukkitPlatform implements BackendPlatform {
@Override
@Nullable
public PipelineInjector createPipelineInjector() {
return serverImplementationProvider.getChannelFunction() != null ? new BukkitPipelineInjector() : null;
return implementationProvider.getChannelFunction() != null ? new BukkitPipelineInjector() : null;
}
@Override
@@ -336,8 +331,8 @@ public class BukkitPlatform implements BackendPlatform {
@Override
@NotNull
public Object convertComponent(@NotNull TabComponent component) {
if (serverImplementationProvider.getComponentConverter() != null) {
return serverImplementationProvider.getComponentConverter().convert(component);
if (implementationProvider.getComponentConverter() != null) {
return implementationProvider.getComponentConverter().convert(component);
} else {
return component;
}
@@ -345,13 +340,8 @@ public class BukkitPlatform implements BackendPlatform {
@Override
@NotNull
@SneakyThrows
public Scoreboard createScoreboard(@NotNull TabPlayer player) {
if (viaVersionProvider != null) {
Scoreboard scoreboard = viaVersionProvider.newScoreboard((BukkitTabPlayer) player);
if (scoreboard != null) return scoreboard;
}
return serverImplementationProvider.newScoreboard((BukkitTabPlayer) player);
return implementationProvider.newScoreboard((BukkitTabPlayer) player);
}
@Override
@@ -372,13 +362,8 @@ public class BukkitPlatform implements BackendPlatform {
@Override
@NotNull
@SneakyThrows
public TabList createTabList(@NotNull TabPlayer player) {
if (viaVersionProvider != null) {
TabList tabList = viaVersionProvider.newTabList((BukkitTabPlayer) player);
if (tabList != null) return tabList;
}
return serverImplementationProvider.newTabList((BukkitTabPlayer) player);
return implementationProvider.newTabList((BukkitTabPlayer) player);
}
@Override
@@ -386,6 +371,11 @@ public class BukkitPlatform implements BackendPlatform {
return true;
}
@Override
public boolean supportsListOrder() {
return serverVersion.getNetworkId() >= ProtocolVersion.V1_21_2.getNetworkId();
}
@Override
public boolean isSafeFromPacketEventsBug() {
return serverVersion.getMinorVersion() >= 13;
@@ -1,10 +1,7 @@
package me.neznamy.tab.platforms.bukkit.provider;
import io.netty.channel.Channel;
import lombok.NonNull;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaScoreboard;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaTabList;
import me.neznamy.tab.shared.platform.Scoreboard;
import me.neznamy.tab.shared.platform.TabList;
import me.neznamy.tab.shared.util.function.FunctionWithException;
@@ -16,10 +13,6 @@ public interface ImplementationProvider {
@NotNull
Scoreboard newScoreboard(@NotNull BukkitTabPlayer player);
void onPacketSend(@NonNull Object packet, @NonNull ViaScoreboard scoreboard);
void onPacketSend(@NonNull Object packet, @NonNull ViaTabList tabList);
@NotNull
TabList newTabList(@NotNull BukkitTabPlayer player);
@@ -2,12 +2,9 @@ package me.neznamy.tab.platforms.bukkit.provider.bukkit;
import io.netty.channel.Channel;
import lombok.Getter;
import lombok.NonNull;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.platforms.bukkit.provider.ComponentConverter;
import me.neznamy.tab.platforms.bukkit.provider.ImplementationProvider;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaScoreboard;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaTabList;
import me.neznamy.tab.shared.platform.Scoreboard;
import me.neznamy.tab.shared.platform.TabList;
import me.neznamy.tab.shared.platform.impl.DummyScoreboard;
@@ -40,16 +37,6 @@ public class BukkitImplementationProvider implements ImplementationProvider {
}
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaScoreboard scoreboard) {
// Do nothing
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaTabList tabList) {
// Do nothing
}
@Override
@NotNull
public TabList newTabList(@NotNull BukkitTabPlayer player) {
@@ -136,19 +136,6 @@ public class PacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
}
}
@SneakyThrows
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
if (DisplayObjectiveClass.isInstance(packet)) {
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), packetToSlot.apply(packet),
(String) DisplayObjective_OBJECTIVE_NAME.get(packet));
}
if (ObjectivePacketClass.isInstance(packet)) {
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(),
Objective_METHOD.getInt(packet), (String) Objective_OBJECTIVE_NAME.get(packet));
}
teamPacketData.onPacketSend(scoreboard.getPlayer(), packet);
}
/**
* Constructs new instance with given player.
*
@@ -227,8 +214,17 @@ public class PacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
}
@Override
@SneakyThrows
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (DisplayObjectiveClass.isInstance(packet)) {
TAB.getInstance().getFeatureManager().onDisplayObjective(player, packetToSlot.apply(packet),
(String) DisplayObjective_OBJECTIVE_NAME.get(packet));
}
if (ObjectivePacketClass.isInstance(packet)) {
TAB.getInstance().getFeatureManager().onObjective(player,
Objective_METHOD.getInt(packet), (String) Objective_OBJECTIVE_NAME.get(packet));
}
teamPacketData.onPacketSend(player, packet);
}
@SneakyThrows
@@ -157,52 +157,6 @@ public class PacketTabList extends TrackedTabList<BukkitTabPlayer> {
}
}
@SneakyThrows
public static void onPacketSend(@NonNull Object packet, @NonNull TrackedTabList<BukkitTabPlayer> tabList) {
if (!(PlayerInfoClass.isInstance(packet))) return;
EnumSet<?> actions = (EnumSet<?>) ACTION.get(packet);
List<Object> updatedList = new ArrayList<>();
boolean rewritePacket = false;
for (Object nmsData : (List<?>) PLAYERS.get(packet)) {
boolean rewriteEntry = false;
UUID id = (UUID) PlayerInfoData_UUID.get(nmsData);
GameProfile profile = (GameProfile) PlayerInfoData_Profile.get(nmsData);
Object displayName = PlayerInfoData_DisplayName.get(nmsData);
int latency = PlayerInfoData_Latency.getInt(nmsData);
int listOrder = v1_21_2Plus ? PlayerInfoData_ListOrder.getInt(nmsData) : 0;
boolean showHat = v1_21_4Plus && PlayerInfoData_ShowHat.getBoolean(nmsData);
if (actions.contains(actionUpdateDisplayName)) {
TabComponent expectedName = tabList.getExpectedDisplayNames().get(id);
if (expectedName != null && expectedName.convert() != displayName) {
displayName = expectedName.convert();
rewriteEntry = rewritePacket = true;
}
}
if (actions.contains(actionUpdateLatency)) {
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(tabList.getPlayer(), id, latency);
if (newLatency != latency) {
latency = newLatency;
rewriteEntry = rewritePacket = true;
}
}
if (actions.contains(actionAddPlayer)) {
TAB.getInstance().getFeatureManager().onEntryAdd(tabList.getPlayer(), id, profile.getName());
}
// 1.19.3 is using records, which do not allow changing final fields, need to rewrite the list entirely
updatedList.add(rewriteEntry ? newPlayerInfoData(
id,
profile,
PlayerInfoData_Listed.getBoolean(nmsData),
latency,
PlayerInfoData_GameMode.get(nmsData),
displayName,
showHat,
listOrder,
PlayerInfoData_RemoteChatSession.get(nmsData)) : nmsData);
}
if (rewritePacket) PLAYERS.set(packet, updatedList);
}
@Override
@SneakyThrows
public void removeEntry(@NonNull UUID entry) {
@@ -282,8 +236,50 @@ public class PacketTabList extends TrackedTabList<BukkitTabPlayer> {
}
@Override
@SneakyThrows
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (!(PlayerInfoClass.isInstance(packet))) return;
EnumSet<?> actions = (EnumSet<?>) ACTION.get(packet);
List<Object> updatedList = new ArrayList<>();
boolean rewritePacket = false;
for (Object nmsData : (List<?>) PLAYERS.get(packet)) {
boolean rewriteEntry = false;
UUID id = (UUID) PlayerInfoData_UUID.get(nmsData);
GameProfile profile = (GameProfile) PlayerInfoData_Profile.get(nmsData);
Object displayName = PlayerInfoData_DisplayName.get(nmsData);
int latency = PlayerInfoData_Latency.getInt(nmsData);
int listOrder = v1_21_2Plus ? PlayerInfoData_ListOrder.getInt(nmsData) : 0;
boolean showHat = v1_21_4Plus && PlayerInfoData_ShowHat.getBoolean(nmsData);
if (actions.contains(actionUpdateDisplayName)) {
TabComponent expectedName = getExpectedDisplayNames().get(id);
if (expectedName != null && expectedName.convert() != displayName) {
displayName = expectedName.convert();
rewriteEntry = rewritePacket = true;
}
}
if (actions.contains(actionUpdateLatency)) {
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(player, id, latency);
if (newLatency != latency) {
latency = newLatency;
rewriteEntry = rewritePacket = true;
}
}
if (actions.contains(actionAddPlayer)) {
TAB.getInstance().getFeatureManager().onEntryAdd(player, id, profile.getName());
}
// 1.19.3 is using records, which do not allow changing final fields, need to rewrite the list entirely
updatedList.add(rewriteEntry ? newPlayerInfoData(
id,
profile,
PlayerInfoData_Listed.getBoolean(nmsData),
latency,
PlayerInfoData_GameMode.get(nmsData),
displayName,
showHat,
listOrder,
PlayerInfoData_RemoteChatSession.get(nmsData)) : nmsData);
}
if (rewritePacket) PLAYERS.set(packet, updatedList);
}
@NotNull
@@ -327,13 +323,8 @@ public class PacketTabList extends TrackedTabList<BukkitTabPlayer> {
@Nullable
@Override
public Skin getSkin() {
return getSkin(player);
}
@Nullable
@SneakyThrows
public static Skin getSkin(@NotNull BukkitTabPlayer player) {
public Skin getSkin() {
Collection<Property> col = ((GameProfile) getProfile.invoke(player.getHandle())).getProperties().get(TabList.TEXTURES_PROPERTY);
if (col.isEmpty()) return null; //offline mode
Property property = col.iterator().next();
@@ -2,13 +2,10 @@ package me.neznamy.tab.platforms.bukkit.provider.reflection;
import io.netty.channel.Channel;
import lombok.Getter;
import lombok.NonNull;
import me.neznamy.tab.platforms.bukkit.BukkitReflection;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.platforms.bukkit.provider.ComponentConverter;
import me.neznamy.tab.platforms.bukkit.provider.ImplementationProvider;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaScoreboard;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaTabList;
import me.neznamy.tab.shared.platform.Scoreboard;
import me.neznamy.tab.shared.platform.TabList;
import me.neznamy.tab.shared.util.ReflectionUtils;
@@ -64,16 +61,6 @@ public class ReflectionImplementationProvider implements ImplementationProvider
return new PacketScoreboard(player);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaScoreboard scoreboard) {
PacketScoreboard.onPacketSend(packet, scoreboard);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaTabList tabList) {
PacketTabList.onPacketSend(packet, tabList);
}
@Override
@NotNull
public TabList newTabList(@NotNull BukkitTabPlayer player) {
@@ -1,195 +0,0 @@
package me.neznamy.tab.platforms.bukkit.provider.viaversion;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.PacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.type.Types;
import lombok.NonNull;
import me.neznamy.chat.component.TabComponent;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.platforms.bukkit.platform.BukkitPlatform;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.platform.decorators.SafeScoreboard;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* Scoreboard abstract implementation using ViaVersion packets,
* focused to unlock new features on older versions, and also
* optimize packet conversion between versions.
*/
public abstract class ViaScoreboard extends SafeScoreboard<BukkitTabPlayer> {
private static final long CHECK_DELAY = 50;
private static final Object DUMMY = new Object();
protected final Class<? extends Protocol> protocol;
protected final PacketType setDisplayObjective;
private final PacketType setObjective;
protected final PacketType setScore;
private final PacketType setPlayerTeam;
/** User connection this scoreboard belongs to */
protected final UserConnection connection;
private transient ScheduledFuture<?> task;
private transient final Queue<PacketWrapper> queuedPackets = new ConcurrentLinkedQueue<>();
/**
* Constructs new instance with given player.
*
* @param player
* Player this scoreboard will belong to
* @param protocol
* Protocol to be sent packets through
* @param setDisplayObjective
* Objective creation packet
* @param setObjective
* Objective update packet
* @param setScore
* Score update packet
* @param setPlayerTeam
* Player team packet
*/
public ViaScoreboard(@NonNull BukkitTabPlayer player, @NonNull Class<? extends Protocol> protocol, @NonNull PacketType setDisplayObjective, @NonNull PacketType setObjective, @NonNull PacketType setScore, @NonNull PacketType setPlayerTeam) {
super(player);
this.protocol = protocol;
this.setDisplayObjective = setDisplayObjective;
this.setObjective = setObjective;
this.setScore = setScore;
this.setPlayerTeam = setPlayerTeam;
this.connection = Via.getManager().getConnectionManager().getConnectedClient(player.getUniqueId());
// Queue packets until connection is available
// Is important to use scheduleWithFixedDelay() to avoid task overlap
task = connection.getChannel().eventLoop().scheduleWithFixedDelay(() -> {
if (connection.getProtocolInfo().getClientState() == State.PLAY) {
PacketWrapper packet;
while ((packet = queuedPackets.poll()) != null) {
packet.send(protocol);
}
task.cancel(true);
}
}, 0L, CHECK_DELAY, TimeUnit.MILLISECONDS);
}
@Override
public void registerObjective(@NonNull Objective objective) {
sendObjectiveUpdate(ObjectiveAction.REGISTER, objective);
}
@Override
public void unregisterObjective(@NonNull Objective objective) {
sendObjectiveUpdate(ObjectiveAction.UNREGISTER, objective);
}
@Override
public void updateObjective(@NonNull Objective objective) {
sendObjectiveUpdate(ObjectiveAction.UPDATE, objective);
}
@Override
public @NonNull Object createTeam(@NonNull String name) {
// This implementation does not use team objects
return DUMMY;
}
@Override
public void registerTeam(@NonNull Team team) {
sendTeamUpdate(TeamAction.CREATE, team);
}
@Override
public void unregisterTeam(@NonNull Team team) {
sendTeamUpdate(TeamAction.REMOVE, team);
}
@Override
public void updateTeam(@NonNull Team team) {
sendTeamUpdate(TeamAction.UPDATE, team);
}
protected void sendObjectiveUpdate(int mode, @NonNull Objective objective) {
final PacketWrapper packet = PacketWrapper.create(setObjective, null, connection);
// Objective name
packet.write(Types.STRING, objective.getName());
// Mode
packet.write(Types.BYTE, (byte) mode);
// Optional
if (mode == ObjectiveAction.REGISTER || mode == ObjectiveAction.UPDATE) {
writeObjectiveDisplay(packet, objective);
}
send(packet);
}
@SuppressWarnings("fallthrough")
protected void sendTeamUpdate(int mode, @NonNull Team team) {
final PacketWrapper packet = PacketWrapper.create(setPlayerTeam, null, connection);
// Team name (max 16 characters on pre 1.20.3)
packet.write(Types.STRING, team.getName());
// Method
packet.write(Types.BYTE, (byte) mode);
switch (mode) {
case TeamAction.REMOVE:
break;
case TeamAction.CREATE:
case TeamAction.UPDATE:
// Team display name
writeComponent(packet, TabComponent.legacyText(team.getName()));
// Friendly flags
packet.write(Types.BYTE, (byte) team.getOptions());
// Name tag visibility
packet.write(Types.STRING, team.getVisibility().toString());
// Collision rule
packet.write(Types.STRING, team.getCollision().toString());
// Team color
packet.write(Types.VAR_INT, team.getColor().getLegacyColor().ordinal());
// Team prefix
writeComponent(packet, team.getPrefix());
// Team suffix
writeComponent(packet, team.getSuffix());
if (mode == TeamAction.UPDATE) {
break;
}
// Intentional fallthrough for CREATE mode
case TeamAction.ADD_PLAYER:
case TeamAction.REMOVE_PLAYER:
// Entities
packet.write(Types.VAR_INT, team.getPlayers().size());
for (String entity : team.getPlayers()) {
// Entity (player username in this case) (max 40 characters on pre 1.20.3)
packet.write(Types.STRING, entity);
}
break;
default:
throw new IllegalArgumentException("Invalid team update mode: " + mode);
}
send(packet);
}
@Override
public void onPacketSend(@NonNull Object packet) {
((BukkitPlatform) TAB.getInstance().getPlatform()).getServerImplementationProvider().onPacketSend(packet, this);
}
protected abstract void writeComponent(@NonNull PacketWrapper packet, @NonNull TabComponent component);
protected abstract void writeObjectiveDisplay(@NonNull PacketWrapper packet, @NonNull Objective objective);
protected void send(@NonNull PacketWrapper packet) {
if (!task.isCancelled()) {
queuedPackets.add(packet);
} else {
packet.scheduleSend(protocol);
}
}
}
@@ -1,82 +0,0 @@
package me.neznamy.tab.platforms.bukkit.provider.viaversion;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.PacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.util.ComponentUtil;
import lombok.NonNull;
import me.neznamy.chat.component.TabComponent;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
/**
* Scoreboard implementation using ViaVersion packets
* to unlock +1.13 player features on pre 1.13 servers.
*/
public class ViaScoreboard113 extends ViaScoreboard {
/**
* Constructs new instance with given player.
*
* @param player Player this scoreboard will belong to
*/
public ViaScoreboard113(@NonNull BukkitTabPlayer player) {
this(player, Protocol1_12_2To1_13.class, ClientboundPackets1_13.SET_DISPLAY_OBJECTIVE, ClientboundPackets1_13.SET_OBJECTIVE, ClientboundPackets1_13.SET_SCORE, ClientboundPackets1_13.SET_PLAYER_TEAM);
}
protected ViaScoreboard113(@NonNull BukkitTabPlayer player, @NonNull Class<? extends Protocol> protocol, @NonNull PacketType setDisplayObjective, @NonNull PacketType setObjective, @NonNull PacketType setScore, @NonNull PacketType setPlayerTeam) {
super(player, protocol, setDisplayObjective, setObjective, setScore, setPlayerTeam);
}
@Override
public void setDisplaySlot(@NonNull Objective objective) {
PacketWrapper packet = PacketWrapper.create(setDisplayObjective, null, connection);
packet.write(Types.BYTE, (byte) objective.getDisplaySlot().ordinal());
packet.write(Types.STRING, objective.getName());
send(packet);
}
@Override
public void setScore(@NonNull Score score) {
sendScoreUpdate(ScoreAction.CHANGE, score);
}
@Override
public void removeScore(@NonNull Score score) {
sendScoreUpdate(ScoreAction.REMOVE, score);
}
protected void sendScoreUpdate(int action, @NonNull Score score) {
final PacketWrapper packet = PacketWrapper.create(setScore, null, connection);
// Entity name (player username in this case)
packet.write(Types.STRING, score.getHolder());
// Action
packet.write(Types.VAR_INT, action);
// Objective name (max 16 characters)
packet.write(Types.STRING, score.getObjective().getName());
if (action == 0) {
// Value
packet.write(Types.VAR_INT, score.getValue());
}
send(packet);
}
@Override
protected void writeComponent(@NonNull PacketWrapper packet, @NonNull TabComponent component) {
packet.write(Types.COMPONENT, ComponentUtil.legacyToJson(component.toLegacyText()));
}
@Override
protected void writeObjectiveDisplay(@NonNull PacketWrapper packet, @NonNull Objective objective) {
// Objective value
writeComponent(packet, objective.getTitle());
// Type
packet.write(Types.VAR_INT, objective.getHealthDisplay() == HealthDisplay.INTEGER ? 0 : 1);
}
}
@@ -1,36 +0,0 @@
package me.neznamy.tab.platforms.bukkit.provider.viaversion;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.PacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_15_2to1_16.Protocol1_15_2To1_16;
import com.viaversion.viaversion.protocols.v1_15_2to1_16.packet.ClientboundPackets1_16;
import lombok.NonNull;
import me.neznamy.chat.component.TabComponent;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
/**
* Scoreboard implementation using ViaVersion packets
* to unlock +1.16 player features on pre 1.16 servers.
*/
public class ViaScoreboard116 extends ViaScoreboard113 {
/**
* Constructs new instance with given player.
*
* @param player Player this scoreboard will belong to
*/
public ViaScoreboard116(@NonNull BukkitTabPlayer player) {
this(player, Protocol1_15_2To1_16.class, ClientboundPackets1_16.SET_DISPLAY_OBJECTIVE, ClientboundPackets1_16.SET_OBJECTIVE, ClientboundPackets1_16.SET_SCORE, ClientboundPackets1_16.SET_PLAYER_TEAM);
}
protected ViaScoreboard116(@NonNull BukkitTabPlayer player, @NonNull Class<? extends Protocol> protocol, @NonNull PacketType setDisplayObjective, @NonNull PacketType setObjective, @NonNull PacketType setScore, @NonNull PacketType setPlayerTeam) {
super(player, protocol, setDisplayObjective, setObjective, setScore, setPlayerTeam);
}
@Override
protected void writeComponent(@NonNull PacketWrapper packet, @NonNull TabComponent component) {
packet.write(Types.COMPONENT, component.toViaVersion());
}
}
@@ -1,101 +0,0 @@
package me.neznamy.tab.platforms.bukkit.provider.viaversion;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.PacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.Protocol1_20_2To1_20_3;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.packet.ClientboundPackets1_20_3;
import lombok.NonNull;
import me.neznamy.chat.component.TabComponent;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import org.jetbrains.annotations.Nullable;
/**
* Scoreboard implementation using ViaVersion packets
* to unlock +1.20.3 player features on pre 1.20.3 servers.
*/
public class ViaScoreboard1203 extends ViaScoreboard116 {
private final PacketType resetScore;
/**
* Constructs new instance with given player.
*
* @param player Player this scoreboard will belong to
*/
public ViaScoreboard1203(@NonNull BukkitTabPlayer player) {
this(player, Protocol1_20_2To1_20_3.class, ClientboundPackets1_20_3.SET_DISPLAY_OBJECTIVE, ClientboundPackets1_20_3.SET_OBJECTIVE, ClientboundPackets1_20_3.SET_SCORE, ClientboundPackets1_20_3.RESET_SCORE, ClientboundPackets1_20_3.SET_PLAYER_TEAM);
}
protected ViaScoreboard1203(@NonNull BukkitTabPlayer player, @NonNull Class<? extends Protocol> protocol, @NonNull PacketType setDisplayObjective, @NonNull PacketType setObjective, @NonNull PacketType setScore, @NonNull PacketType resetScore, @NonNull PacketType setPlayerTeam) {
super(player, protocol, setDisplayObjective, setObjective, setScore, setPlayerTeam);
this.resetScore = resetScore;
}
@Override
public void setDisplaySlot(@NonNull Objective objective) {
PacketWrapper packet = PacketWrapper.create(setDisplayObjective, null, connection);
packet.write(Types.VAR_INT, objective.getDisplaySlot().ordinal());
packet.write(Types.STRING, objective.getName());
send(packet);
}
@Override
public void setScore(@NonNull Score score) {
final PacketWrapper packet = PacketWrapper.create(setScore, null, connection);
// Entity name (player username in this case)
packet.write(Types.STRING, score.getHolder());
// Objective name
packet.write(Types.STRING, score.getObjective().getName());
// Value
packet.write(Types.VAR_INT, score.getValue());
// Display name
packet.write(Types.OPTIONAL_TAG, score.getDisplayName() == null ? null : score.getDisplayName().toViaVersionTag());
// Number format
writeNumberFormat(packet, score.getNumberFormat());
send(packet);
}
@Override
public void removeScore(@NonNull Score score) {
final PacketWrapper packet = PacketWrapper.create(resetScore, null, connection);
// Entity name (player username in this case)
packet.write(Types.STRING, score.getHolder());
// Objective name
packet.write(Types.OPTIONAL_STRING, score.getObjective().getName().isEmpty() ? null : score.getObjective().getName());
send(packet);
}
@Override
protected void writeComponent(@NonNull PacketWrapper packet, @NonNull TabComponent component) {
packet.write(Types.TAG, component.toViaVersionTag());
}
@Override
protected void writeObjectiveDisplay(@NonNull PacketWrapper packet, @NonNull Objective objective) {
super.writeObjectiveDisplay(packet, objective);
writeNumberFormat(packet, objective.getNumberFormat());
}
protected void writeNumberFormat(@NonNull PacketWrapper packet, @Nullable TabComponent content) {
// For now, only fixed format is supported by TAB
if (content == null) {
// Has number format
packet.write(Types.BOOLEAN, false);
} else {
// Has number format
packet.write(Types.BOOLEAN, true);
// Fixed format
packet.write(Types.VAR_INT, 2);
// Content
packet.write(Types.TAG, content.toViaVersionTag());
}
}
}
@@ -1,185 +0,0 @@
package me.neznamy.tab.platforms.bukkit.provider.viaversion;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.PacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.type.Types;
import lombok.NonNull;
import me.neznamy.chat.component.TabComponent;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.platforms.bukkit.platform.BukkitPlatform;
import me.neznamy.tab.platforms.bukkit.provider.reflection.PacketTabList;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.platform.decorators.TrackedTabList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.BitSet;
import java.util.Queue;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* TabList abstract handler using ViaVersion packets,
* focused to unlock new features on older versions,
* and also optimize packet conversion between versions.
*/
public abstract class ViaTabList extends TrackedTabList<BukkitTabPlayer> {
private static final long CHECK_DELAY = 50;
protected final Class<? extends Protocol> protocol;
private final PacketType playerInfoUpdate;
private final PacketType tabList;
/** User connection this tablist belongs to */
protected final UserConnection connection;
private transient ScheduledFuture<?> task;
private transient final Queue<PacketWrapper> queuedPackets = new ConcurrentLinkedQueue<>();
/**
*
* @param player
* Player this tablist will belong to
* @param protocol
* Protocol to be sent packets through
* @param playerInfoUpdate
* Player information update packet
* @param tabList
* Tab list packet
*/
public ViaTabList(@NonNull BukkitTabPlayer player, @NonNull Class<? extends Protocol> protocol, @NonNull PacketType playerInfoUpdate, @NonNull PacketType tabList) {
super(player);
this.protocol = protocol;
this.playerInfoUpdate = playerInfoUpdate;
this.tabList = tabList;
this.connection = Via.getManager().getConnectionManager().getConnectedClient(player.getUniqueId());
// Queue packets until connection is available
// Is important to use scheduleWithFixedDelay() to avoid task overlap
task = connection.getChannel().eventLoop().scheduleWithFixedDelay(() -> {
if (connection.getProtocolInfo().getClientState() == State.PLAY) {
PacketWrapper packet;
while ((packet = queuedPackets.poll()) != null) {
packet.send(protocol);
}
task.cancel(true);
}
}, 0L, CHECK_DELAY, TimeUnit.MILLISECONDS);
}
@Override
public boolean containsEntry(@NonNull UUID entry) {
return true; // TODO?
}
@Override
public void addEntry0(@NonNull Entry entry) {
sendInfoUpdate(Action.ADD_PLAYER, entry.getUniqueId(), entry);
}
@Override
public void updateDisplayName0(@NonNull UUID entry, @Nullable TabComponent displayName) {
sendInfoUpdate(Action.UPDATE_DISPLAY_NAME, entry, displayName);
}
@Override
public void updateLatency(@NonNull UUID entry, int latency) {
sendInfoUpdate(Action.UPDATE_LATENCY, entry, latency);
}
@Override
public void updateGameMode(@NonNull UUID entry, int gameMode) {
sendInfoUpdate(Action.UPDATE_GAME_MODE, entry, gameMode);
}
@Override
public void setPlayerListHeaderFooter(@NonNull TabComponent header, @NonNull TabComponent footer) {
final PacketWrapper packet = PacketWrapper.create(tabList, null, connection);
writeComponent(packet, header);
writeComponent(packet, footer);
send(packet);
}
@Override
@Nullable
public Skin getSkin() {
return PacketTabList.getSkin(player);
}
protected void sendInfoUpdate(@NonNull Action action, @NonNull UUID uniqueId, Object value) {
final PacketWrapper packet = PacketWrapper.create(playerInfoUpdate, null, connection);
// Action
writeAction(packet, action);
// Players size
packet.write(Types.VAR_INT, 1);
// Players
packet.write(Types.UUID, uniqueId);
switch (action) {
case ADD_PLAYER:
writeEntry(packet, (Entry) value);
break;
case REMOVE_PLAYER:
break;
case UPDATE_GAME_MODE:
case UPDATE_LATENCY:
case UPDATE_LIST_ORDER:
packet.write(Types.VAR_INT, (int) value);
break;
case UPDATE_LISTED:
case UPDATE_HAT:
packet.write(Types.BOOLEAN, (boolean) value);
break;
case UPDATE_DISPLAY_NAME:
writeOptionalComponent(packet, (TabComponent) value);
break;
default:
throw new IllegalArgumentException("Cannot send info update with action " + action.name());
}
send(packet);
}
@Override
public void onPacketSend(@NonNull Object packet) {
((BukkitPlatform) TAB.getInstance().getPlatform()).getServerImplementationProvider().onPacketSend(packet, this);
}
protected abstract void writeComponent(@NonNull PacketWrapper packet, @NonNull TabComponent component);
protected abstract void writeOptionalComponent(@NonNull PacketWrapper packet, @Nullable TabComponent component);
protected abstract void writeAction(@NonNull PacketWrapper packet, @NonNull Action action);
protected abstract void writeEntry(@NonNull PacketWrapper packet, @NonNull Entry entry);
@NotNull
protected static BitSet bitSet(int nbits, int action) {
final BitSet bitSet = new BitSet(nbits);
bitSet.set(action);
return bitSet;
}
@NotNull
protected static BitSet bitSet(int nbits, int fromAction, int toAction) {
final BitSet bit = new BitSet(nbits);
bit.set(fromAction, toAction);
return bit;
}
protected void send(@NonNull PacketWrapper packet) {
if (!task.isCancelled()) {
queuedPackets.add(packet);
} else {
packet.scheduleSend(protocol);
}
}
}
@@ -1,114 +0,0 @@
package me.neznamy.tab.platforms.bukkit.provider.viaversion;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.PacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_15_2to1_16.Protocol1_15_2To1_16;
import com.viaversion.viaversion.protocols.v1_15_2to1_16.packet.ClientboundPackets1_16;
import lombok.NonNull;
import me.neznamy.chat.component.TabComponent;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
/**
* TabList handler using ViaVersion packets,
* to unlock +1.16 player features on pre 1.16 servers.
*/
public class ViaTabList116 extends ViaTabList {
private static final int ADD_PLAYER = 0;
private static final int UPDATE_GAME_MODE = 1;
private static final int UPDATE_LATENCY = 2;
private static final int UPDATE_DISPLAY_NAME = 3;
private static final int REMOVE_PLAYER = 4;
/**
* Constructs new instance with given parameters.
*
* @param player
* Player this tablist will belong to
*/
public ViaTabList116(@NotNull BukkitTabPlayer player) {
this(player, Protocol1_15_2To1_16.class, ClientboundPackets1_16.PLAYER_INFO, ClientboundPackets1_16.TAB_LIST);
}
protected ViaTabList116(@NonNull BukkitTabPlayer player, @NonNull Class<? extends Protocol> protocol, @NonNull PacketType playerInfoUpdate, @NonNull PacketType tabList) {
super(player, protocol, playerInfoUpdate, tabList);
}
@Override
public void removeEntry(@NonNull UUID entry) {
sendInfoUpdate(Action.REMOVE_PLAYER, entry, null);
}
@Override
public void updateListed(@NonNull UUID entry, boolean listed) {
// Added on 1.19.3
}
@Override
public void updateListOrder(@NonNull UUID entry, int listOrder) {
// Added in 1.21.2
}
@Override
public void updateHat(@NonNull UUID entry, boolean showHat) {
// Added in 1.21.4
}
@Override
protected void writeComponent(@NonNull PacketWrapper packet, @NonNull TabComponent component) {
packet.write(Types.COMPONENT, component.toViaVersion());
}
@Override
protected void writeOptionalComponent(@NonNull PacketWrapper packet, @Nullable TabComponent component) {
packet.write(Types.OPTIONAL_COMPONENT, component == null ? null : component.toViaVersion());
}
@Override
protected void writeAction(@NonNull PacketWrapper packet, @NonNull Action action) {
switch (action) {
case ADD_PLAYER:
packet.write(Types.VAR_INT, ADD_PLAYER);
break;
case REMOVE_PLAYER:
packet.write(Types.VAR_INT, REMOVE_PLAYER);
break;
case UPDATE_DISPLAY_NAME:
packet.write(Types.VAR_INT, UPDATE_DISPLAY_NAME);
break;
case UPDATE_LATENCY:
packet.write(Types.VAR_INT, UPDATE_LATENCY);
break;
case UPDATE_GAME_MODE:
packet.write(Types.VAR_INT, UPDATE_GAME_MODE);
break;
default:
throw new IllegalStateException("Cannot write " + action.name() + " for 1.16 packet");
}
}
@Override
protected void writeEntry(@NonNull PacketWrapper packet, @NonNull Entry entry) {
packet.write(Types.STRING, entry.getName());
if (entry.getSkin() == null) {
// Properties size
packet.write(Types.VAR_INT, 0);
} else {
// Properties size
packet.write(Types.VAR_INT, 1);
// Properties
packet.write(Types.STRING, entry.getName());
packet.write(Types.STRING, entry.getSkin().getValue());
packet.write(Types.OPTIONAL_STRING, entry.getSkin().getSignature());
}
packet.write(Types.VAR_INT, entry.getGameMode());
packet.write(Types.VAR_INT, entry.getLatency());
writeOptionalComponent(packet, entry.getDisplayName());
}
}
@@ -1,105 +0,0 @@
package me.neznamy.tab.platforms.bukkit.provider.viaversion;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.PacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.packet.ClientboundPackets1_19_3;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.Protocol1_19_1To1_19_3;
import lombok.NonNull;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.BitSet;
import java.util.UUID;
/**
* TabList handler using ViaVersion packets,
* to unlock +1.19.3 player features on pre 1.19.3 servers.
*/
public class ViaTabList1193 extends ViaTabList116 {
private static final BitSet ADD_PLAYER = bitSet(6, 0, 6);
//private static final BitSet INITIALIZE_CHAT = bitSet(6, 1);
private static final BitSet UPDATE_GAME_MODE = bitSet(6, 2);
private static final BitSet UPDATE_LISTED = bitSet(6, 3);
private static final BitSet UPDATE_LATENCY = bitSet(6, 4);
private static final BitSet UPDATE_DISPLAY_NAME = bitSet(6, 5);
private final PacketType playerInfoRemove;
/**
* Constructs new instance with given parameters.
*
* @param player
* Player this tablist will belong to
*/
public ViaTabList1193(@NotNull BukkitTabPlayer player) {
this(player, Protocol1_19_1To1_19_3.class, ClientboundPackets1_19_3.PLAYER_INFO_REMOVE, ClientboundPackets1_19_3.PLAYER_INFO_UPDATE, ClientboundPackets1_19_3.TAB_LIST);
}
protected ViaTabList1193(@NonNull BukkitTabPlayer player, @NonNull Class<? extends Protocol> protocol, @Nullable PacketType playerInfoRemove, @NonNull PacketType playerInfoUpdate, @NonNull PacketType tabList) {
super(player, protocol, playerInfoUpdate, tabList);
this.playerInfoRemove = playerInfoRemove;
}
@Override
public void removeEntry(@NonNull UUID entry) {
final PacketWrapper packet = PacketWrapper.create(playerInfoRemove, null, connection);
// Players
packet.write(Types.UUID_ARRAY, new UUID[] { entry });
send(packet);
}
@Override
public void updateListed(@NonNull UUID entry, boolean listed) {
sendInfoUpdate(Action.UPDATE_LISTED, entry, listed);
}
@Override
protected void writeAction(@NonNull PacketWrapper packet, @NonNull Action action) {
switch (action) {
case ADD_PLAYER:
packet.write(Types.PROFILE_ACTIONS_ENUM1_19_3, ADD_PLAYER);
break;
case UPDATE_DISPLAY_NAME:
packet.write(Types.PROFILE_ACTIONS_ENUM1_19_3, UPDATE_DISPLAY_NAME);
break;
case UPDATE_LATENCY:
packet.write(Types.PROFILE_ACTIONS_ENUM1_19_3, UPDATE_LATENCY);
break;
case UPDATE_GAME_MODE:
packet.write(Types.PROFILE_ACTIONS_ENUM1_19_3, UPDATE_GAME_MODE);
break;
case UPDATE_LISTED:
packet.write(Types.PROFILE_ACTIONS_ENUM1_19_3, UPDATE_LISTED);
break;
default:
throw new IllegalStateException("Cannot write " + action.name() + " for 1.19.3 packet");
}
}
@Override
protected void writeEntry(@NonNull PacketWrapper packet, @NonNull Entry entry) {
packet.write(Types.STRING, entry.getName());
if (entry.getSkin() == null) {
// Properties size
packet.write(Types.VAR_INT, 0);
} else {
// Properties size
packet.write(Types.VAR_INT, 1);
// Properties
packet.write(Types.STRING, entry.getName());
packet.write(Types.STRING, entry.getSkin().getValue());
packet.write(Types.OPTIONAL_STRING, entry.getSkin().getSignature());
}
packet.write(Types.BOOLEAN, false); // No chat session data
packet.write(Types.VAR_INT, entry.getGameMode());
packet.write(Types.BOOLEAN, entry.isListed());
packet.write(Types.VAR_INT, entry.getLatency());
writeOptionalComponent(packet, entry.getDisplayName());
}
}
@@ -1,92 +0,0 @@
package me.neznamy.tab.platforms.bukkit.provider.viaversion;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.PacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.Protocol1_21To1_21_2;
import lombok.NonNull;
import me.neznamy.chat.component.TabComponent;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.BitSet;
import java.util.UUID;
/**
* TabList handler using ViaVersion packets,
* to unlock +1.21.2 player features on pre 1.21.2 servers.
*/
public class ViaTabList1212 extends ViaTabList1193 {
private static final BitSet ADD_PLAYER = bitSet(7, 0, 7);
//private static final BitSet INITIALIZE_CHAT = bitSet(7, 1);
private static final BitSet UPDATE_GAME_MODE = bitSet(7, 2);
private static final BitSet UPDATE_LISTED = bitSet(7, 3);
private static final BitSet UPDATE_LATENCY = bitSet(7, 4);
private static final BitSet UPDATE_DISPLAY_NAME = bitSet(7, 5);
private static final BitSet UPDATE_LIST_ORDER = bitSet(7, 6);
/**
* Constructs new instance with given parameters.
*
* @param player
* Player this tablist will belong to
*/
public ViaTabList1212(@NotNull BukkitTabPlayer player) {
super(player, Protocol1_21To1_21_2.class, ClientboundPackets1_21_2.PLAYER_INFO_REMOVE, ClientboundPackets1_21_2.PLAYER_INFO_UPDATE, ClientboundPackets1_21_2.TAB_LIST);
}
protected ViaTabList1212(@NonNull BukkitTabPlayer player, @NonNull Class<? extends Protocol> protocol, @Nullable PacketType playerInfoRemove, @NonNull PacketType playerInfoUpdate, @NonNull PacketType tabList) {
super(player, protocol, playerInfoRemove, playerInfoUpdate, tabList);
}
@Override
public void updateListOrder(@NonNull UUID entry, int listOrder) {
sendInfoUpdate(Action.UPDATE_LIST_ORDER, entry, listOrder);
}
@Override
protected void writeComponent(@NonNull PacketWrapper packet, @NonNull TabComponent component) {
packet.write(Types.TAG, component.toViaVersionTag());
}
@Override
protected void writeOptionalComponent(@NonNull PacketWrapper packet, @Nullable TabComponent component) {
packet.write(Types.OPTIONAL_TAG, component == null ? null : component.toViaVersionTag());
}
@Override
protected void writeAction(@NonNull PacketWrapper packet, @NonNull Action action) {
switch (action) {
case ADD_PLAYER:
packet.write(Types.PROFILE_ACTIONS_ENUM1_21_2, ADD_PLAYER);
break;
case UPDATE_DISPLAY_NAME:
packet.write(Types.PROFILE_ACTIONS_ENUM1_21_2, UPDATE_DISPLAY_NAME);
break;
case UPDATE_LATENCY:
packet.write(Types.PROFILE_ACTIONS_ENUM1_21_2, UPDATE_LATENCY);
break;
case UPDATE_GAME_MODE:
packet.write(Types.PROFILE_ACTIONS_ENUM1_21_2, UPDATE_GAME_MODE);
break;
case UPDATE_LISTED:
packet.write(Types.PROFILE_ACTIONS_ENUM1_21_2, UPDATE_LISTED);
break;
case UPDATE_LIST_ORDER:
packet.write(Types.PROFILE_ACTIONS_ENUM1_21_2, UPDATE_LIST_ORDER);
break;
default:
throw new IllegalStateException("Cannot write " + action.name() + " for 1.21.2 packet");
}
}
@Override
protected void writeEntry(@NonNull PacketWrapper packet, @NonNull Entry entry) {
super.writeEntry(packet, entry);
packet.write(Types.VAR_INT, entry.getListOrder());
}
}
@@ -1,78 +0,0 @@
package me.neznamy.tab.platforms.bukkit.provider.viaversion;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.Protocol1_21_2To1_21_4;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
import lombok.NonNull;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import org.jetbrains.annotations.NotNull;
import java.util.BitSet;
import java.util.UUID;
/**
* TabList handler using ViaVersion packets,
* to unlock +1.21.4 player features on pre 1.21.4 servers.
*/
public class ViaTabList1214 extends ViaTabList1212 {
private static final BitSet ADD_PLAYER = bitSet(8, 0, 8);
//private static final BitSet INITIALIZE_CHAT = bitSet(8, 1);
private static final BitSet UPDATE_GAME_MODE = bitSet(8, 2);
private static final BitSet UPDATE_LISTED = bitSet(8, 3);
private static final BitSet UPDATE_LATENCY = bitSet(8, 4);
private static final BitSet UPDATE_DISPLAY_NAME = bitSet(8, 5);
private static final BitSet UPDATE_LIST_ORDER = bitSet(8, 6);
private static final BitSet UPDATE_HAT = bitSet(8, 7);
/**
* Constructs new instance with given parameters.
*
* @param player
* Player this tablist will belong to
*/
public ViaTabList1214(@NotNull BukkitTabPlayer player) {
super(player, Protocol1_21_2To1_21_4.class, ClientboundPackets1_21_2.PLAYER_INFO_REMOVE, ClientboundPackets1_21_2.PLAYER_INFO_UPDATE, ClientboundPackets1_21_2.TAB_LIST);
}
@Override
public void updateHat(@NonNull UUID entry, boolean showHat) {
sendInfoUpdate(Action.UPDATE_HAT, entry, showHat);
}
@Override
protected void writeAction(@NonNull PacketWrapper packet, @NonNull Action action) {
switch (action) {
case ADD_PLAYER:
packet.write(Types.PROFILE_ACTIONS_ENUM1_21_4, ADD_PLAYER);
break;
case UPDATE_DISPLAY_NAME:
packet.write(Types.PROFILE_ACTIONS_ENUM1_21_4, UPDATE_DISPLAY_NAME);
break;
case UPDATE_LATENCY:
packet.write(Types.PROFILE_ACTIONS_ENUM1_21_4, UPDATE_LATENCY);
break;
case UPDATE_GAME_MODE:
packet.write(Types.PROFILE_ACTIONS_ENUM1_21_4, UPDATE_GAME_MODE);
break;
case UPDATE_LISTED:
packet.write(Types.PROFILE_ACTIONS_ENUM1_21_4, UPDATE_LISTED);
break;
case UPDATE_LIST_ORDER:
packet.write(Types.PROFILE_ACTIONS_ENUM1_21_4, UPDATE_LIST_ORDER);
break;
case UPDATE_HAT:
packet.write(Types.PROFILE_ACTIONS_ENUM1_21_4, UPDATE_HAT);
break;
default:
throw new IllegalStateException("Cannot write " + action.name() + " for 1.21.4 packet");
}
}
@Override
protected void writeEntry(@NonNull PacketWrapper packet, @NonNull Entry entry) {
super.writeEntry(packet, entry);
packet.write(Types.BOOLEAN, entry.isShowHat());
}
}
@@ -1,65 +0,0 @@
package me.neznamy.tab.platforms.bukkit.provider.viaversion;
import lombok.RequiredArgsConstructor;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.shared.ProtocolVersion;
import me.neznamy.tab.shared.platform.Scoreboard;
import me.neznamy.tab.shared.platform.TabList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;
/**
* Implementation for sending new features on old servers using ViaVersion API.
* If no implementation is required for a player, {@code null} is returned.
*/
@RequiredArgsConstructor
public class ViaVersionProvider {
/** Map of tablist implementations by each new version */
private static final Map<ProtocolVersion, Function<BukkitTabPlayer, TabList>> TABLIST_IMPLEMENTATIONS = new LinkedHashMap<>();
/** Map of scoreboard implementations by each new version */
private static final Map<ProtocolVersion, Function<BukkitTabPlayer, Scoreboard>> SCOREBOARD_IMPLEMENTATIONS = new LinkedHashMap<>();
static {
TABLIST_IMPLEMENTATIONS.put(ProtocolVersion.V1_21_4, ViaTabList1214::new);
TABLIST_IMPLEMENTATIONS.put(ProtocolVersion.V1_21_2, ViaTabList1212::new);
TABLIST_IMPLEMENTATIONS.put(ProtocolVersion.V1_19_3, ViaTabList1193::new);
TABLIST_IMPLEMENTATIONS.put(ProtocolVersion.V1_16, ViaTabList116::new);
SCOREBOARD_IMPLEMENTATIONS.put(ProtocolVersion.V1_20_3, ViaScoreboard1203::new);
SCOREBOARD_IMPLEMENTATIONS.put(ProtocolVersion.V1_16, ViaScoreboard116::new);
SCOREBOARD_IMPLEMENTATIONS.put(ProtocolVersion.V1_13, ViaScoreboard113::new);
}
@NotNull
private final ProtocolVersion serverVersion;
@Nullable
public Scoreboard newScoreboard(@NotNull BukkitTabPlayer player) {
int serverVer = serverVersion.getNetworkId();
int playerVer = player.getVersion().getNetworkId();
for (Map.Entry<ProtocolVersion, Function<BukkitTabPlayer, Scoreboard>> entry : SCOREBOARD_IMPLEMENTATIONS.entrySet()) {
if (serverVer < entry.getKey().getNetworkId() && playerVer >= entry.getKey().getNetworkId()) {
return entry.getValue().apply(player);
}
}
return null;
}
@Nullable
public TabList newTabList(@NotNull BukkitTabPlayer player) {
int serverVer = serverVersion.getNetworkId();
int playerVer = player.getVersion().getNetworkId();
for (Map.Entry<ProtocolVersion, Function<BukkitTabPlayer, TabList>> entry : TABLIST_IMPLEMENTATIONS.entrySet()) {
if (serverVer < entry.getKey().getNetworkId() && playerVer >= entry.getKey().getNetworkId()) {
return entry.getValue().apply(player);
}
}
return null;
}
}
-3
View File
@@ -6,11 +6,8 @@ api-version: 1.13 # Defining to avoid legacy plugin warn
load: POSTWORLD
author: @author@
website: "@website@"
depend: []
softdepend: [PlaceholderAPI, LuckPerms, LibsDisguises, ViaVersion, ViaRewind, floodgate, Vault]
loadbefore: []
prefix: TAB
libraries: []
folia-supported: true
commands:
tab:
@@ -2,12 +2,9 @@ package me.neznamy.tab.platforms.bukkit.v1_12_R1;
import io.netty.channel.Channel;
import lombok.Getter;
import lombok.NonNull;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.platforms.bukkit.provider.ComponentConverter;
import me.neznamy.tab.platforms.bukkit.provider.ImplementationProvider;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaScoreboard;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaTabList;
import me.neznamy.tab.shared.platform.Scoreboard;
import me.neznamy.tab.shared.platform.TabList;
import me.neznamy.tab.shared.util.function.FunctionWithException;
@@ -29,16 +26,6 @@ public class NMSImplementationProvider implements ImplementationProvider {
return new NMSPacketScoreboard(player);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaScoreboard scoreboard) {
NMSPacketScoreboard.onPacketSend(packet, scoreboard);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaTabList tabList) {
NMSPacketTabList.onPacketSend(packet, tabList);
}
@Override
@NotNull
public TabList newTabList(@NotNull BukkitTabPlayer player) {
@@ -34,26 +34,6 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
private static final Field DisplayObjective_OBJECTIVE_NAME = ReflectionUtils.getOnlyField(PacketPlayOutScoreboardDisplayObjective.class, String.class);
private static final Field DisplayObjective_POSITION = ReflectionUtils.getOnlyField(PacketPlayOutScoreboardDisplayObjective.class, int.class);
@SneakyThrows
@SuppressWarnings("unchecked")
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), DisplayObjective_POSITION.getInt(packet),
(String) DisplayObjective_OBJECTIVE_NAME.get(packet));
}
if (packet instanceof PacketPlayOutScoreboardObjective) {
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(),
Objective_METHOD.getInt(packet), (String) Objective_OBJECTIVE_NAME.get(packet));
}
if (packet instanceof PacketPlayOutScoreboardTeam) {
int action = TeamPacket_ACTION.getInt(packet);
if (action == TeamAction.UPDATE) return;
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
if (players == null) players = Collections.emptyList();
TeamPacket_PLAYERS.set(packet, scoreboard.onTeamPacket(action, (String) TeamPacket_NAME.get(packet), players));
}
}
/**
* Constructs new instance with given player.
*
@@ -67,7 +47,7 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
@Override
public void registerObjective(@NonNull Objective objective) {
ScoreboardObjective obj = new ScoreboardObjective(dummyScoreboard, objective.getName(), IScoreboardCriteria.b);
obj.setDisplayName(cutTo(objective.getTitle().toLegacyText(), Limitations.SCOREBOARD_TITLE_PRE_1_13));
obj.setDisplayName(maybeCut(objective.getTitle().toLegacyText(), Limitations.SCOREBOARD_TITLE_PRE_1_13));
obj.a(IScoreboardCriteria.EnumScoreboardHealthDisplay.valueOf(objective.getHealthDisplay().name()));
objective.setPlatformObjective(obj);
sendPacket(new PacketPlayOutScoreboardObjective(obj, ObjectiveAction.REGISTER));
@@ -86,7 +66,7 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
@Override
public void updateObjective(@NonNull Objective objective) {
ScoreboardObjective obj = (ScoreboardObjective) objective.getPlatformObjective();
obj.setDisplayName(cutTo(objective.getTitle().toLegacyText(), Limitations.SCOREBOARD_TITLE_PRE_1_13));
obj.setDisplayName(maybeCut(objective.getTitle().toLegacyText(), Limitations.SCOREBOARD_TITLE_PRE_1_13));
obj.a(IScoreboardCriteria.EnumScoreboardHealthDisplay.valueOf(objective.getHealthDisplay().name()));
sendPacket(new PacketPlayOutScoreboardObjective(obj, ObjectiveAction.UPDATE));
}
@@ -134,13 +114,29 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
t.setCanSeeFriendlyInvisibles((team.getOptions() & 0x02) != 0);
t.setNameTagVisibility(visibilities[team.getVisibility().ordinal()]);
t.setCollisionRule(collisions[team.getCollision().ordinal()]);
t.setPrefix(cutTo(team.getPrefix().toLegacyText(), Limitations.TEAM_PREFIX_SUFFIX_PRE_1_13));
t.setSuffix(cutTo(team.getSuffix().toLegacyText(), Limitations.TEAM_PREFIX_SUFFIX_PRE_1_13));
t.setPrefix(maybeCut(team.getPrefix().toLegacyText(), Limitations.TEAM_PREFIX_SUFFIX_PRE_1_13));
t.setSuffix(maybeCut(team.getSuffix().toLegacyText(), Limitations.TEAM_PREFIX_SUFFIX_PRE_1_13));
}
@Override
@SneakyThrows
@SuppressWarnings("unchecked")
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
TAB.getInstance().getFeatureManager().onDisplayObjective(player, DisplayObjective_POSITION.getInt(packet),
(String) DisplayObjective_OBJECTIVE_NAME.get(packet));
}
if (packet instanceof PacketPlayOutScoreboardObjective) {
TAB.getInstance().getFeatureManager().onObjective(player,
Objective_METHOD.getInt(packet), (String) Objective_OBJECTIVE_NAME.get(packet));
}
if (packet instanceof PacketPlayOutScoreboardTeam) {
int action = TeamPacket_ACTION.getInt(packet);
if (action == TeamAction.UPDATE) return;
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
if (players == null) players = Collections.emptyList();
TeamPacket_PLAYERS.set(packet, onTeamPacket(action, (String) TeamPacket_NAME.get(packet), players));
}
}
/**
@@ -152,4 +148,12 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
private void sendPacket(@NotNull Packet<?> packet) {
((CraftPlayer)player.getPlayer()).getHandle().playerConnection.sendPacket(packet);
}
@NotNull
private String maybeCut(@NonNull String string, int length) {
if (player.getVersion().getMinorVersion() < 13 || TAB.getInstance().getConfiguration().getConfig().isPacketEventsCompensation()) {
return cutTo(string, length);
}
return string;
}
}
@@ -42,31 +42,6 @@ public class NMSPacketTabList extends TrackedTabList<BukkitTabPlayer> {
private static final Field HEADER = ReflectionUtils.getFields(PacketPlayOutPlayerListHeaderFooter.class, IChatBaseComponent.class).get(0);
private static final Field FOOTER = ReflectionUtils.getFields(PacketPlayOutPlayerListHeaderFooter.class, IChatBaseComponent.class).get(1);
@SneakyThrows
@SuppressWarnings("unchecked")
public static void onPacketSend(@NonNull Object packet, @NonNull TrackedTabList<BukkitTabPlayer> tabList) {
if (!(packet instanceof PacketPlayOutPlayerInfo)) return;
EnumPlayerInfoAction action = (EnumPlayerInfoAction) ACTION.get(packet);
for (Object nmsData : (List<Object>) PLAYERS.get(packet)) {
GameProfile profile = (GameProfile) PlayerInfoData_Profile.get(nmsData);
UUID id = profile.getId();
if (action == EnumPlayerInfoAction.UPDATE_DISPLAY_NAME || action == EnumPlayerInfoAction.ADD_PLAYER) {
TabComponent expectedName = tabList.getExpectedDisplayNames().get(id);
if (expectedName != null) PlayerInfoData_DisplayName.set(nmsData, expectedName.convert());
}
if (action == EnumPlayerInfoAction.UPDATE_LATENCY || action == EnumPlayerInfoAction.ADD_PLAYER) {
int oldLatency = PlayerInfoData_Latency.getInt(nmsData);
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(tabList.getPlayer(), id, oldLatency);
if (oldLatency != newLatency) {
PlayerInfoData_Latency.set(nmsData, newLatency);
}
}
if (action == EnumPlayerInfoAction.ADD_PLAYER) {
TAB.getInstance().getFeatureManager().onEntryAdd(tabList.getPlayer(), id, profile.getName());
}
}
}
/**
* Constructs new instance.
*
@@ -143,8 +118,29 @@ public class NMSPacketTabList extends TrackedTabList<BukkitTabPlayer> {
}
@Override
@SneakyThrows
@SuppressWarnings("unchecked")
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (!(packet instanceof PacketPlayOutPlayerInfo)) return;
EnumPlayerInfoAction action = (EnumPlayerInfoAction) ACTION.get(packet);
for (Object nmsData : (List<Object>) PLAYERS.get(packet)) {
GameProfile profile = (GameProfile) PlayerInfoData_Profile.get(nmsData);
UUID id = profile.getId();
if (action == EnumPlayerInfoAction.UPDATE_DISPLAY_NAME || action == EnumPlayerInfoAction.ADD_PLAYER) {
TabComponent expectedName = getExpectedDisplayNames().get(id);
if (expectedName != null) PlayerInfoData_DisplayName.set(nmsData, expectedName.convert());
}
if (action == EnumPlayerInfoAction.UPDATE_LATENCY || action == EnumPlayerInfoAction.ADD_PLAYER) {
int oldLatency = PlayerInfoData_Latency.getInt(nmsData);
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(player, id, oldLatency);
if (oldLatency != newLatency) {
PlayerInfoData_Latency.set(nmsData, newLatency);
}
}
if (action == EnumPlayerInfoAction.ADD_PLAYER) {
TAB.getInstance().getFeatureManager().onEntryAdd(player, id, profile.getName());
}
}
}
@SneakyThrows
@@ -2,12 +2,9 @@ package me.neznamy.tab.platforms.bukkit.v1_16_R3;
import io.netty.channel.Channel;
import lombok.Getter;
import lombok.NonNull;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.platforms.bukkit.provider.ComponentConverter;
import me.neznamy.tab.platforms.bukkit.provider.ImplementationProvider;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaScoreboard;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaTabList;
import me.neznamy.tab.shared.platform.Scoreboard;
import me.neznamy.tab.shared.platform.TabList;
import me.neznamy.tab.shared.util.function.FunctionWithException;
@@ -29,16 +26,6 @@ public class NMSImplementationProvider implements ImplementationProvider {
return new NMSPacketScoreboard(player);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaScoreboard scoreboard) {
NMSPacketScoreboard.onPacketSend(packet, scoreboard);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaTabList tabList) {
NMSPacketTabList.onPacketSend(packet, tabList);
}
@Override
@NotNull
public TabList newTabList(@NotNull BukkitTabPlayer player) {
@@ -33,26 +33,6 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
private static final Field DisplayObjective_OBJECTIVE_NAME = ReflectionUtils.getOnlyField(PacketPlayOutScoreboardDisplayObjective.class, String.class);
private static final Field DisplayObjective_POSITION = ReflectionUtils.getOnlyField(PacketPlayOutScoreboardDisplayObjective.class, int.class);
@SneakyThrows
@SuppressWarnings("unchecked")
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), DisplayObjective_POSITION.getInt(packet),
(String) DisplayObjective_OBJECTIVE_NAME.get(packet));
}
if (packet instanceof PacketPlayOutScoreboardObjective) {
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(),
Objective_METHOD.getInt(packet), (String) Objective_OBJECTIVE_NAME.get(packet));
}
if (packet instanceof PacketPlayOutScoreboardTeam) {
int action = TeamPacket_ACTION.getInt(packet);
if (action == TeamAction.UPDATE) return;
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
if (players == null) players = Collections.emptyList();
TeamPacket_PLAYERS.set(packet, scoreboard.onTeamPacket(action, (String) TeamPacket_NAME.get(packet), players));
}
}
/**
* Constructs new instance with given player.
*
@@ -154,8 +134,24 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
}
@Override
@SneakyThrows
@SuppressWarnings("unchecked")
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
TAB.getInstance().getFeatureManager().onDisplayObjective(player, DisplayObjective_POSITION.getInt(packet),
(String) DisplayObjective_OBJECTIVE_NAME.get(packet));
}
if (packet instanceof PacketPlayOutScoreboardObjective) {
TAB.getInstance().getFeatureManager().onObjective(player,
Objective_METHOD.getInt(packet), (String) Objective_OBJECTIVE_NAME.get(packet));
}
if (packet instanceof PacketPlayOutScoreboardTeam) {
int action = TeamPacket_ACTION.getInt(packet);
if (action == TeamAction.UPDATE) return;
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
if (players == null) players = Collections.emptyList();
TeamPacket_PLAYERS.set(packet, onTeamPacket(action, (String) TeamPacket_NAME.get(packet), players));
}
}
/**
@@ -42,31 +42,6 @@ public class NMSPacketTabList extends TrackedTabList<BukkitTabPlayer> {
private static final Field HEADER = ReflectionUtils.getFields(PacketPlayOutPlayerListHeaderFooter.class, IChatBaseComponent.class).get(0);
private static final Field FOOTER = ReflectionUtils.getFields(PacketPlayOutPlayerListHeaderFooter.class, IChatBaseComponent.class).get(1);
@SneakyThrows
@SuppressWarnings("unchecked")
public static void onPacketSend(@NonNull Object packet, @NonNull TrackedTabList<BukkitTabPlayer> tabList) {
if (!(packet instanceof PacketPlayOutPlayerInfo)) return;
EnumPlayerInfoAction action = (EnumPlayerInfoAction) ACTION.get(packet);
for (Object nmsData : (List<Object>) PLAYERS.get(packet)) {
GameProfile profile = (GameProfile) PlayerInfoData_Profile.get(nmsData);
UUID id = profile.getId();
if (action == EnumPlayerInfoAction.UPDATE_DISPLAY_NAME || action == EnumPlayerInfoAction.ADD_PLAYER) {
TabComponent expectedName = tabList.getExpectedDisplayNames().get(id);
if (expectedName != null) PlayerInfoData_DisplayName.set(nmsData, expectedName.convert());
}
if (action == EnumPlayerInfoAction.UPDATE_LATENCY || action == EnumPlayerInfoAction.ADD_PLAYER) {
int oldLatency = PlayerInfoData_Latency.getInt(nmsData);
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(tabList.getPlayer(), id, oldLatency);
if (oldLatency != newLatency) {
PlayerInfoData_Latency.set(nmsData, newLatency);
}
}
if (action == EnumPlayerInfoAction.ADD_PLAYER) {
TAB.getInstance().getFeatureManager().onEntryAdd(tabList.getPlayer(), id, profile.getName());
}
}
}
/**
* Constructs new instance.
*
@@ -143,8 +118,29 @@ public class NMSPacketTabList extends TrackedTabList<BukkitTabPlayer> {
}
@Override
@SneakyThrows
@SuppressWarnings("unchecked")
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (!(packet instanceof PacketPlayOutPlayerInfo)) return;
EnumPlayerInfoAction action = (EnumPlayerInfoAction) ACTION.get(packet);
for (Object nmsData : (List<Object>) PLAYERS.get(packet)) {
GameProfile profile = (GameProfile) PlayerInfoData_Profile.get(nmsData);
UUID id = profile.getId();
if (action == EnumPlayerInfoAction.UPDATE_DISPLAY_NAME || action == EnumPlayerInfoAction.ADD_PLAYER) {
TabComponent expectedName = getExpectedDisplayNames().get(id);
if (expectedName != null) PlayerInfoData_DisplayName.set(nmsData, expectedName.convert());
}
if (action == EnumPlayerInfoAction.UPDATE_LATENCY || action == EnumPlayerInfoAction.ADD_PLAYER) {
int oldLatency = PlayerInfoData_Latency.getInt(nmsData);
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(player, id, oldLatency);
if (oldLatency != newLatency) {
PlayerInfoData_Latency.set(nmsData, newLatency);
}
}
if (action == EnumPlayerInfoAction.ADD_PLAYER) {
TAB.getInstance().getFeatureManager().onEntryAdd(player, id, profile.getName());
}
}
}
@SneakyThrows
@@ -2,12 +2,9 @@ package me.neznamy.tab.platforms.bukkit.v1_17_R1;
import io.netty.channel.Channel;
import lombok.Getter;
import lombok.NonNull;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.platforms.bukkit.provider.ComponentConverter;
import me.neznamy.tab.platforms.bukkit.provider.ImplementationProvider;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaScoreboard;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaTabList;
import me.neznamy.tab.shared.platform.Scoreboard;
import me.neznamy.tab.shared.platform.TabList;
import me.neznamy.tab.shared.util.function.FunctionWithException;
@@ -29,16 +26,6 @@ public class NMSImplementationProvider implements ImplementationProvider {
return new NMSPacketScoreboard(player);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaScoreboard scoreboard) {
NMSPacketScoreboard.onPacketSend(packet, scoreboard);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaTabList tabList) {
NMSPacketTabList.onPacketSend(packet, tabList);
}
@Override
@NotNull
public TabList newTabList(@NotNull BukkitTabPlayer player) {
@@ -36,46 +36,6 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
private static final Field TeamPacket_PLAYERS = ReflectionUtils.getOnlyField(PacketPlayOutScoreboardTeam.class, Collection.class);
@SneakyThrows
@SuppressWarnings("unchecked")
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
TAB.getInstance().getFeatureManager().onDisplayObjective(
scoreboard.getPlayer(),
((PacketPlayOutScoreboardDisplayObjective)packet).b(),
((PacketPlayOutScoreboardDisplayObjective)packet).c()
);
}
if (packet instanceof PacketPlayOutScoreboardObjective) {
TAB.getInstance().getFeatureManager().onObjective(
scoreboard.getPlayer(),
((PacketPlayOutScoreboardObjective)packet).d(),
((PacketPlayOutScoreboardObjective)packet).b()
);
}
if (packet instanceof PacketPlayOutScoreboardTeam) {
int action = getMethod((PacketPlayOutScoreboardTeam) packet);
if (action == TeamAction.UPDATE) return;
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
if (players == null) players = Collections.emptyList();
TeamPacket_PLAYERS.set(packet, scoreboard.onTeamPacket(action, ((PacketPlayOutScoreboardTeam)packet).d(), players));
}
}
private static int getMethod(@NonNull PacketPlayOutScoreboardTeam team) {
if (team.c() == PacketPlayOutScoreboardTeam.a.a) {
return 0;
} else if (team.c() == PacketPlayOutScoreboardTeam.a.b) {
return 1;
} else if (team.b() == PacketPlayOutScoreboardTeam.a.a) {
return 3;
} else if (team.b() == PacketPlayOutScoreboardTeam.a.b) {
return 4;
} else {
return 2;
}
}
/**
* Constructs new instance with given player.
*
@@ -177,8 +137,44 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
}
@Override
@SneakyThrows
@SuppressWarnings("unchecked")
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
TAB.getInstance().getFeatureManager().onDisplayObjective(
player,
((PacketPlayOutScoreboardDisplayObjective)packet).b(),
((PacketPlayOutScoreboardDisplayObjective)packet).c()
);
}
if (packet instanceof PacketPlayOutScoreboardObjective) {
TAB.getInstance().getFeatureManager().onObjective(
player,
((PacketPlayOutScoreboardObjective)packet).d(),
((PacketPlayOutScoreboardObjective)packet).b()
);
}
if (packet instanceof PacketPlayOutScoreboardTeam) {
int action = getMethod((PacketPlayOutScoreboardTeam) packet);
if (action == TeamAction.UPDATE) return;
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
if (players == null) players = Collections.emptyList();
TeamPacket_PLAYERS.set(packet, onTeamPacket(action, ((PacketPlayOutScoreboardTeam)packet).d(), players));
}
}
private int getMethod(@NonNull PacketPlayOutScoreboardTeam team) {
if (team.c() == PacketPlayOutScoreboardTeam.a.a) {
return 0;
} else if (team.c() == PacketPlayOutScoreboardTeam.a.b) {
return 1;
} else if (team.b() == PacketPlayOutScoreboardTeam.a.a) {
return 3;
} else if (team.b() == PacketPlayOutScoreboardTeam.a.b) {
return 4;
} else {
return 2;
}
}
/**
@@ -61,6 +61,14 @@ public class NMSPacketTabList extends TrackedTabList<BukkitTabPlayer> {
}
}
@Nullable
public static Skin getSkin(@NonNull BukkitTabPlayer player) {
Collection<Property> properties = ((CraftPlayer)player.getPlayer()).getProfile().getProperties().get(TEXTURES_PROPERTY);
if (properties.isEmpty()) return null; // Offline mode
Property property = properties.iterator().next();
return new Skin(property.getValue(), property.getSignature());
}
/**
* Constructs new instance.
*
@@ -127,10 +135,7 @@ public class NMSPacketTabList extends TrackedTabList<BukkitTabPlayer> {
@Override
@Nullable
public Skin getSkin() {
Collection<Property> properties = ((CraftPlayer)player.getPlayer()).getProfile().getProperties().get(TEXTURES_PROPERTY);
if (properties.isEmpty()) return null; // Offline mode
Property property = properties.iterator().next();
return new Skin(property.getValue(), property.getSignature());
return getSkin(player);
}
@Override
@@ -2,12 +2,9 @@ package me.neznamy.tab.platforms.bukkit.v1_18_R2;
import io.netty.channel.Channel;
import lombok.Getter;
import lombok.NonNull;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.platforms.bukkit.provider.ComponentConverter;
import me.neznamy.tab.platforms.bukkit.provider.ImplementationProvider;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaScoreboard;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaTabList;
import me.neznamy.tab.shared.platform.Scoreboard;
import me.neznamy.tab.shared.platform.TabList;
import me.neznamy.tab.shared.util.function.FunctionWithException;
@@ -29,16 +26,6 @@ public class NMSImplementationProvider implements ImplementationProvider {
return new NMSPacketScoreboard(player);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaScoreboard scoreboard) {
NMSPacketScoreboard.onPacketSend(packet, scoreboard);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaTabList tabList) {
NMSPacketTabList.onPacketSend(packet, tabList);
}
@Override
@NotNull
public TabList newTabList(@NotNull BukkitTabPlayer player) {
@@ -37,46 +37,6 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
private static final Field TeamPacket_PLAYERS = ReflectionUtils.getOnlyField(PacketPlayOutScoreboardTeam.class, Collection.class);
@SneakyThrows
@SuppressWarnings("unchecked")
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
TAB.getInstance().getFeatureManager().onDisplayObjective(
scoreboard.getPlayer(),
((PacketPlayOutScoreboardDisplayObjective)packet).b(),
((PacketPlayOutScoreboardDisplayObjective)packet).c()
);
}
if (packet instanceof PacketPlayOutScoreboardObjective) {
TAB.getInstance().getFeatureManager().onObjective(
scoreboard.getPlayer(),
((PacketPlayOutScoreboardObjective)packet).d(),
((PacketPlayOutScoreboardObjective)packet).b()
);
}
if (packet instanceof PacketPlayOutScoreboardTeam) {
int action = getMethod((PacketPlayOutScoreboardTeam) packet);
if (action == TeamAction.UPDATE) return;
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
if (players == null) players = Collections.emptyList();
TeamPacket_PLAYERS.set(packet, scoreboard.onTeamPacket(action, ((PacketPlayOutScoreboardTeam)packet).d(), players));
}
}
private static int getMethod(@NonNull PacketPlayOutScoreboardTeam team) {
if (team.c() == PacketPlayOutScoreboardTeam.a.a) {
return 0;
} else if (team.c() == PacketPlayOutScoreboardTeam.a.b) {
return 1;
} else if (team.b() == PacketPlayOutScoreboardTeam.a.a) {
return 3;
} else if (team.b() == PacketPlayOutScoreboardTeam.a.b) {
return 4;
} else {
return 2;
}
}
/**
* Constructs new instance with given player.
*
@@ -178,8 +138,44 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
}
@Override
@SneakyThrows
@SuppressWarnings("unchecked")
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
TAB.getInstance().getFeatureManager().onDisplayObjective(
player,
((PacketPlayOutScoreboardDisplayObjective)packet).b(),
((PacketPlayOutScoreboardDisplayObjective)packet).c()
);
}
if (packet instanceof PacketPlayOutScoreboardObjective) {
TAB.getInstance().getFeatureManager().onObjective(
player,
((PacketPlayOutScoreboardObjective)packet).d(),
((PacketPlayOutScoreboardObjective)packet).b()
);
}
if (packet instanceof PacketPlayOutScoreboardTeam) {
int action = getMethod((PacketPlayOutScoreboardTeam) packet);
if (action == TeamAction.UPDATE) return;
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
if (players == null) players = Collections.emptyList();
TeamPacket_PLAYERS.set(packet, onTeamPacket(action, ((PacketPlayOutScoreboardTeam)packet).d(), players));
}
}
private int getMethod(@NonNull PacketPlayOutScoreboardTeam team) {
if (team.c() == PacketPlayOutScoreboardTeam.a.a) {
return 0;
} else if (team.c() == PacketPlayOutScoreboardTeam.a.b) {
return 1;
} else if (team.b() == PacketPlayOutScoreboardTeam.a.a) {
return 3;
} else if (team.b() == PacketPlayOutScoreboardTeam.a.b) {
return 4;
} else {
return 2;
}
}
/**
@@ -37,30 +37,6 @@ public class NMSPacketTabList extends TrackedTabList<BukkitTabPlayer> {
private static final Field PlayerInfoData_Latency = ReflectionUtils.getFields(PlayerInfoData.class, int.class).get(0);
private static final Field PlayerInfoData_DisplayName = ReflectionUtils.getOnlyField(PlayerInfoData.class, IChatBaseComponent.class);
@SneakyThrows
public static void onPacketSend(@NonNull Object packet, @NonNull TrackedTabList<BukkitTabPlayer> tabList) {
if (!(packet instanceof PacketPlayOutPlayerInfo)) return;
EnumPlayerInfoAction action = ((PacketPlayOutPlayerInfo)packet).c();
for (PlayerInfoData nmsData : ((PacketPlayOutPlayerInfo)packet).b()) {
GameProfile profile = nmsData.a();
UUID id = profile.getId();
if (action == EnumPlayerInfoAction.d || action == EnumPlayerInfoAction.a) {
TabComponent expectedName = tabList.getExpectedDisplayNames().get(id);
if (expectedName != null) PlayerInfoData_DisplayName.set(nmsData, expectedName.convert());
}
if (action == EnumPlayerInfoAction.c || action == EnumPlayerInfoAction.a) {
int oldLatency = nmsData.b();
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(tabList.getPlayer(), id, oldLatency);
if (oldLatency != newLatency) {
PlayerInfoData_Latency.set(nmsData, newLatency);
}
}
if (action == EnumPlayerInfoAction.a) {
TAB.getInstance().getFeatureManager().onEntryAdd(tabList.getPlayer(), id, profile.getName());
}
}
}
/**
* Constructs new instance.
*
@@ -134,8 +110,28 @@ public class NMSPacketTabList extends TrackedTabList<BukkitTabPlayer> {
}
@Override
@SneakyThrows
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (!(packet instanceof PacketPlayOutPlayerInfo)) return;
EnumPlayerInfoAction action = ((PacketPlayOutPlayerInfo)packet).c();
for (PlayerInfoData nmsData : ((PacketPlayOutPlayerInfo)packet).b()) {
GameProfile profile = nmsData.a();
UUID id = profile.getId();
if (action == EnumPlayerInfoAction.d || action == EnumPlayerInfoAction.a) {
TabComponent expectedName = getExpectedDisplayNames().get(id);
if (expectedName != null) PlayerInfoData_DisplayName.set(nmsData, expectedName.convert());
}
if (action == EnumPlayerInfoAction.c || action == EnumPlayerInfoAction.a) {
int oldLatency = nmsData.b();
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(player, id, oldLatency);
if (oldLatency != newLatency) {
PlayerInfoData_Latency.set(nmsData, newLatency);
}
}
if (action == EnumPlayerInfoAction.a) {
TAB.getInstance().getFeatureManager().onEntryAdd(player, id, profile.getName());
}
}
}
@SneakyThrows
@@ -2,12 +2,9 @@ package me.neznamy.tab.platforms.bukkit.v1_19_R1;
import io.netty.channel.Channel;
import lombok.Getter;
import lombok.NonNull;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.platforms.bukkit.provider.ComponentConverter;
import me.neznamy.tab.platforms.bukkit.provider.ImplementationProvider;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaScoreboard;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaTabList;
import me.neznamy.tab.shared.platform.Scoreboard;
import me.neznamy.tab.shared.platform.TabList;
import me.neznamy.tab.shared.util.function.FunctionWithException;
@@ -29,16 +26,6 @@ public class NMSImplementationProvider implements ImplementationProvider {
return new NMSPacketScoreboard(player);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaScoreboard scoreboard) {
NMSPacketScoreboard.onPacketSend(packet, scoreboard);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaTabList tabList) {
NMSPacketTabList.onPacketSend(packet, tabList);
}
@Override
@NotNull
public TabList newTabList(@NotNull BukkitTabPlayer player) {
@@ -37,46 +37,6 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
private static final Field TeamPacket_PLAYERS = ReflectionUtils.getOnlyField(PacketPlayOutScoreboardTeam.class, Collection.class);
@SneakyThrows
@SuppressWarnings("unchecked")
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
TAB.getInstance().getFeatureManager().onDisplayObjective(
scoreboard.getPlayer(),
((PacketPlayOutScoreboardDisplayObjective)packet).b(),
((PacketPlayOutScoreboardDisplayObjective)packet).c()
);
}
if (packet instanceof PacketPlayOutScoreboardObjective) {
TAB.getInstance().getFeatureManager().onObjective(
scoreboard.getPlayer(),
((PacketPlayOutScoreboardObjective)packet).d(),
((PacketPlayOutScoreboardObjective)packet).b()
);
}
if (packet instanceof PacketPlayOutScoreboardTeam) {
int action = getMethod((PacketPlayOutScoreboardTeam) packet);
if (action == TeamAction.UPDATE) return;
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
if (players == null) players = Collections.emptyList();
TeamPacket_PLAYERS.set(packet, scoreboard.onTeamPacket(action, ((PacketPlayOutScoreboardTeam)packet).d(), players));
}
}
private static int getMethod(@NonNull PacketPlayOutScoreboardTeam team) {
if (team.c() == PacketPlayOutScoreboardTeam.a.a) {
return 0;
} else if (team.c() == PacketPlayOutScoreboardTeam.a.b) {
return 1;
} else if (team.b() == PacketPlayOutScoreboardTeam.a.a) {
return 3;
} else if (team.b() == PacketPlayOutScoreboardTeam.a.b) {
return 4;
} else {
return 2;
}
}
/**
* Constructs new instance with given player.
*
@@ -178,8 +138,44 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
}
@Override
@SneakyThrows
@SuppressWarnings("unchecked")
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
TAB.getInstance().getFeatureManager().onDisplayObjective(
player,
((PacketPlayOutScoreboardDisplayObjective)packet).b(),
((PacketPlayOutScoreboardDisplayObjective)packet).c()
);
}
if (packet instanceof PacketPlayOutScoreboardObjective) {
TAB.getInstance().getFeatureManager().onObjective(
player,
((PacketPlayOutScoreboardObjective)packet).d(),
((PacketPlayOutScoreboardObjective)packet).b()
);
}
if (packet instanceof PacketPlayOutScoreboardTeam) {
int action = getMethod((PacketPlayOutScoreboardTeam) packet);
if (action == TeamAction.UPDATE) return;
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
if (players == null) players = Collections.emptyList();
TeamPacket_PLAYERS.set(packet, onTeamPacket(action, ((PacketPlayOutScoreboardTeam)packet).d(), players));
}
}
private int getMethod(@NonNull PacketPlayOutScoreboardTeam team) {
if (team.c() == PacketPlayOutScoreboardTeam.a.a) {
return 0;
} else if (team.c() == PacketPlayOutScoreboardTeam.a.b) {
return 1;
} else if (team.b() == PacketPlayOutScoreboardTeam.a.a) {
return 3;
} else if (team.b() == PacketPlayOutScoreboardTeam.a.b) {
return 4;
} else {
return 2;
}
}
/**
@@ -37,30 +37,6 @@ public class NMSPacketTabList extends TrackedTabList<BukkitTabPlayer> {
private static final Field PlayerInfoData_Latency = ReflectionUtils.getFields(PlayerInfoData.class, int.class).get(0);
private static final Field PlayerInfoData_DisplayName = ReflectionUtils.getOnlyField(PlayerInfoData.class, IChatBaseComponent.class);
@SneakyThrows
public static void onPacketSend(@NonNull Object packet, @NonNull TrackedTabList<BukkitTabPlayer> tabList) {
if (!(packet instanceof PacketPlayOutPlayerInfo)) return;
EnumPlayerInfoAction action = ((PacketPlayOutPlayerInfo)packet).c();
for (PlayerInfoData nmsData : ((PacketPlayOutPlayerInfo)packet).b()) {
GameProfile profile = nmsData.a();
UUID id = profile.getId();
if (action == EnumPlayerInfoAction.d || action == EnumPlayerInfoAction.a) {
TabComponent expectedName = tabList.getExpectedDisplayNames().get(id);
if (expectedName != null) PlayerInfoData_DisplayName.set(nmsData, expectedName.convert());
}
if (action == EnumPlayerInfoAction.c || action == EnumPlayerInfoAction.a) {
int oldLatency = nmsData.b();
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(tabList.getPlayer(), id, oldLatency);
if (oldLatency != newLatency) {
PlayerInfoData_Latency.set(nmsData, newLatency);
}
}
if (action == EnumPlayerInfoAction.a) {
TAB.getInstance().getFeatureManager().onEntryAdd(tabList.getPlayer(), id, profile.getName());
}
}
}
/**
* Constructs new instance.
*
@@ -134,8 +110,28 @@ public class NMSPacketTabList extends TrackedTabList<BukkitTabPlayer> {
}
@Override
@SneakyThrows
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (!(packet instanceof PacketPlayOutPlayerInfo)) return;
EnumPlayerInfoAction action = ((PacketPlayOutPlayerInfo)packet).c();
for (PlayerInfoData nmsData : ((PacketPlayOutPlayerInfo)packet).b()) {
GameProfile profile = nmsData.a();
UUID id = profile.getId();
if (action == EnumPlayerInfoAction.d || action == EnumPlayerInfoAction.a) {
TabComponent expectedName = getExpectedDisplayNames().get(id);
if (expectedName != null) PlayerInfoData_DisplayName.set(nmsData, expectedName.convert());
}
if (action == EnumPlayerInfoAction.c || action == EnumPlayerInfoAction.a) {
int oldLatency = nmsData.b();
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(player, id, oldLatency);
if (oldLatency != newLatency) {
PlayerInfoData_Latency.set(nmsData, newLatency);
}
}
if (action == EnumPlayerInfoAction.a) {
TAB.getInstance().getFeatureManager().onEntryAdd(player, id, profile.getName());
}
}
}
@SneakyThrows
@@ -2,12 +2,9 @@ package me.neznamy.tab.platforms.bukkit.v1_8_R3;
import io.netty.channel.Channel;
import lombok.Getter;
import lombok.NonNull;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.platforms.bukkit.provider.ComponentConverter;
import me.neznamy.tab.platforms.bukkit.provider.ImplementationProvider;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaScoreboard;
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaTabList;
import me.neznamy.tab.shared.platform.Scoreboard;
import me.neznamy.tab.shared.platform.TabList;
import me.neznamy.tab.shared.util.function.FunctionWithException;
@@ -29,16 +26,6 @@ public class NMSImplementationProvider implements ImplementationProvider {
return new NMSPacketScoreboard(player);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaScoreboard scoreboard) {
NMSPacketScoreboard.onPacketSend(packet, scoreboard);
}
@Override
public void onPacketSend(@NonNull Object packet, @NonNull ViaTabList tabList) {
NMSPacketTabList.onPacketSend(packet, tabList);
}
@Override
@NotNull
public TabList newTabList(@NotNull BukkitTabPlayer player) {
@@ -33,26 +33,6 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
private static final Field DisplayObjective_OBJECTIVE_NAME = ReflectionUtils.getOnlyField(PacketPlayOutScoreboardDisplayObjective.class, String.class);
private static final Field DisplayObjective_POSITION = ReflectionUtils.getOnlyField(PacketPlayOutScoreboardDisplayObjective.class, int.class);
@SneakyThrows
@SuppressWarnings("unchecked")
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), DisplayObjective_POSITION.getInt(packet),
(String) DisplayObjective_OBJECTIVE_NAME.get(packet));
}
if (packet instanceof PacketPlayOutScoreboardObjective) {
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(),
Objective_METHOD.getInt(packet), (String) Objective_OBJECTIVE_NAME.get(packet));
}
if (packet instanceof PacketPlayOutScoreboardTeam) {
int action = TeamPacket_ACTION.getInt(packet);
if (action == TeamAction.UPDATE) return;
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
if (players == null) players = Collections.emptyList();
TeamPacket_PLAYERS.set(packet, scoreboard.onTeamPacket(action, (String) TeamPacket_NAME.get(packet), players));
}
}
/**
* Constructs new instance with given player.
*
@@ -66,7 +46,7 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
@Override
public void registerObjective(@NonNull Objective objective) {
ScoreboardObjective obj = new ScoreboardObjective(dummyScoreboard, objective.getName(), IScoreboardCriteria.b);
obj.setDisplayName(cutTo(objective.getTitle().toLegacyText(), Limitations.SCOREBOARD_TITLE_PRE_1_13));
obj.setDisplayName(maybeCut(objective.getTitle().toLegacyText(), Limitations.SCOREBOARD_TITLE_PRE_1_13));
obj.a(IScoreboardCriteria.EnumScoreboardHealthDisplay.valueOf(objective.getHealthDisplay().name()));
objective.setPlatformObjective(obj);
sendPacket(new PacketPlayOutScoreboardObjective(obj, ObjectiveAction.REGISTER));
@@ -85,7 +65,7 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
@Override
public void updateObjective(@NonNull Objective objective) {
ScoreboardObjective obj = (ScoreboardObjective) objective.getPlatformObjective();
obj.setDisplayName(cutTo(objective.getTitle().toLegacyText(), Limitations.SCOREBOARD_TITLE_PRE_1_13));
obj.setDisplayName(maybeCut(objective.getTitle().toLegacyText(), Limitations.SCOREBOARD_TITLE_PRE_1_13));
obj.a(IScoreboardCriteria.EnumScoreboardHealthDisplay.valueOf(objective.getHealthDisplay().name()));
sendPacket(new PacketPlayOutScoreboardObjective(obj, ObjectiveAction.UPDATE));
}
@@ -132,13 +112,29 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
t.setAllowFriendlyFire((team.getOptions() & 0x01) != 0);
t.setCanSeeFriendlyInvisibles((team.getOptions() & 0x02) != 0);
t.setNameTagVisibility(visibilities[team.getVisibility().ordinal()]);
t.setPrefix(cutTo(team.getPrefix().toLegacyText(), Limitations.TEAM_PREFIX_SUFFIX_PRE_1_13));
t.setSuffix(cutTo(team.getSuffix().toLegacyText(), Limitations.TEAM_PREFIX_SUFFIX_PRE_1_13));
t.setPrefix(maybeCut(team.getPrefix().toLegacyText(), Limitations.TEAM_PREFIX_SUFFIX_PRE_1_13));
t.setSuffix(maybeCut(team.getSuffix().toLegacyText(), Limitations.TEAM_PREFIX_SUFFIX_PRE_1_13));
}
@Override
@SneakyThrows
@SuppressWarnings("unchecked")
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
TAB.getInstance().getFeatureManager().onDisplayObjective(player, DisplayObjective_POSITION.getInt(packet),
(String) DisplayObjective_OBJECTIVE_NAME.get(packet));
}
if (packet instanceof PacketPlayOutScoreboardObjective) {
TAB.getInstance().getFeatureManager().onObjective(player,
Objective_METHOD.getInt(packet), (String) Objective_OBJECTIVE_NAME.get(packet));
}
if (packet instanceof PacketPlayOutScoreboardTeam) {
int action = TeamPacket_ACTION.getInt(packet);
if (action == TeamAction.UPDATE) return;
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
if (players == null) players = Collections.emptyList();
TeamPacket_PLAYERS.set(packet, onTeamPacket(action, (String) TeamPacket_NAME.get(packet), players));
}
}
/**
@@ -150,4 +146,12 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
private void sendPacket(@NotNull Packet<?> packet) {
((CraftPlayer)player.getPlayer()).getHandle().playerConnection.sendPacket(packet);
}
@NotNull
private String maybeCut(@NonNull String string, int length) {
if (player.getVersion().getMinorVersion() < 13 || TAB.getInstance().getConfiguration().getConfig().isPacketEventsCompensation()) {
return cutTo(string, length);
}
return string;
}
}
@@ -36,31 +36,6 @@ public class NMSPacketTabList extends TrackedTabList<BukkitTabPlayer> {
private static final Field FOOTER = ReflectionUtils.getFields(PacketPlayOutPlayerListHeaderFooter.class, IChatBaseComponent.class).get(1);
@SneakyThrows
@SuppressWarnings("unchecked")
public static void onPacketSend(@NonNull Object packet, TrackedTabList<BukkitTabPlayer> tabList) {
if (!(packet instanceof PacketPlayOutPlayerInfo)) return;
EnumPlayerInfoAction action = (EnumPlayerInfoAction) ACTION.get(packet);
for (PlayerInfoData nmsData : (List<PlayerInfoData>) PLAYERS.get(packet)) {
GameProfile profile = nmsData.a();
UUID id = profile.getId();
if (action == EnumPlayerInfoAction.UPDATE_DISPLAY_NAME || action == EnumPlayerInfoAction.ADD_PLAYER) {
TabComponent expectedName = tabList.getExpectedDisplayNames().get(id);
if (expectedName != null) PlayerInfoData_DisplayName.set(nmsData, expectedName.convert());
}
if (action == EnumPlayerInfoAction.UPDATE_LATENCY || action == EnumPlayerInfoAction.ADD_PLAYER) {
int oldLatency = PlayerInfoData_Latency.getInt(nmsData);
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(tabList.getPlayer(), id, oldLatency);
if (oldLatency != newLatency) {
PlayerInfoData_Latency.set(nmsData, newLatency);
}
}
if (action == EnumPlayerInfoAction.ADD_PLAYER) {
TAB.getInstance().getFeatureManager().onEntryAdd(tabList.getPlayer(), id, profile.getName());
}
}
}
/**
* Constructs new instance.
*
@@ -136,8 +111,29 @@ public class NMSPacketTabList extends TrackedTabList<BukkitTabPlayer> {
}
@Override
@SneakyThrows
@SuppressWarnings("unchecked")
public void onPacketSend(@NonNull Object packet) {
onPacketSend(packet, this);
if (!(packet instanceof PacketPlayOutPlayerInfo)) return;
EnumPlayerInfoAction action = (EnumPlayerInfoAction) ACTION.get(packet);
for (PlayerInfoData nmsData : (List<PlayerInfoData>) PLAYERS.get(packet)) {
GameProfile profile = nmsData.a();
UUID id = profile.getId();
if (action == EnumPlayerInfoAction.UPDATE_DISPLAY_NAME || action == EnumPlayerInfoAction.ADD_PLAYER) {
TabComponent expectedName = getExpectedDisplayNames().get(id);
if (expectedName != null) PlayerInfoData_DisplayName.set(nmsData, expectedName.convert());
}
if (action == EnumPlayerInfoAction.UPDATE_LATENCY || action == EnumPlayerInfoAction.ADD_PLAYER) {
int oldLatency = PlayerInfoData_Latency.getInt(nmsData);
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(player, id, oldLatency);
if (oldLatency != newLatency) {
PlayerInfoData_Latency.set(nmsData, newLatency);
}
}
if (action == EnumPlayerInfoAction.ADD_PLAYER) {
TAB.getInstance().getFeatureManager().onEntryAdd(player, id, profile.getName());
}
}
}
@SneakyThrows
+2 -1
View File
@@ -1,7 +1,8 @@
dependencies {
implementation(projects.shared)
implementation("org.bstats:bstats-bungeecord:3.1.0")
compileOnly("net.md-5:bungeecord-proxy:1.21-R0.1-SNAPSHOT")
compileOnly("net.md-5:bungeecord-api:1.21-R0.4-SNAPSHOT")
compileOnly("net.md-5:bungeecord-proxy:1.21-R0.3-SNAPSHOT") // R0.4 is not available anywhere, combine with new API
compileOnly("com.github.limework.redisbungee:RedisBungee-Bungee:0.11.0")
compileOnly("com.github.LeonMangler:PremiumVanishAPI:2.8.8")
}
@@ -10,10 +10,8 @@ import me.neznamy.tab.shared.platform.decorators.SafeScoreboard;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.protocol.Either;
import net.md_5.bungee.protocol.NumberFormat;
import net.md_5.bungee.protocol.packet.ScoreboardDisplay;
import net.md_5.bungee.protocol.packet.ScoreboardObjective;
import net.md_5.bungee.protocol.packet.ScoreboardScore;
import net.md_5.bungee.protocol.packet.ScoreboardScoreReset;
import net.md_5.bungee.protocol.packet.*;
import net.md_5.bungee.protocol.packet.Team.NameTagVisibility;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -119,14 +117,32 @@ public class BungeeScoreboard extends SafeScoreboard<BungeeTabPlayer> {
either(TabComponent.legacyText(team.getName()), Limitations.TEAM_PREFIX_SUFFIX_PRE_1_13),
either(team.getPrefix(), Limitations.TEAM_PREFIX_SUFFIX_PRE_1_13),
either(team.getSuffix(), Limitations.TEAM_PREFIX_SUFFIX_PRE_1_13),
net.md_5.bungee.protocol.packet.Team.NameTagVisibility.valueOf(team.getVisibility().name()),
net.md_5.bungee.protocol.packet.Team.CollisionRule.valueOf(team.getCollision().name()),
convertVisibility(team.getVisibility()),
convertCollision(team.getCollision()),
player.getVersion().getMinorVersion() >= TEAM_REWORK_VERSION ? team.getColor().getLegacyColor().ordinal() : 0,
(byte) team.getOptions(),
team.getPlayers().toArray(new String[0])
));
}
@NotNull
private Either<String, NameTagVisibility> convertVisibility(@NotNull NameVisibility visibility) {
if (player.getVersion().getNetworkId() >= ProtocolVersion.V1_21_5.getNetworkId()) {
return Either.right(NameTagVisibility.valueOf(visibility.name()));
} else {
return Either.left(visibility.toString());
}
}
@NotNull
private Either<String, net.md_5.bungee.protocol.packet.Team.CollisionRule> convertCollision(@NotNull CollisionRule collision) {
if (player.getVersion().getNetworkId() >= ProtocolVersion.V1_21_5.getNetworkId()) {
return Either.right(net.md_5.bungee.protocol.packet.Team.CollisionRule.valueOf(collision.name()));
} else {
return Either.left(collision.toString());
}
}
@Override
public void onPacketSend(@NonNull Object packet) {
if (packet instanceof ScoreboardDisplay) {
@@ -1,8 +1,9 @@
package me.neznamy.tab.platforms.bungeecord;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.util.ReflectionUtils;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.protocol.Either;
import net.md_5.bungee.protocol.packet.Team;
/**
* Main class for BungeeCord.
@@ -11,17 +12,28 @@ public class BungeeTAB extends Plugin {
@Override
public void onEnable() {
if (ReflectionUtils.classExists("net.md_5.bungee.protocol.packet.Team$NameTagVisibility")) {
if (isCompatible()) {
TAB.create(new BungeePlatform(this));
} else {
getLogger().warning("§c====================================================================================================");
getLogger().warning("§cThe plugin requires BungeeCord build #1899 " +
"(released on February 1st, 2025) and up (or an equivalent fork) to work. If you are using a fork that did not" +
" update to the new BungeeCord version yet, stay on TAB v5.0.5, which supports older builds.");
getLogger().warning("§c====================================================================================================");
logIncompatibleVersionWarning();
}
}
private boolean isCompatible() {
try {
return Team.class.getDeclaredField("nameTagVisibility").getType() == Either.class;
} catch (ReflectiveOperationException e) {
return false;
}
}
private void logIncompatibleVersionWarning() {
getLogger().warning("§c====================================================================================================");
getLogger().warning("§cThe plugin requires BungeeCord build #1980 (released on June 21st, 2025) and up (or an equivalent fork) to work.");
getLogger().warning("§cIf you are using a fork that did not update to the new BungeeCord version yet, stay on TAB v5.2.2, which supports older builds.");
getLogger().warning("§c====================================================================================================");
}
@Override
public void onDisable() {
if (TAB.getInstance() != null) TAB.getInstance().unload();
@@ -12,7 +12,6 @@ import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.connection.InitialHandler;
import net.md_5.bungee.connection.LoginResult;
import net.md_5.bungee.protocol.Property;
import net.md_5.bungee.protocol.packet.PlayerListHeaderFooter;
import net.md_5.bungee.protocol.packet.PlayerListItem;
import net.md_5.bungee.protocol.packet.PlayerListItem.Item;
import net.md_5.bungee.protocol.packet.PlayerListItemUpdate;
@@ -47,7 +46,7 @@ public abstract class BungeeTabList extends TrackedTabList<BungeeTabPlayer> {
@Override
public void setPlayerListHeaderFooter(@NonNull TabComponent header, @NonNull TabComponent footer) {
player.sendPacket(new PlayerListHeaderFooter(toComponent(header), toComponent(footer)));
player.getPlayer().setTabHeader(toComponent(header), toComponent(footer));
}
/**
-2
View File
@@ -1,5 +1,3 @@
dependencies {
compileOnlyApi("net.kyori:adventure-api:4.18.0")
compileOnlyApi("com.viaversion:viaversion-api:5.2.1")
compileOnlyApi("com.viaversion:viaversion-common:5.2.1")
}
@@ -1,8 +1,5 @@
package me.neznamy.chat.component;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.util.ComponentUtil;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
@@ -11,7 +8,6 @@ import me.neznamy.chat.ChatModifier;
import me.neznamy.chat.EnumChatFormat;
import me.neznamy.chat.TextColor;
import me.neznamy.chat.hook.AdventureHook;
import me.neznamy.chat.hook.ViaVersionHook;
import me.neznamy.chat.rgb.RGBUtils;
import me.neznamy.chat.util.TriFunction;
import net.kyori.adventure.text.Component;
@@ -112,15 +108,6 @@ public abstract class TabComponent {
@Setter
private Component adventureComponent;
/** ViaVersion component from this component */
@Nullable
@Setter
private JsonElement viaComponent;
/** ViaVersion tag from this component */
@Nullable
@Setter
private Tag viaTag;
@Nullable
private Object fixedFormat;
@@ -191,26 +178,6 @@ public abstract class TabComponent {
return adventureComponent;
}
/**
* Converts this component to an ViaVersion component.
* @return Converted component
*/
@NotNull
public JsonElement toViaVersion() {
if (viaComponent == null) viaComponent = ViaVersionHook.convert(this);
return viaComponent;
}
/**
* Converts this component to an ViaVersion tag.
* @return Converted component
*/
@NotNull
public Tag toViaVersionTag() {
if (viaTag == null) viaTag = ComponentUtil.jsonToTag(toViaVersion());
return viaTag;
}
/**
* Creates a FixedFormat using given platform-specific create function.
* If the value is already initialized, it is returned immediately instead.
@@ -334,7 +301,7 @@ public abstract class TabComponent {
break;
}
}
final TextComponent component = new TextComponent("", components);
TextComponent component = new TextComponent("", components);
// Safe check to avoid rare mojang "bug" that display text as italic by default
// This doesn't affect #toLegacyText() method at all
component.modifier.setItalic(false);
@@ -1,81 +0,0 @@
package me.neznamy.chat.hook;
import com.viaversion.viaversion.libs.gson.JsonArray;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.util.ComponentUtil;
import me.neznamy.chat.ChatModifier;
import me.neznamy.chat.component.KeybindComponent;
import me.neznamy.chat.component.LegacyTextComponent;
import me.neznamy.chat.component.TabComponent;
import me.neznamy.chat.component.TextComponent;
import me.neznamy.chat.component.TranslatableComponent;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@ApiStatus.Internal
public class ViaVersionHook {
@NotNull
public static JsonElement convert(@NotNull TabComponent component) {
if (component instanceof LegacyTextComponent) {
return ComponentUtil.legacyToJson(component.toLegacyText());
}
final JsonObject object = new JsonObject();
// Root
if (component instanceof TextComponent) {
object.addProperty("type", "text"); // +1.20.3 optimization
object.addProperty("text", ((TextComponent) component).getText());
} else if (component instanceof TranslatableComponent) {
object.addProperty("type", "translatable"); // +1.20.3 optimization
object.addProperty("translate", ((TranslatableComponent) component).getKey());
} else if (component instanceof KeybindComponent) {
object.addProperty("type", "keybind"); // +1.20.3 optimization
object.addProperty("keybind", ((KeybindComponent) component).getKeybind());
} else {
throw new IllegalStateException("Unknown component type: " + component.getClass().getName());
}
// Color
final ChatModifier modifier = component.getModifier();
if (modifier.getColor() != null) {
object.addProperty("color", "#" + modifier.getColor().getHexCode());
}
if (modifier.getShadowColor() != null) {
object.addProperty("shadow_color", modifier.getShadowColor());
}
// Render
if (Boolean.TRUE.equals(modifier.getBold())) {
object.addProperty("bold", true);
}
if (modifier.getItalic() != null) {
object.addProperty("italic", modifier.getItalic());
}
if (Boolean.TRUE.equals(modifier.getObfuscated())) {
object.addProperty("obfuscated", true);
}
if (Boolean.TRUE.equals(modifier.getStrikethrough())) {
object.addProperty("strikethrough", true);
}
if (Boolean.TRUE.equals(modifier.getUnderlined())) {
object.addProperty("underlined", true);
}
if (modifier.getFont() != null) {
object.addProperty("font", modifier.getFont());
}
// Extra
if (!component.getExtra().isEmpty()) {
final JsonArray extra = new JsonArray();
for (TabComponent sub : component.getExtra()) {
extra.add((JsonElement) convert(sub));
}
object.add("extra", extra);
}
return object;
}
}
+2 -1
View File
@@ -11,10 +11,11 @@ repositories {
maven("https://maven.nucleoid.xyz/")
}
val minecraftVersion = "1.21.6"
val minecraftVersion = "1.21.7"
// Fabric API versions for each Minecraft version for easier backporting
val fabricApiVersions = mapOf(
"1.21.7" to "0.128.1+1.21.7",
"1.21.6" to "0.125.1+1.21.6",
"1.21.5" to "0.119.9+1.21.5",
"1.21.4" to "0.119.2+1.21.4",
+2 -1
View File
@@ -14,7 +14,8 @@
"fabric-api-base": "*",
"java": ">=17",
"minecraft": [
"1.21.6"
"1.21.6",
"1.21.7"
]
},
"recommends": {
+3 -1
View File
@@ -12,10 +12,12 @@ repositories {
maven("https://maven.neoforged.net/releases")
}
val minecraftVersion = "1.21.6"
val minecraftVersion = "1.21.7"
// Forge API versions for each Minecraft version for easier backporting
// Official website (for updating in the future): https://files.minecraftforge.net/net/minecraftforge/forge/
val forgeApiVersions = mapOf(
"1.21.7" to "1.21.7-57.0.0",
"1.21.6" to "1.21.6-56.0.0",
"1.21.5" to "1.21.5-55.0.3",
"1.21.4" to "1.21.4-54.1.3",
+1 -1
View File
@@ -22,6 +22,6 @@ side = "SERVER"
[[dependencies.tab]]
modId = "minecraft"
mandatory = true
versionRange = "[1.21.6]"
versionRange = "[1.21.6],[1.21.7]"
ordering = "NONE"
side = "SERVER"
+3 -1
View File
@@ -12,10 +12,12 @@ repositories {
maven("https://maven.neoforged.net/releases")
}
val minecraftVersion = "1.21.6"
val minecraftVersion = "1.21.7"
// NeoForge API versions for each Minecraft version for easier backporting
// Official website (for updating in the future): https://projects.neoforged.net/neoforged/neoforge
val neoforgeApiVersions = mapOf(
"1.21.7" to "21.7.1-beta",
"1.21.6" to "21.6.5-beta",
"1.21.5" to "21.5.77",
"1.21.4" to "21.4.138",
@@ -21,6 +21,6 @@ side = "SERVER"
[[dependencies.tab]]
modId = "minecraft"
type = "required"
versionRange = "[1.21.6]"
versionRange = "[1.21.6],[1.21.7]"
ordering = "NONE"
side = "SERVER"
@@ -1,19 +1,18 @@
package me.neznamy.tab.shared;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter;
import me.neznamy.chat.EnumChatFormat;
import me.neznamy.tab.shared.features.PlaceholderManagerImpl;
import me.neznamy.tab.shared.features.types.RefreshableFeature;
import me.neznamy.chat.EnumChatFormat;
import me.neznamy.chat.rgb.RGBUtils;
import me.neznamy.tab.shared.placeholders.expansion.TabExpansion;
import me.neznamy.tab.shared.placeholders.types.RelationalPlaceholderImpl;
import me.neznamy.tab.shared.platform.TabPlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* A dynamic text with placeholder support. If any placeholder
* used in this text changes value, feature defining this text
@@ -315,4 +314,18 @@ public class Property {
}
return format;
}
/**
* Returns original raw value with placeholders replaced by their values.
*
* @return original raw value with placeholders replaced
*/
@NotNull
public String getOriginalReplacedValue() {
String value = originalRawValue;
for (String identifier : PlaceholderManagerImpl.detectPlaceholders(value)) {
value = TAB.getInstance().getPlaceholderManager().getPlaceholder(identifier).set(identifier, owner);
}
return EnumChatFormat.color(value);
}
}
@@ -11,6 +11,7 @@ import org.jetbrains.annotations.NotNull;
public enum ProtocolVersion {
UNKNOWN,
V1_21_7 (772),
V1_21_6 (771),
V1_21_5 (770),
V1_21_4 (769),
@@ -33,7 +33,7 @@ public class MySQLConfiguration {
@NotNull
public static MySQLConfiguration fromSection(@NonNull ConfigurationSection section) {
// Check keys
section.checkForUnknownKey(Arrays.asList("enabled", "host", "port", "database", "username", "password", "useSSL"));
section.checkForUnknownKey(Arrays.asList("enabled", "host", "port", "database", "username", "password", "usessl"));
return new MySQLConfiguration(
section.getString("host", "127.0.0.1"),
@@ -93,6 +93,7 @@ public class BossBarManagerImpl extends RefreshableFeature implements BossBarMan
@Override
public void onJoin(@NotNull TabPlayer connectedPlayer) {
TAB.getInstance().getPlaceholderManager().getTabExpansion().setBossBarVisible(connectedPlayer, false);
if (toggleManager != null) toggleManager.convert(connectedPlayer);
setBossBarVisible(connectedPlayer, configuration.isHiddenByDefault() == (toggleManager != null && toggleManager.contains(connectedPlayer)), false);
}
@@ -186,6 +187,32 @@ public class BossBarManagerImpl extends RefreshableFeature implements BossBarMan
return Collections.unmodifiableMap(registeredBossBars);
}
@Override
public void removeBossBar(@NonNull String name) {
ensureActive();
BossBar bar = registeredBossBars.remove(name);
if (bar == null) throw new IllegalArgumentException("No registered BossBar found with name " + name);
lineValues = registeredBossBars.values().toArray(new BossBarLine[0]);
for (TabPlayer player : TAB.getInstance().getOnlinePlayers()) {
bar.removePlayer(player);
player.bossbarData.visibleBossBars.remove(bar);
}
}
@Override
public void removeBossBar(@NonNull BossBar bossBar) {
ensureActive();
BossBarLine bar = (BossBarLine) bossBar;
if (!registeredBossBars.remove(bar.getName(), bar)) {
throw new IllegalArgumentException("This bossbar (" + bar.getName() + ") is not registered.");
}
lineValues = registeredBossBars.values().toArray(new BossBarLine[0]);
for (TabPlayer player : TAB.getInstance().getOnlinePlayers()) {
bar.removePlayer(player);
player.bossbarData.visibleBossBars.remove(bar);
}
}
@Override
public void toggleBossBar(@NonNull me.neznamy.tab.api.TabPlayer player, boolean sendToggleMessage) {
ensureActive();
@@ -4,6 +4,7 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor;
import me.neznamy.chat.EnumChatFormat;
import me.neznamy.tab.shared.ProtocolVersion;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.config.file.ConfigurationSection;
import me.neznamy.tab.shared.platform.TabPlayer;
import org.jetbrains.annotations.NotNull;
@@ -107,14 +108,16 @@ public class LayoutConfiguration {
}
public String getEntryName(@NotNull TabPlayer viewer, int slot, boolean teamsEnabled) {
if (viewer.getVersion().getNetworkId() >= ProtocolVersion.V1_19_3.getNetworkId() && viewer.getVersion().getNetworkId() < ProtocolVersion.V1_21_2.getNetworkId()) {
boolean legacySorting = viewer.getVersion().getNetworkId() < ProtocolVersion.V1_19_3.getNetworkId();
boolean modernSorting = viewer.getVersion().getNetworkId() >= ProtocolVersion.V1_21_2.getNetworkId() && TAB.getInstance().getPlatform().supportsListOrder();
if (legacySorting || modernSorting) {
return "";
} else {
if (teamsEnabled) {
return "|slot_" + (10+slotTranslator.apply(slot));
} else {
return " slot_" + (10+slotTranslator.apply(slot));
}
} else {
return "";
}
}
}
@@ -665,7 +665,7 @@ public class NameTag extends RefreshableFeature implements NameTagManager, JoinL
@Override
@NotNull
public String getOriginalPrefix(@NonNull me.neznamy.tab.api.TabPlayer player) {
public String getOriginalRawPrefix(@NonNull me.neznamy.tab.api.TabPlayer player) {
ensureActive();
TabPlayer p = (TabPlayer) player;
p.ensureLoaded();
@@ -674,13 +674,43 @@ public class NameTag extends RefreshableFeature implements NameTagManager, JoinL
@Override
@NotNull
public String getOriginalSuffix(@NonNull me.neznamy.tab.api.TabPlayer player) {
public String getOriginalRawSuffix(@NonNull me.neznamy.tab.api.TabPlayer player) {
ensureActive();
TabPlayer p = (TabPlayer) player;
p.ensureLoaded();
return p.teamData.suffix.getOriginalRawValue();
}
@Override
@NotNull
public String getOriginalReplacedPrefix(@NonNull me.neznamy.tab.api.TabPlayer player) {
ensureActive();
TabPlayer p = (TabPlayer) player;
p.ensureLoaded();
return p.teamData.prefix.getOriginalReplacedValue();
}
@Override
@NotNull
public String getOriginalReplacedSuffix(@NonNull me.neznamy.tab.api.TabPlayer player) {
ensureActive();
TabPlayer p = (TabPlayer) player;
p.ensureLoaded();
return p.teamData.suffix.getOriginalReplacedValue();
}
@Override
@NotNull
public String getOriginalPrefix(@NonNull me.neznamy.tab.api.TabPlayer player) {
return getOriginalRawPrefix(player);
}
@Override
@NotNull
public String getOriginalSuffix(@NonNull me.neznamy.tab.api.TabPlayer player) {
return getOriginalRawSuffix(player);
}
@Override
public void toggleNameTagVisibilityView(@NonNull me.neznamy.tab.api.TabPlayer p, boolean sendToggleMessage) {
setNameTagVisibilityView((TabPlayer) p, ((TabPlayer) p).teamData.invisibleNameTagView, sendToggleMessage);
@@ -335,26 +335,71 @@ public class PlayerList extends RefreshableFeature implements TabListFormatManag
}
@Override
public @NotNull String getOriginalPrefix(@NonNull me.neznamy.tab.api.TabPlayer player) {
@NotNull
public String getOriginalPrefix(@NonNull me.neznamy.tab.api.TabPlayer player) {
return getOriginalRawPrefix(player);
}
@Override
@NotNull
public String getOriginalName(@NonNull me.neznamy.tab.api.TabPlayer player) {
return getOriginalRawName(player);
}
@Override
@NotNull
public String getOriginalSuffix(@NonNull me.neznamy.tab.api.TabPlayer player) {
return getOriginalRawSuffix(player);
}
@Override
@NotNull
public String getOriginalRawPrefix(@NonNull me.neznamy.tab.api.TabPlayer player) {
ensureActive();
((TabPlayer)player).ensureLoaded();
return ((TabPlayer)player).tablistData.prefix.getOriginalRawValue();
}
@Override
public @NotNull String getOriginalName(@NonNull me.neznamy.tab.api.TabPlayer player) {
@NotNull
public String getOriginalRawName(@NonNull me.neznamy.tab.api.TabPlayer player) {
ensureActive();
((TabPlayer)player).ensureLoaded();
return ((TabPlayer)player).tablistData.name.getOriginalRawValue();
}
@Override
public @NotNull String getOriginalSuffix(@NonNull me.neznamy.tab.api.TabPlayer player) {
@NotNull
public String getOriginalRawSuffix(@NonNull me.neznamy.tab.api.TabPlayer player) {
ensureActive();
((TabPlayer)player).ensureLoaded();
return ((TabPlayer)player).tablistData.suffix.getOriginalRawValue();
}
@Override
@NotNull
public String getOriginalReplacedPrefix(@NonNull me.neznamy.tab.api.TabPlayer player) {
ensureActive();
((TabPlayer)player).ensureLoaded();
return ((TabPlayer)player).tablistData.prefix.getOriginalReplacedValue();
}
@Override
@NotNull
public String getOriginalReplacedName(@NonNull me.neznamy.tab.api.TabPlayer player) {
ensureActive();
((TabPlayer)player).ensureLoaded();
return ((TabPlayer)player).tablistData.name.getOriginalReplacedValue();
}
@Override
@NotNull
public String getOriginalReplacedSuffix(@NonNull me.neznamy.tab.api.TabPlayer player) {
ensureActive();
((TabPlayer)player).ensureLoaded();
return ((TabPlayer)player).tablistData.suffix.getOriginalReplacedValue();
}
// ------------------
// ProxySupport
// ------------------
@@ -77,8 +77,14 @@ public abstract class ProxySupport extends TabFeature implements JoinListener, Q
TAB.getInstance().getErrorManager().unknownProxyMessage(action);
return;
}
ProxyMessage proxyMessage = function.apply(in);
TAB.getInstance().debug("[Proxy Support] Decoded message " + proxyMessage);
ProxyMessage proxyMessage;
try {
proxyMessage = function.apply(in);
TAB.getInstance().debug("[Proxy Support] Decoded message " + proxyMessage);
} catch (Exception e) {
TAB.getInstance().getErrorManager().printError("Failed to decode proxy message \"" + new String(Base64.getDecoder().decode(msg)) + "\" ", e);
return;
}
// Queue the task to make sure it does not execute before plugin fully loads, causing NPE
TAB.getInstance().getCpu().runMeasuredTask(getFeatureName(), CpuUsageCategory.PROXY_MESSAGE, () -> {
@@ -24,6 +24,7 @@ import java.util.Map.Entry;
/**
* Feature handler for scoreboard feature.
*/
@Getter
public class ScoreboardManagerImpl extends RefreshableFeature implements ScoreboardManager, JoinListener,
CommandListener, DisplayObjectiveListener, ObjectiveListener, Loadable,
QuitListener, CustomThreaded, ServerSwitchListener {
@@ -31,18 +32,17 @@ public class ScoreboardManagerImpl extends RefreshableFeature implements Scorebo
/** Objective name used by this feature */
public static final String OBJECTIVE_NAME = "TAB-Scoreboard";
@Getter
private final StringToComponentCache cache = new StringToComponentCache("Scoreboard", 1000);
@Getter
private final ThreadExecutor customThread = new ThreadExecutor("TAB Scoreboard Thread");
@Getter
private final ScoreboardConfiguration configuration;
//defined scoreboards
@Getter private final Map<String, me.neznamy.tab.api.scoreboard.Scoreboard> registeredScoreboards = new LinkedHashMap<>();
private me.neznamy.tab.api.scoreboard.Scoreboard[] definedScoreboards;
/** All registered scoreboards, both in config and using the API */
private final Map<String, ScoreboardImpl> registeredScoreboards = new LinkedHashMap<>();
/** Scoreboards defined in the config. This does not include scoreboards creating using API. */
private ScoreboardImpl[] definedScoreboards;
/** Manager for toggled players if remembering is enabled in config */
@Nullable
@@ -73,7 +73,7 @@ public class ScoreboardManagerImpl extends RefreshableFeature implements Scorebo
registeredScoreboards.put(scoreboardName, sb);
TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.scoreboardLine(scoreboardName), sb);
}
definedScoreboards = registeredScoreboards.values().stream().filter(s -> !((ScoreboardImpl)s).isApi()).toArray(me.neznamy.tab.api.scoreboard.Scoreboard[]::new);
definedScoreboards = registeredScoreboards.values().stream().filter(s -> !s.isApi()).toArray(ScoreboardImpl[]::new);
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()) {
onJoin(p);
}
@@ -151,8 +151,8 @@ public class ScoreboardManagerImpl extends RefreshableFeature implements Scorebo
*/
public @Nullable me.neznamy.tab.api.scoreboard.Scoreboard detectHighestScoreboard(@NonNull TabPlayer p) {
if (p.scoreboardData.forcedScoreboard != null) return p.scoreboardData.forcedScoreboard;
for (me.neznamy.tab.api.scoreboard.Scoreboard sb : definedScoreboards) {
if (((ScoreboardImpl)sb).isConditionMet(p)) return sb;
for (ScoreboardImpl sb : definedScoreboards) {
if (sb.isConditionMet(p)) return sb;
}
return null;
}
@@ -214,6 +214,35 @@ public class ScoreboardManagerImpl extends RefreshableFeature implements Scorebo
return sb;
}
@Override
public void removeScoreboard(@NonNull String name) {
ScoreboardImpl removed = registeredScoreboards.remove(name);
if (removed == null) {
throw new IllegalArgumentException("No registered scoreboard found with name " + name);
}
Set<TabPlayer> players = removed.getPlayers();
removed.unregister();
for (TabPlayer p : players) {
p.scoreboardData.forcedScoreboard = null;
sendHighestScoreboard(p);
}
}
@Override
public void removeScoreboard(@NonNull me.neznamy.tab.api.scoreboard.Scoreboard scoreboard) {
if (!registeredScoreboards.remove(scoreboard.getName(), (ScoreboardImpl) scoreboard)) {
throw new IllegalArgumentException("This scoreboard (" + scoreboard.getName() + ") is not registered.");
}
Set<TabPlayer> players = ((ScoreboardImpl)scoreboard).getPlayers();
scoreboard.unregister();
for (TabPlayer p : players) {
p.scoreboardData.forcedScoreboard = null;
sendHighestScoreboard(p);
}
}
@Override
public void showScoreboard(@NonNull me.neznamy.tab.api.TabPlayer player, @NonNull me.neznamy.tab.api.scoreboard.Scoreboard scoreboard) {
ensureActive();
@@ -352,6 +381,11 @@ public class ScoreboardManagerImpl extends RefreshableFeature implements Scorebo
}
}
@NotNull
public Map<String, me.neznamy.tab.api.scoreboard.Scoreboard> getRegisteredScoreboards() {
return Collections.unmodifiableMap(registeredScoreboards);
}
/**
* Class storing scoreboard data of players.
*/
@@ -106,8 +106,9 @@ public class PlayerPlaceholderImpl extends TabPlaceholder implements PlayerPlace
if (value == null) return false; //bridge placeholders, they are updated using updateValue method
if (ERROR_VALUE.equals(value)) return false;
String newValue = replacements.findReplacement(setPlaceholders(value, p));
if (newValue.equals(identifier)) return false;
String lastValue = p.lastPlaceholderValues.put(this, newValue);
if (lastValue == null || (!identifier.equals(newValue) && !newValue.equals(lastValue))) {
if (!newValue.equals(lastValue)) {
if (updateParents) updateParents(p);
TAB.getInstance().getPlaceholderManager().getTabExpansion().setPlaceholderValue(p, identifier, newValue);
return true;
@@ -180,6 +180,15 @@ public interface Platform {
*/
boolean supportsScoreboards();
/**
* Returns {@code true} if server supports list order option (1.21.2+), {@code false} if not.
*
* @return {@code true} if server supports list order option (1.21.2+), {@code false} if not
*/
default boolean supportsListOrder() {
return true;
}
/**
* Returns {@code true} if the server is safe from being affected by the packetevents bug with limitations, {@code false} if not.
*
@@ -1,7 +1,5 @@
package me.neznamy.tab.shared.util.function;
import org.jetbrains.annotations.NotNull;
/**
* An interface for Function which can throw an exception.
* @param <A>
@@ -12,24 +10,6 @@ import org.jetbrains.annotations.NotNull;
@FunctionalInterface
public interface FunctionWithException<A, B> {
/**
* Empty immutable instance.
*/
FunctionWithException<?, ?> EMPTY = a -> null;
/**
* Get an empty function instance that always return null.
*
* @return a function with null result.
* @param <A> Function argument
* @param <B> Function return type
*/
@NotNull
@SuppressWarnings("unchecked")
static <A, B> FunctionWithException<A, B> empty() {
return (FunctionWithException<A, B>) EMPTY;
}
/**
* Runs the function and returns the result
*
@@ -40,23 +20,4 @@ public interface FunctionWithException<A, B> {
* If thrown by function
*/
B apply(A a) throws Exception;
/**
* Provide a fallback function if current function result into null value.
*
* @param fallback the fallback function.
* @return a newly generated function with fallback provider.
* @param <T> function argument.
* @param <R> function return type.
*/
@SuppressWarnings("unchecked")
default <T extends A, R extends B> FunctionWithException<T, R> fallback(FunctionWithException<T, R> fallback) {
if (this == EMPTY) {
return fallback;
}
return a -> {
final B b = apply(a);
return b != null ? (R) b : fallback.apply(a);
};
}
}
@@ -131,6 +131,11 @@ public class SpongePlatform implements BackendPlatform {
return true;
}
@Override
public boolean supportsListOrder() {
return false; // Maybe add it in the future when LTS bumps
}
@Override
public double getTPS() {
return Sponge.server().ticksPerSecond();
@@ -84,10 +84,17 @@ public class VelocityPlatform extends ProxyPlatform {
// Scoreboard API failed to enable due to an error
}
} else {
logInfo(new TextComponent("As of version 5.0.0, TAB no longer uses TAB-Bridge to encode scoreboard packets on Velocity. " +
"Instead, it uses a custom made plugin that adds scoreboard API directly to Velocity, which offers better performance and reliability. " +
"You can download the plugin from https://github.com/NEZNAMY/VelocityScoreboardAPI/releases/. " +
"Until then, the following features will not work: scoreboard-teams, belowname-objective, playerlist-objective, scoreboard", TextColor.RED));
logInfo(new TextComponent("==============================================================================", TextColor.RED));
logInfo(new TextComponent("Velocity does not have any sort of scoreboard API.", TextColor.RED));
logInfo(new TextComponent("As a result, many features cannot be implemented using the standard Velocity API.", TextColor.RED));
logInfo(new TextComponent("In order to enhance your experience, please consider installing VelocityScoreboardAPI " +
"(https://github.com/NEZNAMY/VelocityScoreboardAPI/releases/) plugin.", TextColor.RED));
logInfo(new TextComponent("Until then, the following features will not work:", TextColor.RED));
logInfo(new TextComponent("- scoreboard-teams", TextColor.RED));
logInfo(new TextComponent("- belowname-objective", TextColor.RED));
logInfo(new TextComponent("- playerlist-objective", TextColor.RED));
logInfo(new TextComponent("- scoreboard", TextColor.RED));
logInfo(new TextComponent("==============================================================================", TextColor.RED));
}
if (plugin.getServer().getPluginManager().isLoaded("premiumvanish")) {
new VelocityPremiumVanishHook().register();