mirror of
https://github.com/NEZNAMY/TAB.git
synced 2026-11-12 20:22:01 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e5ea29c40 | ||
|
|
287b51a0bf | ||
|
|
28cbf952fa | ||
|
|
598c35a3aa | ||
|
|
b8b67a64ab | ||
|
|
7f6020ef34 | ||
|
|
aeed453e15 | ||
|
|
71dddcca4c | ||
|
|
46cdf79e20 | ||
|
|
d7af96823b | ||
|
|
5a228bd6b3 | ||
|
|
fcd95655ce | ||
|
|
7f5b57f8d2 | ||
|
|
f596877716 | ||
|
|
1802c8fd90 | ||
|
|
e05856facc | ||
|
|
45cfc3abb0 | ||
|
|
2d39579861 | ||
|
|
431f4bb4d5 | ||
|
|
7bc9d38176 | ||
|
|
7536447a8f | ||
|
|
059b796061 | ||
|
|
a89942484f | ||
|
|
c28be3fd65 | ||
|
|
5f1116795c | ||
|
|
4f54d2f6b2 | ||
|
|
6b7bedbe2d | ||
|
|
20ff225c31 |
No files matched your search
+1
-2
@@ -6,5 +6,4 @@ is in quality of the report (typically providing correct steps to reproduce that
|
||||
* Test **experimental builds**, which can be found in [GitHub Actions](https://github.com/NEZNAMY/TAB/actions) for problems of any kind including bugs.
|
||||
This way you will help make the actual releases more stable / help get stable releases sooner.
|
||||
* Help improve the wiki by opening a [Wiki change issue](https://github.com/NEZNAMY/TAB/issues/new?assignees=&labels=Wiki&template=wiki_change.yml),
|
||||
where you can improve existing descriptions, add information you found missing, fix typos / grammar mistakes or add more examples of usage of functions.
|
||||
* [Buy a copy](https://builtbybit.com/resources/14009/) of the plugin or [send a donation](https://paypal.me/neznamy1) to keep the plugin active.
|
||||
where you can improve existing descriptions, add information you found missing, fix typos / grammar mistakes or add more examples.
|
||||
@@ -1,70 +1,23 @@
|
||||
# About
|
||||
TAB aims to be a superior all-in-one minecraft plugin for displaying information that outperforms all
|
||||
similar plugins in terms of features, performance, compatibility and support.
|
||||
similar plugins in terms of features, performance and compatibility.
|
||||
More information can be found at [Why TAB?](https://github.com/NEZNAMY/TAB/wiki/Why-TAB%3F) wiki page.
|
||||
|
||||
# Distribution
|
||||
As of TAB 3.0.0, released with MC 1.18 (November 30th, 2021), there is no free / premium
|
||||
version anymore. Only one version of the plugin exists now, which contains all implemented features
|
||||
and is available to everyone for free. However, customer support is only provided to
|
||||
customers who have purchased the plugin (see [Customer support](#customer-support)).
|
||||
|
||||
# Compiling
|
||||
Compilation requires JDK 17 and up.
|
||||
To compile the plugin, run `./gradlew build` from the terminal.
|
||||
Once the plugin compiles, grab the jar from `/jar/build/libs/` folder.
|
||||
The universal jar contains all modules for all supported platforms.
|
||||
|
||||
# Customer support
|
||||
Unlike with other projects where requirements and level of support provided are unclear,
|
||||
we provide a clear answer to what kind of service you will or will not receive. Some projects don't
|
||||
even clearly state if they are free or paid. While they are listed as paid on spigot, they have
|
||||
a free download link in description, which can be confusing.
|
||||
Support is also quite often "we have a discord server, but don't ping devs for support", suggesting
|
||||
there is no official support, just the community.
|
||||
|
||||
In TAB, everything is clearly defined. **Downloads are free, but services are paid.**
|
||||
The plugin is free to download for everyone. The only exception might be occasional update delays
|
||||
for free users once a year.
|
||||
Customer support, however, is only provided to customers who have formally purchased a copy
|
||||
of the plugin on any of the websites the plugin is being sold on:
|
||||
* [BuiltByBit](https://builtbybit.com/resources/14009/)
|
||||
* [Polymart](https://polymart.org/resource/484)
|
||||
|
||||
After purchasing, you can request assistance via either private messages on the website where you
|
||||
have purchased it, or using [TAB's Discord server](https://discord.gg/EaSvdk6) (which is highly
|
||||
preferred, since the communication will be much faster thanks to notifications and more).
|
||||
* We use a ticket system, which allows us to effectively track any amount of unresolved problems.
|
||||
No more questions getting lost in the sea of messages from other people asking. Tickets are only closed
|
||||
after user confirmed all of their questions were answered and then receive a transcript of the ticket
|
||||
from the bot after ticket is closed into private messages (unless user is blocking them).
|
||||
* We do not rely on the community helping, which often makes things even worse. We know people have
|
||||
better things to do than helping random people with a random plugin, especially when most people only
|
||||
have a very basic knowledge of the plugin, not being able to answer more complicated problems.
|
||||
* We have notifications enabled and reply as soon as possible. We do not have the server muted unlike
|
||||
most mods on most servers who only check it when they are really bored, give a wiki link and
|
||||
disappear again.
|
||||
* As the developer, I do not rely on helpers providing support instead of me. They are handy as
|
||||
I am obviously not available 24/7, but I do not intentionally leave anything to them. I reply
|
||||
whenever I am available without any intentional delays.
|
||||
|
||||
# Other links
|
||||
Download the plugin for free:
|
||||
* [GitHub releases](https://github.com/NEZNAMY/TAB/releases)
|
||||
* [BuiltByBit](https://builtbybit.com/resources/20631/)
|
||||
* [Modrinth](https://modrinth.com/plugin/tab-was-taken)
|
||||
|
||||
[Wiki](https://github.com/NEZNAMY/TAB/wiki)
|
||||
# Documentation
|
||||
You can find everything about the plugin on the [Wiki](https://github.com/NEZNAMY/TAB/wiki). This includes a detailed description
|
||||
of all features, as well as information regarding compatibility or limitations of each feature.
|
||||
|
||||
# Issues
|
||||
The [Issues](https://github.com/NEZNAMY/TAB/issues) section is **only** available for cases included in templates.
|
||||
In other words, they **are not available for**:
|
||||
* **Support** - support is provided on discord for buyers, where roles are given to verified users
|
||||
allowing us to know who bought it and who didn't. It also serves as a much faster way of communication.
|
||||
* **Feature requests** - closed indefinitely.
|
||||
|
||||
**If you're a customer, please use discord for reporting bugs, especially if you aren't good at making bug reports.
|
||||
You will be provided with a much faster and higher quality service.**
|
||||
The [Issues](https://github.com/NEZNAMY/TAB/issues) section is an issue tracker for all the kind of problems covered in issue templates.
|
||||
Please refrain from attempting to use it to receive help with your server, such issues will be closed immediately.
|
||||
When opening an issue, provide as much information as possible. The difference between a bug getting fixed in 1 week vs 1 hour
|
||||
is in quality of the report. Bug reports where steps to reproduce are "idk" have no value and will not help to get the bug fixed at all.
|
||||
|
||||
# Contributing
|
||||
See [CONTRIBUTING.md](https://github.com/NEZNAMY/TAB/blob/master/CONTRIBUTING.md)
|
||||
+1
-1
@@ -4,7 +4,7 @@ plugins {
|
||||
|
||||
allprojects {
|
||||
group = "me.neznamy"
|
||||
version = "4.0.2"
|
||||
version = "4.0.3-SNAPSHOT"
|
||||
description = "An all-in-one solution that works"
|
||||
|
||||
ext.set("id", "tab")
|
||||
|
||||
@@ -21,7 +21,7 @@ public class BukkitEventListener extends EventListener<Player> implements Listen
|
||||
quit(e.getPlayer().getUniqueId());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onJoin(PlayerJoinEvent e) {
|
||||
join(e.getPlayer());
|
||||
}
|
||||
@@ -40,4 +40,4 @@ public class BukkitEventListener extends EventListener<Player> implements Listen
|
||||
public TabPlayer createPlayer(Player player) {
|
||||
return new BukkitTabPlayer(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,18 @@
|
||||
package me.neznamy.tab.platforms.bukkit;
|
||||
|
||||
import me.neznamy.tab.platforms.bukkit.platform.BukkitPlatform;
|
||||
import me.neznamy.tab.platforms.bukkit.platform.FoliaPlatform;
|
||||
import me.neznamy.tab.shared.ProtocolVersion;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.storage.nms.*;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bstats.charts.SimplePie;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.*;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* Main class for Bukkit platform
|
||||
@@ -30,7 +28,8 @@ public class BukkitTAB extends JavaPlugin {
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
BukkitPlatform platform = new BukkitPlatform(this);
|
||||
BukkitPlatform platform = ReflectionUtils.classExists("io.papermc.paper.threadedregions.RegionizedServer") ?
|
||||
new FoliaPlatform(this) : new BukkitPlatform(this);
|
||||
TAB.setInstance(new TAB(platform, ProtocolVersion.fromFriendlyName(version), getDataFolder()));
|
||||
if (TAB.getInstance().getServerVersion() == ProtocolVersion.UNKNOWN_SERVER_VERSION) {
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] Unknown server version: " + Bukkit.getBukkitVersion() + "! Plugin may not work correctly."));
|
||||
@@ -65,10 +64,12 @@ public class BukkitTAB extends JavaPlugin {
|
||||
private boolean isVersionSupported() {
|
||||
try {
|
||||
long time = System.currentTimeMillis();
|
||||
NMSStorage.setInstance(getNMSLoader());
|
||||
String serverPackage = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
|
||||
int minorVersion = Integer.parseInt(serverPackage.split("_")[1]);
|
||||
NMSStorage.setInstance(minorVersion >= 17 ? new BukkitModernNMSStorage() : new BukkitLegacyNMSStorage());
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("[TAB] Loaded NMS hook in " + (System.currentTimeMillis()-time) + "ms"));
|
||||
return true;
|
||||
} catch (IllegalStateException ex) {
|
||||
} catch (Exception ex) {
|
||||
if (ProtocolVersion.fromFriendlyName(Bukkit.getBukkitVersion().split("-")[0]) == ProtocolVersion.UNKNOWN_SERVER_VERSION) {
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] Your server version is not compatible. " +
|
||||
"This plugin version was made for " + ProtocolVersion.values()[ProtocolVersion.values().length-1].getFriendlyName() +
|
||||
@@ -80,19 +81,4 @@ public class BukkitTAB extends JavaPlugin {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private @NotNull NMSStorage getNMSLoader() {
|
||||
List<Callable<NMSStorage>> loaders = Arrays.asList(
|
||||
BukkitLegacyNMSStorage::new,
|
||||
BukkitModernNMSStorage::new,
|
||||
MojangModernNMSStorage::new,
|
||||
ThermosNMSStorage::new
|
||||
);
|
||||
for (Callable<NMSStorage> loader : loaders) {
|
||||
try {
|
||||
return loader.call();
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
throw new IllegalStateException("Unsupported server version");
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import me.neznamy.tab.platforms.bukkit.platform.BukkitPlatform;
|
||||
import me.neznamy.tab.platforms.bukkit.scoreboard.PacketScoreboard;
|
||||
import me.neznamy.tab.shared.chat.rgb.RGBUtils;
|
||||
import me.neznamy.tab.shared.hook.ViaVersionHook;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package me.neznamy.tab.platforms.bukkit.features;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import me.neznamy.tab.platforms.bukkit.platform.BukkitPlatform;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
@@ -190,4 +191,9 @@ public class BukkitNameTagX extends BackendNameTagX implements Listener, PacketS
|
||||
datawatcher.getHelper().setArmorStandFlags((byte)16);
|
||||
return datawatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runInEntityScheduler(Object entity, Runnable task) {
|
||||
((BukkitPlatform)TAB.getInstance().getPlatform()).runEntityTask((Entity) entity, task);
|
||||
}
|
||||
}
|
||||
+11
-3
@@ -21,8 +21,8 @@ public class DataWatcher implements EntityData {
|
||||
|
||||
/** NMS Fields */
|
||||
public static Class<?> CLASS;
|
||||
public static Constructor<?> CONSTRUCTOR;
|
||||
public static Method REGISTER;
|
||||
private static Constructor<?> CONSTRUCTOR;
|
||||
private static Method REGISTER;
|
||||
public static Method markDirty;
|
||||
public static Method packDirty;
|
||||
|
||||
@@ -38,8 +38,16 @@ public class DataWatcher implements EntityData {
|
||||
* @param nms
|
||||
* NMS storage reference
|
||||
*/
|
||||
public static void load(NMSStorage nms) {
|
||||
public static void load(NMSStorage nms) throws NoSuchMethodException {
|
||||
CONSTRUCTOR = ReflectionUtils.getOnlyConstructor(CLASS);
|
||||
if (nms.getMinorVersion() >= 9) {
|
||||
REGISTER = ReflectionUtils.getMethod(CLASS, new String[]{"register", "a"}, DataWatcherObject.CLASS, Object.class); // {Bukkit, Bukkit 1.18+}
|
||||
} else {
|
||||
REGISTER = ReflectionUtils.getMethod(CLASS, new String[]{"func_75682_a", "a"}, int.class, Object.class); // {Thermos 1.7.10, Bukkit}
|
||||
}
|
||||
if (nms.getMinorVersion() >= 19) {
|
||||
packDirty = CLASS.getMethod("b");
|
||||
}
|
||||
if (nms.is1_19_3Plus()) {
|
||||
markDirty = ReflectionUtils.getOnlyMethod(CLASS, void.class, DataWatcherObject.CLASS);
|
||||
}
|
||||
|
||||
+22
@@ -52,6 +52,28 @@ public class DataWatcherHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static void load(NMSStorage nms) throws NoSuchFieldException, IllegalAccessException {
|
||||
if (nms.getMinorVersion() < 9) return;
|
||||
DataWatcherSerializer_BYTE = DataWatcherRegistry.getDeclaredField("a").get(null);
|
||||
DataWatcherSerializer_FLOAT = DataWatcherRegistry.getDeclaredField("c").get(null);
|
||||
DataWatcherSerializer_STRING = DataWatcherRegistry.getDeclaredField("d").get(null);
|
||||
if (nms.is1_19_3Plus()) {
|
||||
DataWatcherSerializer_OPTIONAL_COMPONENT = DataWatcherRegistry.getDeclaredField("g").get(null);
|
||||
if (nms.is1_19_4Plus()) {
|
||||
DataWatcherSerializer_BOOLEAN = DataWatcherRegistry.getDeclaredField("k").get(null);
|
||||
} else {
|
||||
DataWatcherSerializer_BOOLEAN = DataWatcherRegistry.getDeclaredField("j").get(null);
|
||||
}
|
||||
} else {
|
||||
if (nms.getMinorVersion() >= 13) {
|
||||
DataWatcherSerializer_OPTIONAL_COMPONENT = DataWatcherRegistry.getDeclaredField("f").get(null);
|
||||
DataWatcherSerializer_BOOLEAN = DataWatcherRegistry.getDeclaredField("i").get(null);
|
||||
} else {
|
||||
DataWatcherSerializer_BOOLEAN = DataWatcherRegistry.getDeclaredField("h").get(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes entity byte flags
|
||||
*
|
||||
|
||||
+6
-36
@@ -7,7 +7,6 @@ import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcherItem;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcherObject;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.storage.packet.*;
|
||||
import me.neznamy.tab.platforms.bukkit.scoreboard.PacketScoreboard;
|
||||
import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -39,7 +38,7 @@ public class BukkitLegacyNMSStorage extends NMSStorage {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns class from given name
|
||||
* Returns class from given name. Supports modded servers, such as Thermos.
|
||||
*
|
||||
* @param name
|
||||
* class name
|
||||
@@ -48,40 +47,11 @@ public class BukkitLegacyNMSStorage extends NMSStorage {
|
||||
* if class was not found
|
||||
*/
|
||||
public Class<?> getLegacyClass(@NotNull String name) throws ClassNotFoundException {
|
||||
return Class.forName("net.minecraft.server." + serverPackage + "." + name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadNamedFieldsAndMethods() throws ReflectiveOperationException {
|
||||
PacketScoreboard.ScoreboardScore_setScore = ReflectionUtils.getMethod(PacketScoreboard.ScoreboardScoreClass, new String[] {"setScore", "c"}, int.class); // 1.5.1+, 1.5
|
||||
PacketScoreboard.ScoreboardTeam_setAllowFriendlyFire = ReflectionUtils.getMethod(PacketScoreboard.ScoreboardTeam, new String[] {"setAllowFriendlyFire", "a"}, boolean.class); // 1.5.1+, 1.5
|
||||
PacketScoreboard.ScoreboardTeam_setCanSeeFriendlyInvisibles = ReflectionUtils.getMethod(PacketScoreboard.ScoreboardTeam, new String[] {"setCanSeeFriendlyInvisibles", "b"}, boolean.class); // 1.5.1+, 1.5
|
||||
if (minorVersion >= 7) {
|
||||
ChatSerializer_DESERIALIZE = ChatSerializer.getMethod("a", String.class);
|
||||
}
|
||||
if (minorVersion >= 8) {
|
||||
PacketScoreboard.ScoreboardTeam_setNameTagVisibility = ReflectionUtils.getMethod(PacketScoreboard.ScoreboardTeam, new String[] {"setNameTagVisibility", "a"}, PacketScoreboard.EnumNameTagVisibility); // {1.8.1+, 1.8}
|
||||
}
|
||||
if (minorVersion >= 9) {
|
||||
DataWatcher.REGISTER = DataWatcher.CLASS.getMethod("register", DataWatcherObject.CLASS, Object.class);
|
||||
DataWatcherHelper.DataWatcherSerializer_BYTE = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("a").get(null);
|
||||
DataWatcherHelper.DataWatcherSerializer_FLOAT = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("c").get(null);
|
||||
DataWatcherHelper.DataWatcherSerializer_STRING = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("d").get(null);
|
||||
if (getMinorVersion() >= 13) {
|
||||
DataWatcherHelper.DataWatcherSerializer_OPTIONAL_COMPONENT = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("f").get(null);
|
||||
DataWatcherHelper.DataWatcherSerializer_BOOLEAN = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("i").get(null);
|
||||
} else {
|
||||
DataWatcherHelper.DataWatcherSerializer_BOOLEAN = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("h").get(null);
|
||||
}
|
||||
} else {
|
||||
DataWatcher.REGISTER = DataWatcher.CLASS.getMethod("a", int.class, Object.class);
|
||||
}
|
||||
if (minorVersion >= 13) {
|
||||
PacketScoreboard.ScoreboardTeam_setPrefix = PacketScoreboard.ScoreboardTeam.getMethod("setPrefix", IChatBaseComponent);
|
||||
PacketScoreboard.ScoreboardTeam_setSuffix = PacketScoreboard.ScoreboardTeam.getMethod("setSuffix", IChatBaseComponent);
|
||||
} else {
|
||||
PacketScoreboard.ScoreboardTeam_setPrefix = ReflectionUtils.getMethod(PacketScoreboard.ScoreboardTeam, new String[] {"setPrefix", "b"}, String.class); // 1.5.1+, 1.5
|
||||
PacketScoreboard.ScoreboardTeam_setSuffix = ReflectionUtils.getMethod(PacketScoreboard.ScoreboardTeam, new String[] {"setSuffix", "c"}, String.class); // 1.5.1+, 1.5
|
||||
try {
|
||||
return getClass().getClassLoader().loadClass("net.minecraft.server." + serverPackage + "." + name);
|
||||
} catch (NullPointerException e) {
|
||||
// nested class not found
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-38
@@ -7,7 +7,6 @@ import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcherItem;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcherObject;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.storage.packet.*;
|
||||
import me.neznamy.tab.platforms.bukkit.scoreboard.PacketScoreboard;
|
||||
import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* NMS loader for minecraft 1.17+ using Mojang packaging and bukkit names.
|
||||
@@ -15,37 +14,6 @@ import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class BukkitModernNMSStorage extends NMSStorage {
|
||||
|
||||
@Override
|
||||
public void loadNamedFieldsAndMethods() throws ReflectiveOperationException {
|
||||
ChatSerializer_DESERIALIZE = ChatSerializer.getMethod("a", String.class);
|
||||
DataWatcher.REGISTER = ReflectionUtils.getMethod(DataWatcher.CLASS, new String[]{"register", "a"}, DataWatcherObject.CLASS, Object.class); // {Bukkit, Bukkit 1.18+}
|
||||
PacketScoreboard.ScoreboardScore_setScore = ReflectionUtils.getMethod(PacketScoreboard.ScoreboardScoreClass, new String[]{"setScore", "b"}, int.class); // {Bukkit, Bukkit 1.18+}
|
||||
PacketScoreboard.ScoreboardTeam_setAllowFriendlyFire = ReflectionUtils.getMethod(PacketScoreboard.ScoreboardTeam, new String[]{"setAllowFriendlyFire", "a"}, boolean.class); // {Bukkit, Bukkit 1.18+}
|
||||
PacketScoreboard.ScoreboardTeam_setCanSeeFriendlyInvisibles = ReflectionUtils.getMethod(PacketScoreboard.ScoreboardTeam, new String[]{"setCanSeeFriendlyInvisibles", "b"}, boolean.class); // {Bukkit, Bukkit 1.18+}
|
||||
PacketScoreboard.ScoreboardTeam_setPrefix = ReflectionUtils.getMethod(PacketScoreboard.ScoreboardTeam, new String[]{"setPrefix", "b"}, IChatBaseComponent); // {Bukkit, Bukkit 1.18+}
|
||||
PacketScoreboard.ScoreboardTeam_setSuffix = ReflectionUtils.getMethod(PacketScoreboard.ScoreboardTeam, new String[]{"setSuffix", "c"}, IChatBaseComponent); // {Bukkit, Bukkit 1.18+}
|
||||
PacketScoreboard.ScoreboardTeam_setNameTagVisibility = ReflectionUtils.getMethod(PacketScoreboard.ScoreboardTeam, new String[]{"setNameTagVisibility", "a"}, PacketScoreboard.EnumNameTagVisibility); // {Bukkit, Bukkit 1.18+}
|
||||
DataWatcherHelper.DataWatcherSerializer_BYTE = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("a").get(null);
|
||||
DataWatcherHelper.DataWatcherSerializer_FLOAT = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("c").get(null);
|
||||
DataWatcherHelper.DataWatcherSerializer_STRING = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("d").get(null);
|
||||
if (is1_19_3Plus()) {
|
||||
DataWatcherHelper.DataWatcherSerializer_OPTIONAL_COMPONENT = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("g").get(null);
|
||||
if (is1_19_4Plus()) {
|
||||
DataWatcherHelper.DataWatcherSerializer_BOOLEAN = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("k").get(null);
|
||||
} else {
|
||||
DataWatcherHelper.DataWatcherSerializer_BOOLEAN = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("j").get(null);
|
||||
}
|
||||
} else {
|
||||
DataWatcherHelper.DataWatcherSerializer_OPTIONAL_COMPONENT = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("f").get(null);
|
||||
DataWatcherHelper.DataWatcherSerializer_BOOLEAN = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("i").get(null);
|
||||
}
|
||||
if (minorVersion >= 19) {
|
||||
PacketPlayOutSpawnEntityLivingStorage.EntityTypes_ARMOR_STAND = PacketPlayOutSpawnEntityLivingStorage.EntityTypes.getDeclaredField("d").get(null);
|
||||
(PacketPlayOutSpawnEntityLivingStorage.ENTITY_TYPE = PacketPlayOutSpawnEntityLivingStorage.CLASS.getDeclaredField("e")).setAccessible(true);
|
||||
DataWatcher.packDirty = DataWatcher.CLASS.getMethod("b");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadClasses() throws ClassNotFoundException {
|
||||
ChatSerializer = Class.forName("net.minecraft.network.chat.IChatBaseComponent$ChatSerializer");
|
||||
@@ -86,12 +54,9 @@ public class BukkitModernNMSStorage extends NMSStorage {
|
||||
PacketPlayOutEntityMetadataStorage.CLASS = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata");
|
||||
PacketPlayOutNamedEntitySpawn = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutNamedEntitySpawn");
|
||||
BukkitTabList.EnumGamemodeClass = (Class<Enum>) Class.forName("net.minecraft.world.level.EnumGamemode");
|
||||
if (minorVersion >= 19) {
|
||||
PacketPlayOutSpawnEntityLivingStorage.EntityTypes = Class.forName("net.minecraft.world.entity.EntityTypes");
|
||||
PacketPlayOutSpawnEntityLivingStorage.CLASS = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutSpawnEntity");
|
||||
} else {
|
||||
PacketPlayOutSpawnEntityLivingStorage.CLASS = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutSpawnEntityLiving");
|
||||
}
|
||||
PacketPlayOutSpawnEntityLivingStorage.Vec3D = Class.forName("net.minecraft.world.phys.Vec3D");
|
||||
PacketPlayOutSpawnEntityLivingStorage.EntityTypes = Class.forName("net.minecraft.world.entity.EntityTypes");
|
||||
PacketPlayOutSpawnEntityLivingStorage.CLASS = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutSpawnEntity");
|
||||
if (is1_19_3Plus()) {
|
||||
BukkitTabList.ClientboundPlayerInfoRemovePacket = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket");
|
||||
BukkitTabList.PacketPlayOutPlayerInfoClass = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket");
|
||||
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
package me.neznamy.tab.platforms.bukkit.nms.storage.nms;
|
||||
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitTabList;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcher;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcherHelper;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcherItem;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcherObject;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.storage.packet.*;
|
||||
import me.neznamy.tab.platforms.bukkit.scoreboard.PacketScoreboard;
|
||||
|
||||
/**
|
||||
* NMS loader for minecraft 1.17+ using Mojang packaging and names.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class MojangModernNMSStorage extends NMSStorage {
|
||||
|
||||
@Override
|
||||
public void loadNamedFieldsAndMethods() throws ReflectiveOperationException {
|
||||
ChatSerializer_DESERIALIZE = ChatSerializer.getMethod("fromJson", String.class);
|
||||
DataWatcher.REGISTER = DataWatcher.CLASS.getMethod("define", DataWatcherObject.CLASS, Object.class);
|
||||
PacketScoreboard.ScoreboardScore_setScore = PacketScoreboard.ScoreboardScoreClass.getMethod("setScore", int.class);
|
||||
PacketScoreboard.ScoreboardTeam_setAllowFriendlyFire = PacketScoreboard.ScoreboardTeam.getMethod("setAllowFriendlyFire", boolean.class);
|
||||
PacketScoreboard.ScoreboardTeam_setCanSeeFriendlyInvisibles = PacketScoreboard.ScoreboardTeam.getMethod("setSeeFriendlyInvisibles", boolean.class);
|
||||
PacketScoreboard.ScoreboardTeam_setPrefix = PacketScoreboard.ScoreboardTeam.getMethod("setPlayerPrefix", IChatBaseComponent);
|
||||
PacketScoreboard.ScoreboardTeam_setSuffix = PacketScoreboard.ScoreboardTeam.getMethod("setPlayerSuffix", IChatBaseComponent);
|
||||
PacketScoreboard.ScoreboardTeam_setNameTagVisibility = PacketScoreboard.ScoreboardTeam.getMethod("setNameTagVisibility", PacketScoreboard.EnumNameTagVisibility);
|
||||
DataWatcherHelper.DataWatcherSerializer_BYTE = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("BYTE").get(null);
|
||||
DataWatcherHelper.DataWatcherSerializer_FLOAT = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("FLOAT").get(null);
|
||||
DataWatcherHelper.DataWatcherSerializer_STRING = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("STRING").get(null);
|
||||
DataWatcherHelper.DataWatcherSerializer_OPTIONAL_COMPONENT = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("OPTIONAL_COMPONENT").get(null);
|
||||
DataWatcherHelper.DataWatcherSerializer_BOOLEAN = DataWatcherHelper.DataWatcherRegistry.getDeclaredField("BOOLEAN").get(null);
|
||||
if (minorVersion >= 19) {
|
||||
PacketPlayOutSpawnEntityLivingStorage.EntityTypes_ARMOR_STAND = PacketPlayOutSpawnEntityLivingStorage.EntityTypes.getDeclaredField("ARMOR_STAND").get(null);
|
||||
(PacketPlayOutSpawnEntityLivingStorage.ENTITY_TYPE = PacketPlayOutSpawnEntityLivingStorage.CLASS.getDeclaredField("type")).setAccessible(true);
|
||||
DataWatcher.packDirty = DataWatcher.CLASS.getMethod("packDirty");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadClasses() throws ClassNotFoundException {
|
||||
IChatBaseComponent = Class.forName("net.minecraft.network.chat.Component");
|
||||
ChatSerializer = Class.forName("net.minecraft.network.chat.Component$Serializer");
|
||||
World = Class.forName("net.minecraft.world.level.Level");
|
||||
EntityArmorStand = Class.forName("net.minecraft.world.entity.decoration.ArmorStand");
|
||||
EntityHuman = Class.forName("net.minecraft.world.entity.player.Player");
|
||||
NetworkManager = Class.forName("net.minecraft.network.Connection");
|
||||
Packet = Class.forName("net.minecraft.network.protocol.Packet");
|
||||
EnumChatFormat = (Class<Enum>) Class.forName("net.minecraft.ChatFormatting");
|
||||
EntityPlayer = Class.forName("net.minecraft.server.level.ServerPlayer");
|
||||
Entity = Class.forName("net.minecraft.world.entity.Entity");
|
||||
EntityLiving = Class.forName("net.minecraft.world.entity.LivingEntity");
|
||||
PlayerConnection = Class.forName("net.minecraft.server.network.ServerGamePacketListenerImpl");
|
||||
BukkitTabList.PacketPlayOutPlayerListHeaderFooterClass = Class.forName("net.minecraft.network.protocol.game.ClientboundTabListPacket");
|
||||
DataWatcher.CLASS = Class.forName("net.minecraft.network.syncher.SynchedEntityData");
|
||||
DataWatcherItem.CLASS = Class.forName("net.minecraft.network.syncher.SynchedEntityData$DataItem");
|
||||
DataWatcherObject.CLASS = Class.forName("net.minecraft.network.syncher.EntityDataAccessor");
|
||||
DataWatcherHelper.DataWatcherRegistry = Class.forName("net.minecraft.network.syncher.EntityDataSerializers");
|
||||
DataWatcherHelper.DataWatcherSerializer = Class.forName("net.minecraft.network.syncher.EntityDataSerializer");
|
||||
PacketPlayOutEntityTeleportStorage.CLASS = Class.forName("net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket");
|
||||
PacketPlayOutEntity = Class.forName("net.minecraft.network.protocol.game.ClientboundMoveEntityPacket");
|
||||
PacketPlayOutEntityDestroyStorage.CLASS = Class.forName("net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket");
|
||||
PacketPlayOutEntityLook = Class.forName("net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$Rot");
|
||||
PacketPlayOutEntityMetadataStorage.CLASS = Class.forName("net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket");
|
||||
PacketPlayOutNamedEntitySpawn = Class.forName("net.minecraft.network.protocol.game.ClientboundAddPlayerPacket");
|
||||
BukkitTabList.EnumGamemodeClass = (Class<Enum>) Class.forName("net.minecraft.world.level.GameType");
|
||||
PacketScoreboard.DisplayObjectiveClass = Class.forName("net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket");
|
||||
PacketScoreboard.ObjectivePacketClass = Class.forName("net.minecraft.network.protocol.game.ClientboundSetObjectivePacket");
|
||||
PacketScoreboard.Scoreboard = Class.forName("net.minecraft.world.scores.Scoreboard");
|
||||
PacketScoreboard.ScorePacketClass = Class.forName("net.minecraft.network.protocol.game.ClientboundSetScorePacket");
|
||||
PacketScoreboard.ScoreboardObjective = Class.forName("net.minecraft.world.scores.Objective");
|
||||
PacketScoreboard.ScoreboardScoreClass = Class.forName("net.minecraft.world.scores.Score");
|
||||
PacketScoreboard.IScoreboardCriteria = Class.forName("net.minecraft.world.scores.criteria.ObjectiveCriteria");
|
||||
PacketScoreboard.EnumScoreboardHealthDisplay = (Class<Enum>) Class.forName("net.minecraft.world.scores.criteria.ObjectiveCriteria$RenderType");
|
||||
PacketScoreboard.EnumScoreboardAction = (Class<Enum>) Class.forName("net.minecraft.server.ServerScoreboard$Method");
|
||||
PacketScoreboard.TeamPacketClass = Class.forName("net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket");
|
||||
PacketScoreboard.ScoreboardTeam = Class.forName("net.minecraft.world.scores.PlayerTeam");
|
||||
PacketScoreboard.EnumNameTagVisibility = (Class<Enum>) Class.forName("net.minecraft.world.scores.Team$Visibility");
|
||||
PacketScoreboard.EnumTeamPush = (Class<Enum>) Class.forName("net.minecraft.world.scores.Team$CollisionRule");
|
||||
if (minorVersion >= 19) {
|
||||
PacketPlayOutSpawnEntityLivingStorage.EntityTypes = Class.forName("net.minecraft.world.entity.EntityType");
|
||||
PacketPlayOutSpawnEntityLivingStorage.CLASS = Class.forName("net.minecraft.network.protocol.game.ClientboundAddEntityPacket");
|
||||
} else {
|
||||
PacketPlayOutSpawnEntityLivingStorage.CLASS = Class.forName("net.minecraft.network.protocol.game.ClientboundAddMobPacket");
|
||||
}
|
||||
if (is1_19_3Plus()) {
|
||||
BukkitTabList.ClientboundPlayerInfoRemovePacket = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket");
|
||||
BukkitTabList.PacketPlayOutPlayerInfoClass = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket");
|
||||
BukkitTabList.EnumPlayerInfoActionClass = (Class<Enum>) Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket$Action");
|
||||
BukkitTabList.PlayerInfoDataClass = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket$Entry");
|
||||
BukkitTabList.RemoteChatSession$Data = Class.forName("net.minecraft.network.chat.RemoteChatSession$Data");
|
||||
} else {
|
||||
BukkitTabList.PacketPlayOutPlayerInfoClass = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoPacket");
|
||||
BukkitTabList.EnumPlayerInfoActionClass = (Class<Enum>) Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoPacket$Action");
|
||||
BukkitTabList.PlayerInfoDataClass = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoPacket$PlayerUpdate");
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-11
@@ -6,6 +6,7 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.SneakyThrows;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitTabList;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcherHelper;
|
||||
import me.neznamy.tab.platforms.bukkit.scoreboard.PacketScoreboard;
|
||||
import me.neznamy.tab.shared.ProtocolVersion;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
@@ -97,8 +98,13 @@ public abstract class NMSStorage {
|
||||
sendPacket = ReflectionUtils.getMethod(PlayerConnection, new String[]{"sendPacket"}, Packet);
|
||||
}
|
||||
if (minorVersion >= 8) {
|
||||
ChatSerializer_DESERIALIZE = ChatSerializer.getMethod("a", String.class);
|
||||
CHANNEL = ReflectionUtils.getOnlyField(NetworkManager, Channel.class);
|
||||
getProfile = ReflectionUtils.getOnlyMethod(EntityHuman, GameProfile.class);
|
||||
try {
|
||||
getProfile = ReflectionUtils.getOnlyMethod(EntityHuman, GameProfile.class);
|
||||
} catch (IllegalStateException catServer) {
|
||||
getProfile = EntityHuman.getMethod("getProfile");
|
||||
}
|
||||
Constructor<?> newEntityArmorStand = EntityArmorStand.getConstructor(World, double.class, double.class, double.class);
|
||||
Method World_getHandle = Class.forName("org.bukkit.craftbukkit." + serverPackage + ".CraftWorld").getMethod("getHandle");
|
||||
dummyEntity = newEntityArmorStand.newInstance(World_getHandle.invoke(Bukkit.getWorlds().get(0)), 0, 0, 0);
|
||||
@@ -111,6 +117,7 @@ public abstract class NMSStorage {
|
||||
getHandle = Class.forName("org.bukkit.craftbukkit." + serverPackage + ".entity.CraftPlayer").getMethod("getHandle");
|
||||
DataWatcher.load(this);
|
||||
DataWatcherItem.load(this);
|
||||
DataWatcherHelper.load(this);
|
||||
PacketPlayOutEntityDestroyStorage.load();
|
||||
PacketPlayOutEntityMetadataStorage.load(this);
|
||||
PacketPlayOutEntityTeleportStorage.load(this);
|
||||
@@ -118,7 +125,6 @@ public abstract class NMSStorage {
|
||||
PacketScoreboard.load(this);
|
||||
PacketPlayOutEntity_ENTITYID = ReflectionUtils.getFields(PacketPlayOutEntity, int.class).get(0);
|
||||
PacketPlayOutNamedEntitySpawn_ENTITYID = ReflectionUtils.getFields(PacketPlayOutNamedEntitySpawn, int.class).get(0);
|
||||
loadNamedFieldsAndMethods();
|
||||
if (minorVersion < 17) {
|
||||
try {
|
||||
(PING = EntityPlayer.getDeclaredField("ping")).setAccessible(true); // 1.5.2 - 1.16.5
|
||||
@@ -136,15 +142,6 @@ public abstract class NMSStorage {
|
||||
*/
|
||||
public abstract void loadClasses() throws ClassNotFoundException;
|
||||
|
||||
/**
|
||||
* Loads all fields and methods which must be loaded by their name due to
|
||||
* lack of other methods of reliably retrieving them.
|
||||
*
|
||||
* @throws ReflectiveOperationException
|
||||
* If a field or method was not found
|
||||
*/
|
||||
public abstract void loadNamedFieldsAndMethods() throws ReflectiveOperationException;
|
||||
|
||||
/**
|
||||
* Converts TAB's IChatBaseComponent into minecraft's component using String deserialization.
|
||||
* If the requested component is found in cache, it is returned. If not, it is created, added into cache and returned.
|
||||
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
package me.neznamy.tab.platforms.bukkit.nms.storage.nms;
|
||||
|
||||
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcher;
|
||||
import me.neznamy.tab.platforms.bukkit.scoreboard.PacketScoreboard;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* NMS loader for Thermos 1.7.10.
|
||||
*/
|
||||
public class ThermosNMSStorage extends BukkitLegacyNMSStorage {
|
||||
|
||||
@Override
|
||||
public Class<?> getLegacyClass(@NotNull String name) throws ClassNotFoundException {
|
||||
try {
|
||||
return getClass().getClassLoader().loadClass("net.minecraft.server." + serverPackage + "." + name);
|
||||
} catch (NullPointerException e) {
|
||||
// nested class not found
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadNamedFieldsAndMethods() throws ReflectiveOperationException {
|
||||
PacketScoreboard.ScoreboardScore_setScore = PacketScoreboard.ScoreboardScoreClass.getMethod("func_96647_c", int.class);
|
||||
PacketScoreboard.ScoreboardTeam_setAllowFriendlyFire = PacketScoreboard.ScoreboardTeam.getMethod("func_96660_a", boolean.class);
|
||||
PacketScoreboard.ScoreboardTeam_setCanSeeFriendlyInvisibles = PacketScoreboard.ScoreboardTeam.getMethod("func_98300_b", boolean.class);
|
||||
DataWatcher.REGISTER = DataWatcher.CLASS.getMethod("func_75682_a", int.class, Object.class);
|
||||
PacketScoreboard.ScoreboardTeam_setPrefix = PacketScoreboard.ScoreboardTeam.getMethod("func_96666_b", String.class);
|
||||
PacketScoreboard.ScoreboardTeam_setSuffix = PacketScoreboard.ScoreboardTeam.getMethod("func_96662_c", String.class);
|
||||
}
|
||||
}
|
||||
+54
-56
@@ -20,8 +20,15 @@ public class PacketPlayOutSpawnEntityLivingStorage {
|
||||
|
||||
/** NMS Fields */
|
||||
public static Class<?> CLASS;
|
||||
public static Class<?> EntityTypes;
|
||||
public static Constructor<?> CONSTRUCTOR;
|
||||
|
||||
/** 1.17+ */
|
||||
public static Class<?> Vec3D;
|
||||
public static Class<?> EntityTypes;
|
||||
public static Object Vec3D_Empty;
|
||||
public static Object EntityTypes_ARMOR_STAND;
|
||||
|
||||
/** 1.16.5- */
|
||||
public static Field ENTITY_ID;
|
||||
public static Field ENTITY_TYPE;
|
||||
public static Field YAW;
|
||||
@@ -31,9 +38,6 @@ public class PacketPlayOutSpawnEntityLivingStorage {
|
||||
public static Field Y;
|
||||
public static Field Z;
|
||||
public static Field DATA_WATCHER;
|
||||
public static Object EntityTypes_ARMOR_STAND;
|
||||
|
||||
/** Entity types */
|
||||
public static final EnumMap<EntityType, Integer> entityIds = new EnumMap<>(EntityType.class);
|
||||
|
||||
/**
|
||||
@@ -44,47 +48,44 @@ public class PacketPlayOutSpawnEntityLivingStorage {
|
||||
* @throws NoSuchMethodException
|
||||
* If something fails
|
||||
*/
|
||||
public static void load(NMSStorage nms) throws NoSuchMethodException {
|
||||
if (nms.getMinorVersion() >= 19) {
|
||||
entityIds.put(EntityType.ARMOR_STAND, 2);
|
||||
} else if (nms.getMinorVersion() >= 13) {
|
||||
public static void load(NMSStorage nms) throws NoSuchMethodException, IllegalAccessException, NoSuchFieldException {
|
||||
int minorVersion = nms.getMinorVersion();
|
||||
if (minorVersion >= 13) {
|
||||
entityIds.put(EntityType.ARMOR_STAND, 1);
|
||||
} else {
|
||||
entityIds.put(EntityType.WITHER, 64);
|
||||
if (nms.getMinorVersion() >= 8) {
|
||||
if (minorVersion >= 8) {
|
||||
entityIds.put(EntityType.ARMOR_STAND, 30);
|
||||
}
|
||||
}
|
||||
|
||||
if (nms.getMinorVersion() >= 17) {
|
||||
CONSTRUCTOR = CLASS.getConstructor(nms.is1_19_3Plus() ? nms.Entity : nms.EntityLiving);
|
||||
|
||||
if (minorVersion >= 19) {
|
||||
EntityTypes_ARMOR_STAND = EntityTypes.getDeclaredField("d").get(null);
|
||||
CONSTRUCTOR = CLASS.getConstructor(int.class, UUID.class, double.class, double.class, double.class, float.class, float.class, EntityTypes, int.class, Vec3D, double.class);
|
||||
Vec3D_Empty = ReflectionUtils.getOnlyField(Vec3D, Vec3D).get(null);
|
||||
} else if (minorVersion >= 17) {
|
||||
EntityTypes_ARMOR_STAND = EntityTypes.getDeclaredField("c").get(null);
|
||||
CONSTRUCTOR = CLASS.getConstructor(int.class, UUID.class, double.class, double.class, double.class, float.class, float.class, EntityTypes, int.class, Vec3D);
|
||||
Vec3D_Empty = ReflectionUtils.getOnlyField(Vec3D, Vec3D).get(null);
|
||||
} else {
|
||||
CONSTRUCTOR = CLASS.getConstructor();
|
||||
}
|
||||
ENTITY_ID = ReflectionUtils.getFields(CLASS, int.class).get(0);
|
||||
YAW = ReflectionUtils.getFields(CLASS, byte.class).get(0);
|
||||
PITCH = ReflectionUtils.getFields(CLASS, byte.class).get(1);
|
||||
if (nms.getMinorVersion() >= 9) {
|
||||
UUID = ReflectionUtils.getOnlyField(CLASS, UUID.class);
|
||||
if (nms.getMinorVersion() >= 19) {
|
||||
X = ReflectionUtils.getFields(CLASS, double.class).get(2);
|
||||
Y = ReflectionUtils.getFields(CLASS, double.class).get(3);
|
||||
Z = ReflectionUtils.getFields(CLASS, double.class).get(4);
|
||||
} else {
|
||||
ENTITY_ID = ReflectionUtils.getFields(CLASS, int.class).get(0);
|
||||
YAW = ReflectionUtils.getFields(CLASS, byte.class).get(0);
|
||||
PITCH = ReflectionUtils.getFields(CLASS, byte.class).get(1);
|
||||
if (minorVersion >= 9) {
|
||||
UUID = ReflectionUtils.getOnlyField(CLASS, UUID.class);
|
||||
X = ReflectionUtils.getFields(CLASS, double.class).get(0);
|
||||
Y = ReflectionUtils.getFields(CLASS, double.class).get(1);
|
||||
Z = ReflectionUtils.getFields(CLASS, double.class).get(2);
|
||||
} else {
|
||||
X = ReflectionUtils.getFields(CLASS, int.class).get(2);
|
||||
Y = ReflectionUtils.getFields(CLASS, int.class).get(3);
|
||||
Z = ReflectionUtils.getFields(CLASS, int.class).get(4);
|
||||
}
|
||||
} else {
|
||||
X = ReflectionUtils.getFields(CLASS, int.class).get(2);
|
||||
Y = ReflectionUtils.getFields(CLASS, int.class).get(3);
|
||||
Z = ReflectionUtils.getFields(CLASS, int.class).get(4);
|
||||
}
|
||||
if (nms.getMinorVersion() < 19) {
|
||||
ENTITY_TYPE = ReflectionUtils.getFields(CLASS, int.class).get(1);
|
||||
}
|
||||
if (nms.getMinorVersion() <= 14) {
|
||||
DATA_WATCHER = ReflectionUtils.getOnlyField(CLASS, DataWatcher.CLASS);
|
||||
if (minorVersion <= 14) {
|
||||
DATA_WATCHER = ReflectionUtils.getOnlyField(CLASS, DataWatcher.CLASS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,35 +95,32 @@ public class PacketPlayOutSpawnEntityLivingStorage {
|
||||
* @return NMS packet
|
||||
*/
|
||||
@SneakyThrows
|
||||
public static Object build(int entityId, UUID id, Object entityType, Location location, EntityData data) {
|
||||
NMSStorage nms = NMSStorage.getInstance();
|
||||
Object nmsPacket;
|
||||
if (nms.getMinorVersion() >= 17) {
|
||||
nmsPacket = CONSTRUCTOR.newInstance(nms.dummyEntity);
|
||||
} else {
|
||||
nmsPacket = CONSTRUCTOR.newInstance();
|
||||
public static Object build(int id, UUID uuid, Object entityType, Location l, EntityData data) {
|
||||
int minorVersion = NMSStorage.getInstance().getMinorVersion();
|
||||
if (minorVersion >= 19) {
|
||||
return CONSTRUCTOR.newInstance(id, uuid, l.getX(), l.getY(), l.getZ(), l.getYaw(), l.getPitch(), EntityTypes_ARMOR_STAND, 0, Vec3D_Empty, 0d);
|
||||
}
|
||||
ENTITY_ID.set(nmsPacket, entityId);
|
||||
YAW.set(nmsPacket, (byte)(location.getYaw() * 256.0f / 360.0f));
|
||||
PITCH.set(nmsPacket, (byte)(location.getPitch() * 256.0f / 360.0f));
|
||||
if (nms.getMinorVersion() <= 14) {
|
||||
if (minorVersion >= 17) {
|
||||
return CONSTRUCTOR.newInstance(id, uuid, l.getX(), l.getY(), l.getZ(), l.getYaw(), l.getPitch(), EntityTypes_ARMOR_STAND, 0, Vec3D_Empty);
|
||||
}
|
||||
Object nmsPacket = CONSTRUCTOR.newInstance();
|
||||
ENTITY_ID.set(nmsPacket, id);
|
||||
YAW.set(nmsPacket, (byte)(l.getYaw() * 256.0f / 360.0f));
|
||||
PITCH.set(nmsPacket, (byte)(l.getPitch() * 256.0f / 360.0f));
|
||||
if (minorVersion <= 14) {
|
||||
DATA_WATCHER.set(nmsPacket, data.build());
|
||||
}
|
||||
if (nms.getMinorVersion() >= 9) {
|
||||
UUID.set(nmsPacket, id);
|
||||
X.set(nmsPacket, location.getX());
|
||||
Y.set(nmsPacket, location.getY());
|
||||
Z.set(nmsPacket, location.getZ());
|
||||
if (minorVersion >= 9) {
|
||||
UUID.set(nmsPacket, uuid);
|
||||
X.set(nmsPacket, l.getX());
|
||||
Y.set(nmsPacket, l.getY());
|
||||
Z.set(nmsPacket, l.getZ());
|
||||
} else {
|
||||
X.set(nmsPacket, floor(location.getX()*32));
|
||||
Y.set(nmsPacket, floor(location.getY()*32));
|
||||
Z.set(nmsPacket, floor(location.getZ()*32));
|
||||
}
|
||||
if (nms.getMinorVersion() >= 19) {
|
||||
ENTITY_TYPE.set(nmsPacket, EntityTypes_ARMOR_STAND); // :(
|
||||
} else {
|
||||
ENTITY_TYPE.set(nmsPacket, entityIds.get((EntityType) entityType));
|
||||
X.set(nmsPacket, floor(l.getX()*32));
|
||||
Y.set(nmsPacket, floor(l.getY()*32));
|
||||
Z.set(nmsPacket, floor(l.getZ()*32));
|
||||
}
|
||||
ENTITY_TYPE.set(nmsPacket, entityIds.get((EntityType) entityType));
|
||||
return nmsPacket;
|
||||
}
|
||||
|
||||
|
||||
+23
-15
@@ -1,10 +1,13 @@
|
||||
package me.neznamy.tab.platforms.bukkit;
|
||||
package me.neznamy.tab.platforms.bukkit.platform;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.SneakyThrows;
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitPipelineInjector;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitPlaceholderRegistry;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
|
||||
import me.neznamy.tab.shared.GroupManager;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
@@ -28,6 +31,7 @@ import me.neznamy.tab.shared.placeholders.expansion.TabExpansion;
|
||||
import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
@@ -118,20 +122,7 @@ public class BukkitPlatform implements BackendPlatform {
|
||||
TAB.getInstance().getPlaceholderManager().registerRelationalPlaceholder(identifier, pl.getRefreshInterval(identifier), (viewer, target) ->
|
||||
placeholderAPI ? PlaceholderAPI.setRelationalPlaceholders((Player) viewer.getPlayer(), (Player) target.getPlayer(), identifier) : identifier);
|
||||
} else if (identifier.startsWith("%sync:")) {
|
||||
String syncedPlaceholder = "%" + identifier.substring(6, identifier.length()-1) + "%";
|
||||
PlayerPlaceholderImpl[] ppl = new PlayerPlaceholderImpl[1];
|
||||
ppl[0] = pl.registerPlayerPlaceholder(identifier, refresh, p -> {
|
||||
try {
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
long time = System.nanoTime();
|
||||
ppl[0].updateValue(p, placeholderAPI ? PlaceholderAPI.setPlaceholders((Player) p.getPlayer(), syncedPlaceholder) : identifier);
|
||||
TAB.getInstance().getCPUManager().addPlaceholderTime(identifier, System.nanoTime()-time);
|
||||
});
|
||||
return null;
|
||||
} catch (UnsupportedOperationException e) {
|
||||
return "<Folia does not support sync placeholders>";
|
||||
}
|
||||
});
|
||||
registerSyncPlaceholder(identifier, refresh);
|
||||
} else if (identifier.startsWith("%server_")) {
|
||||
TAB.getInstance().getPlaceholderManager().registerServerPlaceholder(identifier, refresh, () ->
|
||||
placeholderAPI ? PlaceholderAPI.setPlaceholders(null, identifier) : identifier);
|
||||
@@ -141,6 +132,19 @@ public class BukkitPlatform implements BackendPlatform {
|
||||
}
|
||||
}
|
||||
|
||||
public void registerSyncPlaceholder(String identifier, int refresh) {
|
||||
String syncedPlaceholder = "%" + identifier.substring(6);
|
||||
PlayerPlaceholderImpl[] ppl = new PlayerPlaceholderImpl[1];
|
||||
ppl[0] = TAB.getInstance().getPlaceholderManager().registerPlayerPlaceholder(identifier, refresh, p -> {
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
long time = System.nanoTime();
|
||||
ppl[0].updateValue(p, placeholderAPI ? PlaceholderAPI.setPlaceholders((Player) p.getPlayer(), syncedPlaceholder) : identifier);
|
||||
TAB.getInstance().getCPUManager().addPlaceholderTime(identifier, System.nanoTime()-time);
|
||||
});
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendConsoleMessage(@NotNull IChatBaseComponent message) {
|
||||
Bukkit.getConsoleSender().sendMessage("[TAB] " + RGBUtils.getInstance().convertToBukkitFormat(message.toFlatText(),
|
||||
@@ -165,4 +169,8 @@ public class BukkitPlatform implements BackendPlatform {
|
||||
}
|
||||
return new GroupManager("None", p -> TabConstants.NO_GROUP);
|
||||
}
|
||||
|
||||
public void runEntityTask(Entity entity, Runnable task) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package me.neznamy.tab.platforms.bukkit.platform;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import me.neznamy.tab.platforms.bukkit.features.PerWorldPlayerList;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.placeholders.PlayerPlaceholderImpl;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Platform override for Folia
|
||||
*/
|
||||
public class FoliaPlatform extends BukkitPlatform {
|
||||
|
||||
public FoliaPlatform(JavaPlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadPlayers() {
|
||||
super.loadPlayers();
|
||||
|
||||
// Values are never updated in the API, warn users
|
||||
TAB.getInstance().sendConsoleMessage("&cFolia never updates MSPT and TPS values in the API, making " +
|
||||
"%mspt% and %tps% return the default values (0 and 20).", true);
|
||||
|
||||
// Folia never calls PlayerChangedWorldEvent, this is a workaround
|
||||
TAB.getInstance().getCPUManager().startRepeatingMeasuredTask(100, "Folia compatibility", "Refreshing world", () -> {
|
||||
for (TabPlayer player : TAB.getInstance().getOnlinePlayers()) {
|
||||
String bukkitWorld = ((Player)player.getPlayer()).getWorld().getName();
|
||||
if (!player.getWorld().equals(bukkitWorld)) {
|
||||
TAB.getInstance().getFeatureManager().onWorldChange(player.getUniqueId(), bukkitWorld);
|
||||
PerWorldPlayerList pwp = TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.PER_WORLD_PLAYER_LIST);
|
||||
if (pwp != null) {
|
||||
runSync((Entity) player.getPlayer(), () -> pwp.onWorldChange(new PlayerChangedWorldEvent((Player) player.getPlayer(), ((Player) player.getPlayer()).getWorld())));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSyncPlaceholder(String identifier, int refresh) {
|
||||
String syncedPlaceholder = "%" + identifier.substring(6);
|
||||
PlayerPlaceholderImpl[] ppl = new PlayerPlaceholderImpl[1];
|
||||
ppl[0] = TAB.getInstance().getPlaceholderManager().registerPlayerPlaceholder(identifier, refresh, p -> {
|
||||
runSync((Entity) p.getPlayer(), () -> {
|
||||
long time = System.nanoTime();
|
||||
String output = isPlaceholderAPI() ? PlaceholderAPI.setPlaceholders((Player) p.getPlayer(), syncedPlaceholder) : identifier;
|
||||
TAB.getInstance().getCPUManager().addPlaceholderTime(identifier, System.nanoTime()-time);
|
||||
TAB.getInstance().getCPUManager().runTask(() -> ppl[0].updateValue(p, output)); // To ensure player is loaded
|
||||
});
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs task using player's entity scheduler. It's using reflection, because
|
||||
* Folia uses Java 17 while TAB maintains Java 8 compatibility for compatibility
|
||||
* with MC versions older than their player base.
|
||||
*
|
||||
* @param entity
|
||||
* entity to run task for
|
||||
* @param task
|
||||
* Task to run
|
||||
*/
|
||||
@SneakyThrows
|
||||
@SuppressWarnings("JavaReflectionMemberAccess")
|
||||
private void runSync(Entity entity, Runnable task) {
|
||||
Object entityScheduler = Entity.class.getMethod("getScheduler").invoke(entity);
|
||||
Consumer<?> consumer = $ -> task.run(); // Reflection and lambdas don't go together
|
||||
entityScheduler.getClass().getMethod("run", Plugin.class, Consumer.class, Runnable.class)
|
||||
.invoke(entityScheduler, getPlugin(), consumer, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runEntityTask(Entity entity, Runnable task) {
|
||||
runSync(entity, task);
|
||||
}
|
||||
}
|
||||
@@ -115,15 +115,22 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
TeamPacket_ACTION = ReflectionUtils.getInstanceFields(TeamPacketClass, int.class).get(0);
|
||||
TeamPacket_PLAYERS = ReflectionUtils.getOnlyField(TeamPacketClass, Collection.class);
|
||||
ScoreboardTeam_getPlayerNameSet = ReflectionUtils.getOnlyMethod(ScoreboardTeam, Collection.class);
|
||||
ScoreboardScore_setScore = ReflectionUtils.getMethod(ScoreboardScoreClass, new String[] {"func_96647_c", "setScore", "b", "c"}, int.class); // {Thermos, 1.5.1 - 1.17.1, 1.18+, 1.5}
|
||||
ScoreboardTeam_setAllowFriendlyFire = ReflectionUtils.getMethod(ScoreboardTeam, new String[] {"func_96660_a", "setAllowFriendlyFire", "a"}, boolean.class); // {Thermos, 1.5.1+, 1.5 & 1.18+}
|
||||
ScoreboardTeam_setCanSeeFriendlyInvisibles = ReflectionUtils.getMethod(ScoreboardTeam, new String[] {"func_98300_b", "setCanSeeFriendlyInvisibles", "b"}, boolean.class); // {Thermos, 1.5.1+, 1.5 & 1.18+}
|
||||
if (nms.getMinorVersion() >= 13) {
|
||||
newScorePacket_1_13 = ScorePacketClass.getConstructor(EnumScoreboardAction, String.class, String.class, int.class);
|
||||
newObjectivePacket = ObjectivePacketClass.getConstructor(ScoreboardObjective, int.class);
|
||||
Objective_DISPLAY_NAME = ReflectionUtils.getOnlyField(ObjectivePacketClass, nms.IChatBaseComponent);
|
||||
ScoreboardTeam_setColor = ReflectionUtils.getOnlyMethod(ScoreboardTeam, void.class, nms.EnumChatFormat);
|
||||
ScoreboardTeam_setPrefix = ReflectionUtils.getMethod(ScoreboardTeam, new String[]{"setPrefix", "b"}, nms.IChatBaseComponent); // {1.17.1-, 1.18+}
|
||||
ScoreboardTeam_setSuffix = ReflectionUtils.getMethod(ScoreboardTeam, new String[]{"setSuffix", "c"}, nms.IChatBaseComponent); // {1.17.1-, 1.18+}
|
||||
} else {
|
||||
newScorePacket_String = ScorePacketClass.getConstructor(String.class);
|
||||
newObjectivePacket = ObjectivePacketClass.getConstructor();
|
||||
Objective_DISPLAY_NAME = ReflectionUtils.getFields(ObjectivePacketClass, String.class).get(1);
|
||||
ScoreboardTeam_setPrefix = ReflectionUtils.getMethod(ScoreboardTeam, new String[] {"func_96666_b", "setPrefix", "b"}, String.class); // {Thermos, 1.5.1+, 1.5}
|
||||
ScoreboardTeam_setSuffix = ReflectionUtils.getMethod(ScoreboardTeam, new String[] {"func_96662_c", "setSuffix", "c"}, String.class); // {Thermos, 1.5.1+, 1.5}
|
||||
if (nms.getMinorVersion() >= 8) {
|
||||
newScorePacket = ScorePacketClass.getConstructor(ScoreboardScoreClass);
|
||||
Objective_RENDER_TYPE = ReflectionUtils.getOnlyField(ObjectivePacketClass, EnumScoreboardHealthDisplay);
|
||||
@@ -131,6 +138,9 @@ public class PacketScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
newScorePacket = ScorePacketClass.getConstructor(ScoreboardScoreClass, int.class);
|
||||
}
|
||||
}
|
||||
if (nms.getMinorVersion() >= 8) {
|
||||
ScoreboardTeam_setNameTagVisibility = ReflectionUtils.getMethod(ScoreboardTeam, new String[] {"setNameTagVisibility", "a"}, EnumNameTagVisibility); // {1.8.1+, 1.8 & 1.18+}
|
||||
}
|
||||
if (nms.getMinorVersion() >= 9) {
|
||||
ScoreboardTeam_setCollisionRule = ReflectionUtils.getOnlyMethod(ScoreboardTeam, void.class, EnumTeamPush);
|
||||
}
|
||||
|
||||
+7
-1
@@ -2,10 +2,12 @@ package me.neznamy.tab.platforms.bukkit.scoreboard;
|
||||
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.shared.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.platform.Scoreboard;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.scoreboard.Objective;
|
||||
import org.bukkit.scoreboard.RenderType;
|
||||
import org.bukkit.scoreboard.Team;
|
||||
@@ -27,7 +29,9 @@ import java.util.Collection;
|
||||
* changes and fields fail to load. Or as a complete replacement
|
||||
* if compatibility with other plugins turns out not to be a problem.
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions") // Throw the NPE if something is not as expected, parent class should ensure it anyway
|
||||
// Throw the NPE if something is not as expected, parent class should ensure it anyway
|
||||
// Use Bukkit setColor, the adventure one does not support magic codes while they are permitted
|
||||
@SuppressWarnings({"ConstantConditions", "deprecation"})
|
||||
public class PaperScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
|
||||
private final org.bukkit.scoreboard.Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
|
||||
@@ -85,6 +89,7 @@ public class PaperScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
Team team = scoreboard.registerNewTeam(name);
|
||||
team.prefix(toAdventure(prefix));
|
||||
team.suffix(toAdventure(suffix));
|
||||
team.setColor(ChatColor.valueOf(EnumChatFormat.lastColorsOf(prefix).name()));
|
||||
team.setOption(Team.Option.NAME_TAG_VISIBILITY, Team.OptionStatus.values()[visibility.ordinal()]);
|
||||
team.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.values()[collision.ordinal()]);
|
||||
players.forEach(team::addEntry);
|
||||
@@ -105,6 +110,7 @@ public class PaperScoreboard extends Scoreboard<BukkitTabPlayer> {
|
||||
Team team = scoreboard.getTeam(name);
|
||||
team.prefix(toAdventure(prefix));
|
||||
team.suffix(toAdventure(suffix));
|
||||
team.setColor(ChatColor.valueOf(EnumChatFormat.lastColorsOf(prefix).name()));
|
||||
team.setOption(Team.Option.NAME_TAG_VISIBILITY, Team.OptionStatus.values()[visibility.ordinal()]);
|
||||
team.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.values()[collision.ordinal()]);
|
||||
team.setAllowFriendlyFire((options & 0x01) != 0);
|
||||
|
||||
@@ -11,7 +11,7 @@ softdepend: [PlaceholderAPI, LuckPerms, LibsDisguises, ViaVersion, ViaRewind, fl
|
||||
loadbefore: []
|
||||
prefix: TAB
|
||||
libraries: []
|
||||
folia-supported: false
|
||||
folia-supported: true
|
||||
commands:
|
||||
tab:
|
||||
description: Plugin's main command
|
||||
|
||||
@@ -54,11 +54,20 @@ public class CpuManager {
|
||||
|
||||
for (Entry<String, Long> entry : placeholderUsagePrevious.entrySet()) {
|
||||
float usagePercent = nanosToPercent(entry.getValue());
|
||||
if (usagePercent > 50) {
|
||||
if (usagePercent > 30) {
|
||||
TAB.getInstance().sendConsoleMessage("&c[WARN] CPU usage of placeholder " + entry.getKey() +
|
||||
" is " + (int)usagePercent + "%. It will most likely cause problems. Try increasing refresh interval.", true);
|
||||
}
|
||||
}
|
||||
Map<String, Map<String, Float>> features = getFeatureUsage();
|
||||
double featuresTotal = 0;
|
||||
for (Map<String, Float> map : features.values()) {
|
||||
featuresTotal += map.values().stream().mapToDouble(Float::floatValue).sum();
|
||||
}
|
||||
if (featuresTotal > 90) {
|
||||
TAB.getInstance().sendConsoleMessage("&c[WARN] CPU usage of the plugin is "
|
||||
+ (int)featuresTotal + "%. This will cause problems. Check /tab cpu to find out why.", true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -306,6 +306,9 @@ public class FeatureManager {
|
||||
if (configuration.getConfig().getBoolean("per-world-playerlist.enabled", false)) {
|
||||
TabFeature pwp = TAB.getInstance().getPlatform().getPerWorldPlayerList();
|
||||
if (pwp != null) featureManager.registerFeature(TabConstants.Feature.PER_WORLD_PLAYER_LIST, pwp);
|
||||
if (configuration.getConfig().getBoolean("layout.enabled", false)) {
|
||||
TAB.getInstance().getMisconfigurationHelper().bothPerWorldPlayerListAndLayoutEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
if (configuration.getConfig().getBoolean("yellow-number-in-tablist.enabled", true))
|
||||
|
||||
@@ -187,6 +187,13 @@ public class MisconfigurationHelper {
|
||||
"Disable global playerlist for the same result, but with better performance.");
|
||||
}
|
||||
|
||||
public void bothPerWorldPlayerListAndLayoutEnabled() {
|
||||
startupWarn("Both per world playerlist and layout features are enabled, but layout makes per world playerlist redundant.",
|
||||
"Layout automatically works with all connected players and replaces real player entries with" +
|
||||
" fake players, making per world playerlist completely useless as real players are pushed out of the playerlist.",
|
||||
"Disable per world playerlist for the same result, but with better performance.");
|
||||
}
|
||||
|
||||
public void checkLayoutMap(@NotNull String layoutName, @NotNull Map<String, Object> map) {
|
||||
List<String> expectedKeys = Arrays.asList("condition", "fixed-slots", "groups");
|
||||
for (String mapKey : map.keySet()) {
|
||||
|
||||
+2
@@ -202,4 +202,6 @@ public abstract class BackendNameTagX extends NameTagX implements GameModeListen
|
||||
public abstract double getZ(@NotNull TabPlayer player);
|
||||
|
||||
public abstract EntityData createDataWatcher(@NotNull TabPlayer viewer, byte flags, @NotNull String displayName, boolean nameVisible);
|
||||
|
||||
public abstract void runInEntityScheduler(Object entity, Runnable task);
|
||||
}
|
||||
+7
-3
@@ -62,7 +62,7 @@ public class VehicleRefresher extends TabFeature implements JoinListener, QuitLi
|
||||
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()) {
|
||||
Object vehicle = feature.getVehicle(p);
|
||||
if (vehicle != null) {
|
||||
vehicles.put(feature.getEntityId(vehicle), feature.getPassengers(vehicle));
|
||||
updateVehicle(vehicle);
|
||||
playersInVehicle.put(p, vehicle);
|
||||
if (feature.isDisableOnBoats() && feature.getEntityType(vehicle).contains("boat")) {
|
||||
playersOnBoats.add(p);
|
||||
@@ -74,7 +74,7 @@ public class VehicleRefresher extends TabFeature implements JoinListener, QuitLi
|
||||
@Override
|
||||
public void onJoin(@NotNull TabPlayer connectedPlayer) {
|
||||
Object vehicle = feature.getVehicle(connectedPlayer);
|
||||
if (vehicle != null) vehicles.put(feature.getEntityId(vehicle), feature.getPassengers(vehicle));
|
||||
if (vehicle != null) updateVehicle(vehicle);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,7 +102,7 @@ public class VehicleRefresher extends TabFeature implements JoinListener, QuitLi
|
||||
}
|
||||
if (!playersInVehicle.containsKey(p) && vehicle != null) {
|
||||
//vehicle enter
|
||||
vehicles.put(feature.getEntityId(vehicle), feature.getPassengers(vehicle));
|
||||
updateVehicle(vehicle);
|
||||
feature.getArmorStandManager(p).respawn(); //making teleport instant instead of showing teleport animation
|
||||
playersInVehicle.put(p, vehicle);
|
||||
if (feature.isDisableOnBoats() && feature.getEntityType(vehicle).contains("boat")) {
|
||||
@@ -123,4 +123,8 @@ public class VehicleRefresher extends TabFeature implements JoinListener, QuitLi
|
||||
public boolean isOnBoat(@NotNull TabPlayer p) {
|
||||
return playersOnBoats.contains(p);
|
||||
}
|
||||
|
||||
private void updateVehicle(Object vehicle) {
|
||||
feature.runInEntityScheduler(vehicle, () -> vehicles.put(feature.getEntityId(vehicle), feature.getPassengers(vehicle)));
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import me.neznamy.tab.shared.features.nametags.NameTag;
|
||||
import me.neznamy.tab.shared.features.nametags.unlimited.NameTagX;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
import me.neznamy.tab.shared.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.shared.config.file.ConfigurationFile;
|
||||
@@ -66,6 +67,11 @@ public class DebugCommand extends SubCommand {
|
||||
sendMessage(sender, "&6Storage type: &b" + (tab.getConfiguration().getGroups() instanceof ConfigurationFile ? "File" : "MySQL"));
|
||||
sendMessage(sender, separator);
|
||||
if (analyzed == null) return;
|
||||
if (!analyzed.isLoaded()) {
|
||||
sendMessage(sender, "&cThe specified player is not loaded. This is either because player failed to load" +
|
||||
" due to an error (see TAB's folder for errors.log file) or the plugin is overloaded (see /tab cpu).");
|
||||
return;
|
||||
}
|
||||
sendMessage(sender, "&ePlayer: &a" + analyzed.getName());
|
||||
if (analyzed instanceof ProxyTabPlayer) {
|
||||
sendMessage(sender, "&eBridge connection: " + (((ProxyTabPlayer)analyzed).isBridgeConnected() ? "&aConnected" : "&cNot connected"));
|
||||
@@ -88,8 +94,12 @@ public class DebugCommand extends SubCommand {
|
||||
boolean disabledNametags = ((NameTag) tab.getNameTagManager()).getDisableChecker().isDisabledPlayer(analyzed);
|
||||
showProperty(sender, analyzed, TabConstants.Property.TAGPREFIX, disabledNametags);
|
||||
showProperty(sender, analyzed, TabConstants.Property.TAGSUFFIX, disabledNametags);
|
||||
for (String line : getExtraLines()) {
|
||||
showProperty(sender, analyzed, line, disabledNametags);
|
||||
NameTagX nameTagX = TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS);
|
||||
if (nameTagX != null) {
|
||||
boolean disabledUnlimited = nameTagX.isPlayerDisabled(analyzed);
|
||||
for (String line : getExtraLines()) {
|
||||
showProperty(sender, analyzed, line, disabledUnlimited);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sendMessage(sender, "&atagprefix: &cDisabled");
|
||||
|
||||
@@ -44,6 +44,10 @@ public class ParseCommand extends SubCommand {
|
||||
}
|
||||
}
|
||||
String replaced = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
|
||||
if (!replaced.contains("%")) {
|
||||
sendMessage(sender, "&cThe provided input (" + replaced + ") does not contain any placeholders, therefore there's nothing to test.");
|
||||
return;
|
||||
}
|
||||
String message = EnumChatFormat.color("&6Replacing placeholder &e%placeholder% &6for player &e" + target.getName()).replace("%placeholder%", replaced);
|
||||
sendRawMessage(sender, message);
|
||||
try {
|
||||
|
||||
@@ -26,24 +26,33 @@ public class FixedSlot extends TabFeature implements Refreshable {
|
||||
private final UUID id;
|
||||
private final String text;
|
||||
private final String propertyName;
|
||||
private final TabList.Skin skin;
|
||||
private final String skin;
|
||||
private final String skinProperty;
|
||||
private final int ping;
|
||||
|
||||
@Override
|
||||
public void refresh(@NotNull TabPlayer p, boolean force) {
|
||||
if (!manager.getViews().containsKey(p) || manager.getViews().get(p).getPattern() != pattern || p.getVersion().getMinorVersion() < 8 || p.isBedrockPlayer()) return;
|
||||
p.getTabList().updateDisplayName(id, IChatBaseComponent.optimizedComponent(p.getProperty(propertyName).updateAndGet()));
|
||||
|
||||
boolean updateName = p.getProperty(propertyName).update(); // update property so skin change can use new name, avoids sending both packets
|
||||
if (p.getProperty(skinProperty).update()) {
|
||||
p.getTabList().removeEntry(id);
|
||||
p.getTabList().addEntry(createEntry(p));
|
||||
return;
|
||||
}
|
||||
if (updateName) p.getTabList().updateDisplayName(id, IChatBaseComponent.optimizedComponent(p.getProperty(propertyName).get()));
|
||||
}
|
||||
|
||||
public @NotNull TabList.Entry createEntry(@NotNull TabPlayer viewer) {
|
||||
viewer.setProperty(this, propertyName, text);
|
||||
viewer.setProperty(this, skinProperty, skin);
|
||||
return new TabList.Entry(
|
||||
id,
|
||||
manager.getDirection().getEntryName(viewer, slot),
|
||||
skin,
|
||||
manager.getSkinManager().getSkin(viewer.getProperty(skinProperty).get()),
|
||||
ping,
|
||||
0,
|
||||
IChatBaseComponent.optimizedComponent(viewer.getProperty(propertyName).updateAndGet()) // maybe just get is fine?
|
||||
IChatBaseComponent.optimizedComponent(viewer.getProperty(propertyName).get())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -69,11 +78,12 @@ public class FixedSlot extends TabFeature implements Refreshable {
|
||||
pattern,
|
||||
manager.getUUID(slot),
|
||||
text,
|
||||
"Layout-" + line + "-SLOT-" + slot,
|
||||
manager.getSkinManager().getSkin(skin.length() == 0 ? manager.getDefaultSkin() : skin),
|
||||
"Layout-" + pattern.getName() + "-SLOT-" + slot,
|
||||
skin.length() == 0 ? manager.getDefaultSkin() : skin,
|
||||
"Layout-" + pattern.getName() + "-SLOT-" + slot + "-skin",
|
||||
ping
|
||||
);
|
||||
if (text.length() > 0) TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.layoutSlot(line, slot), f);
|
||||
if (text.length() > 0) TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.layoutSlot(pattern.getName(), slot), f);
|
||||
return f;
|
||||
}
|
||||
}
|
||||
@@ -93,7 +93,8 @@ public class LayoutPattern extends TabFeature implements Refreshable, Layout {
|
||||
@Override
|
||||
public void addFixedSlot(int slot, @NonNull String text, @NonNull String skin, int ping) {
|
||||
fixedSlots.put(slot, new FixedSlot(manager, slot, this, manager.getUUID(slot), text,
|
||||
"Layout-" + text + "-SLOT-" + slot, manager.getSkinManager().getSkin(skin), ping));
|
||||
"Layout-" + text + "-SLOT-" + slot, skin, "Layout-" + text + "-SLOT-" + slot+ "-skin", ping));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+6
-2
@@ -56,7 +56,7 @@ public abstract class NameTagX extends NameTag implements UnlimitedNameTagManage
|
||||
updateProperties(all);
|
||||
armorStandManagerMap.put(all, armorStandFunction.apply(this, all));
|
||||
if (unlimitedDisableChecker.isDisableConditionMet(all)) {
|
||||
unlimitedDisableChecker.addDisabledPlayer(all);
|
||||
addDisabledPlayer(all);
|
||||
}
|
||||
TAB.getInstance().getPlaceholderManager().getTabExpansion().setNameTagPreview(all, false);
|
||||
}
|
||||
@@ -66,12 +66,16 @@ public abstract class NameTagX extends NameTag implements UnlimitedNameTagManage
|
||||
@Override
|
||||
public void onJoin(@NotNull TabPlayer connectedPlayer) {
|
||||
if (unlimitedDisableChecker.isDisableConditionMet(connectedPlayer))
|
||||
unlimitedDisableChecker.addDisabledPlayer(connectedPlayer);
|
||||
addDisabledPlayer(connectedPlayer);
|
||||
super.onJoin(connectedPlayer);
|
||||
armorStandManagerMap.put(connectedPlayer, armorStandFunction.apply(this, connectedPlayer));
|
||||
TAB.getInstance().getPlaceholderManager().getTabExpansion().setNameTagPreview(connectedPlayer, false);
|
||||
}
|
||||
|
||||
public void addDisabledPlayer(@NotNull TabPlayer player) {
|
||||
unlimitedDisableChecker.addDisabledPlayer(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(@NotNull TabPlayer refreshed, boolean force) {
|
||||
super.refresh(refreshed, force);
|
||||
|
||||
@@ -35,14 +35,16 @@ public class ViaVersionHook {
|
||||
int version = Via.getAPI().getPlayerVersion(player);
|
||||
if (version == -1) {
|
||||
TAB.getInstance().sendConsoleMessage("&cViaVersion returned protocol version -1 for player " + playerName +
|
||||
". Using version of the server (" + TAB.getInstance().getServerVersion().getNetworkId() + ")", true);
|
||||
". Using server's version (" + TAB.getInstance().getServerVersion().getNetworkId() + " - " +
|
||||
TAB.getInstance().getServerVersion().getFriendlyName() + ")", true);
|
||||
return TAB.getInstance().getServerVersion().getNetworkId();
|
||||
}
|
||||
TAB.getInstance().debug("ViaVersion returned protocol version " + version + " for " + playerName);
|
||||
ProtocolVersion protocol = ProtocolVersion.fromNetworkId(version);
|
||||
if (protocol == ProtocolVersion.UNKNOWN_CLIENT_VERSION) {
|
||||
TAB.getInstance().sendConsoleMessage("&cViaVersion returned unknown protocol version " + version +
|
||||
" for player " + playerName + ". This may result in plugin not working correctly for them.", true);
|
||||
} else {
|
||||
TAB.getInstance().debug("ViaVersion returned protocol version " + version + " for " + playerName);
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ public class ServerPlaceholderImpl extends TabPlaceholder implements ServerPlace
|
||||
if (identifier.startsWith("%rel_")) throw new IllegalArgumentException("\"rel_\" is reserved for relational placeholder identifiers");
|
||||
this.supplier = supplier;
|
||||
update0();
|
||||
if (lastValue == null) lastValue = identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+8
-1
@@ -11,6 +11,7 @@ import me.neznamy.tab.shared.placeholders.conditions.Condition;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
@@ -22,7 +23,13 @@ import java.util.Map.Entry;
|
||||
public class UniversalPlaceholderRegistry implements PlaceholderRegistry {
|
||||
|
||||
/** Decimal formatter for 2 decimal places */
|
||||
private final DecimalFormat decimal2 = new DecimalFormat("#.##");
|
||||
private final DecimalFormat decimal2;
|
||||
|
||||
public UniversalPlaceholderRegistry() {
|
||||
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
|
||||
symbols.setDecimalSeparator('.');
|
||||
decimal2 = new DecimalFormat("#.##", symbols);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
|
||||
+6
@@ -39,6 +39,12 @@ public class ProxyNameTagX extends NameTagX {
|
||||
((ProxyTabPlayer)p).sendPluginMessage("NameTagX", "SetEnabled", !disabledNow && !getDisableChecker().isDisabledPlayer(p));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDisabledPlayer(@NotNull TabPlayer player) {
|
||||
super.addDisabledPlayer(player);
|
||||
((ProxyTabPlayer)player).sendPluginMessage("NameTagX", "SetEnabled", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisableConditionChange(TabPlayer p, boolean disabledNow) {
|
||||
super.onDisableConditionChange(p, disabledNow);
|
||||
|
||||
@@ -19,12 +19,7 @@ import org.slf4j.Logger;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Main class for Velocity platform.
|
||||
* The velocity-plugin.json is manually deleted from releases and therefore
|
||||
* requires manual compilation. This avoids unnecessary complications
|
||||
* and bug reports from an unsupported platform.
|
||||
* Most of the reasons why Velocity is not and will not be supported are listed at
|
||||
* https://gist.github.com/NEZNAMY/21c1aabe57a0a462ee175386c510fdf8
|
||||
* Main class for Velocity.
|
||||
*/
|
||||
@Plugin(
|
||||
id = TabConstants.PLUGIN_ID,
|
||||
@@ -64,6 +59,9 @@ public class VelocityTAB {
|
||||
server.getChannelRegistrar().register(minecraftChannelIdentifier);
|
||||
server.getEventManager().register(this, new VelocityEventListener());
|
||||
TAB.setInstance(new TAB(new VelocityPlatform(this, server), ProtocolVersion.PROXY, dataFolder.toFile()));
|
||||
TAB.getInstance().sendConsoleMessage("&c[WARN] Velocity compatibility is very experimental and should not be used in production! " +
|
||||
"If you use it, you WILL run into issues and they WILL NOT be fixed. Any bug reports featuring Velocity installation " +
|
||||
"will be immediately closed.", true);
|
||||
TAB.getInstance().load();
|
||||
metricsFactory.make(this, 10533).addCustomChart(new SimplePie(TabConstants.MetricsChart.GLOBAL_PLAYER_LIST_ENABLED,
|
||||
() -> TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.GLOBAL_PLAYER_LIST) ? "Yes" : "No"));
|
||||
|
||||
Reference in new issue
Block a user