Compare commits

...
49 Commits
Author SHA1 Message Date
NEZNAMY 189797aa73 Bukkit - Use the other constructor for player info packet which is cleaner (also #797) 2023-01-21 00:18:19 +01:00
NEZNAMY 1ae2ef7cad Fix compilation 2023-01-21 00:17:02 +01:00
NEZNAMY de14e14d33 Revert "Placeholders - Add timeout for placeholders to return value, causing TAB to freeze"
This reverts commit 37caed3123.
2023-01-19 22:30:09 +01:00
NEZNAMY 19892c14c1 Revert "Placeholders - Increase placeholder retrieve timeout to 500ms (#792)"
This reverts commit 6d85875fde.
2023-01-19 22:29:59 +01:00
NEZNAMY 2e00c4c002 Revert "NameTags - Fix error that doesn't make sense (#794)"
This reverts commit 12f5dd52b4.
2023-01-19 22:29:52 +01:00
NEZNAMY 97aa367629 Revert "Fix thread pool not being single threaded (maybe #781?)"
This reverts commit 87cc9a030b.
2023-01-19 22:28:22 +01:00
NEZNAMY 87cc9a030b Fix thread pool not being single threaded (maybe #781?) 2023-01-19 22:01:11 +01:00
NEZNAMY 8ba83d1cb1 BossBar - Fix errors when progress is below 0 or above 100 2023-01-19 16:59:05 +01:00
NEZNAMY 9f0e60bd47 Per world PlayerList - Remove redundant task schedule to main thread 2023-01-19 16:58:45 +01:00
NEZNAMY 93b2a25b2e Merge pull request #795 from Chris6ix/update-actions
Update Actions
2023-01-17 22:01:37 +01:00
Chris 4242d7a839 Remove Test Build Trigger 2023-01-17 21:33:33 +01:00
Chris 0ddb99bd46 Trigger Test Build 2023-01-17 21:29:34 +01:00
Chris 969672e3ad Update Actions 2023-01-17 21:26:40 +01:00
NEZNAMY 2423fbb150 Update README.md 2023-01-17 20:28:47 +01:00
NEZNAMY a99928dbf5 Placeholders - Colorize output of relational placeholders as well 2023-01-17 20:25:06 +01:00
NEZNAMY 12f5dd52b4 NameTags - Fix error that doesn't make sense (#794) 2023-01-17 15:38:20 +01:00
NEZNAMY 2bd105446e Bukkit - Properly send RGB messages into console (only for Paper+, Spigot doesn't support RGB at all) 2023-01-17 14:11:51 +01:00
NEZNAMY 6d85875fde Placeholders - Increase placeholder retrieve timeout to 500ms (#792) 2023-01-16 18:49:23 +01:00
NEZNAMY 42810aa490 3.2.3-SNAPSHOT 2023-01-16 18:47:42 +01:00
NEZNAMY bd31521bd3 3.2.2 2023-01-15 12:02:05 +01:00
NEZNAMY ec0deb8378 Yellow Number - Disable the feature for Bedrock players 2023-01-12 21:57:56 +01:00
NEZNAMY ae66b6e9a1 RGB - Fix MiniMessage->Bukkit conversion being after Bukkit->TAB, making it not translate anymore 2023-01-12 14:55:41 +01:00
NEZNAMY 3b86becebd Header/Footer - Do not add &r after \n anymore 2023-01-12 14:53:38 +01:00
NEZNAMY 4a8d86825b Configuration - Small changes to default configuration files 2023-01-10 18:56:34 +01:00
NEZNAMY 54a3bd81b4 Global PlayerList - Increase player removal prevention delay to 2000ms from 500ms 2023-01-10 16:49:16 +01:00
NEZNAMY b6768cca99 CPU manager - Add try/catch for task scheduling (#781) 2023-01-10 16:48:28 +01:00
NEZNAMY 60c414deed Bukkit - Remove redundant methods in nms loader 2023-01-05 16:48:16 +01:00
NEZNAMY 009283a83f Update README.md 2023-01-05 16:04:38 +01:00
Callum Seabrook 4a430b97df Merge pull request #779 from JT122406/master
Updates
2023-01-04 22:50:08 +00:00
NEZNAMY 722333da2e Fix RejectedExecutionException (#769) 2023-01-04 19:15:56 +01:00
NEZNAMY 1215af5262 Bukkit - Add 1.5.0 support 2023-01-04 18:28:24 +01:00
NEZNAMY 254088c37b Bukkit - Repackage nms loaders (also fix startup on Thermos) 2023-01-04 18:14:39 +01:00
J.T. McQuiggandCallum Seabrook cb2ce4acca Update gradle/libs.versions.toml
Co-authored-by: Callum Seabrook <callum.seabrook@prevarinite.com>
2023-01-04 11:20:55 -05:00
J.T.McQuigg 872adca8fd Updates 2023-01-03 23:09:35 -05:00
J.T.McQuigg f37cc0bdd8 Gradle 7.6 2023-01-03 23:02:04 -05:00
NEZNAMY 4063578ac3 Code style - Remove duplicate .toLowerCase() 2023-01-02 20:45:23 +01:00
NEZNAMY 2528de7eeb Code style - Use built-in String#trim function 2023-01-02 20:25:11 +01:00
NEZNAMY 37caed3123 Placeholders - Add timeout for placeholders to return value, causing TAB to freeze 2022-12-23 14:49:31 +01:00
NEZNAMY 27fe9dfb12 Commands - Make player command update player instantly if uuid is used instead of player name 2022-12-21 22:00:58 +01:00
NEZNAMY 0169cbd4d2 Bukkit - Fix wrong method taken sometimes, causing player kick with unlimited nametag mode 2022-12-20 15:08:18 +01:00
NEZNAMY ed760aec08 Aligned PlayerList - Fix rare error that makes no sense 2022-12-20 15:04:48 +01:00
NEZNAMY 858cbcefeb Code style - Add toString override 2022-12-20 15:04:21 +01:00
NEZNAMY 8a87d581a9 Scoreboard - Do not send packets to players who cannot see that specific scoreboard 2022-12-18 17:16:26 +01:00
NEZNAMY 6d642f4e51 NameTags - Fix players getting unregistered with wrong team name 2022-12-17 19:12:00 +01:00
NEZNAMY aca63640bc Attempt to fix rare NPE 2022-12-17 19:08:32 +01:00
NEZNAMY 1845a35315 3.2.2-SNAPSHOT 2022-12-16 22:25:39 +01:00
NEZNAMY cab5f89a95 Remove redundant check 2022-12-16 22:03:21 +01:00
NEZNAMY 1777d8bf01 Remove redundant try/catch 2022-12-16 21:14:47 +01:00
NEZNAMY 91b0bfaa9d Configuration - Simplify file copying, since default files already are encoded with UTF-8 encoding 2022-12-16 15:04:52 +01:00
50 changed files with 318 additions and 372 deletions

No files matched your search

+5 -5
View File
@@ -11,22 +11,22 @@ jobs:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v3.3.0 #https://github.com/actions/checkout/releases
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Set up JDK 11
uses: actions/setup-java@v3
uses: actions/setup-java@v3.9.0 #https://github.com/actions/setup-java/releases
with:
distribution: 'temurin'
java-version: 11
- name: Cache SonarCloud packages
uses: actions/cache@v2
uses: actions/cache@v3.2.3 #https://github.com/actions/cache/releases
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache Gradle
uses: actions/cache@v2
uses: actions/cache@v3.2.3 #https://github.com/actions/cache/releases
with:
path: |
~/.gradle/caches
@@ -39,7 +39,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
run: ./gradlew clean build
- name: Upload a Build Artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v3.1.2 #https://github.com/actions/upload-artifact/releases
with:
name: Jar
path: jar/build/libs/TAB-**.jar
+11 -15
View File
@@ -6,8 +6,8 @@ More information can be found at [Why TAB?](https://github.com/NEZNAMY/TAB/wiki/
# 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, official support on discord is only provided to
those who have purchased the plugin.
and is available to everyone for free. However, customer support is only provided to
customers who have purchased the plugin.
# Compiling
Compilation requires JDK 8 and up.
@@ -15,17 +15,10 @@ To compile the plugin, run `./gradlew build` from the terminal.
Once the plugin compiles, grab the jar from `/jar/build/libs/` folder.
# Links
The precompiled JAR can be downloaded for free from:
* GitHub releases: https://github.com/NEZNAMY/TAB/releases
* BuiltByBit: https://builtbybit.com/resources/20631/
Support my work & receive official assistance with configuration:
* BuiltByBit: https://builtbybit.com/resources/14009/
* Polymart: https://polymart.org/resource/484
Other links:
* Discord support for buyers: https://discord.gg/EaSvdk6
* Wiki: https://github.com/NEZNAMY/TAB/wiki
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)
Support my work & receive customer support: [BuiltByBit](https://builtbybit.com/resources/14009/), [Polymart](https://polymart.org/resource/484)
Other links: [Discord support for customers](https://discord.gg/EaSvdk6), [Wiki](https://github.com/NEZNAMY/TAB/wiki)
# Issues
The [Issues](https://github.com/NEZNAMY/TAB/issues) section is **only** available for cases included in templates.
@@ -33,6 +26,9 @@ 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.**
# Contributing
If this plugin has helped you in any way, and you would like to return something back
@@ -40,8 +36,8 @@ to make the plugin even better, there is a lot of ways to contribute:
* Open a **pull request** containing a new feature or a bug fix, which you believe many users will benefit from.
* Make detailed high-quality **bug reports**. The difference between a bug getting fixed in 1 week vs 1 hour
is in quality of the report (typically providing correct steps to reproduce that actually work).
* Test **experimental builds**, which can be found in [Github Actions](https://github.com/NEZNAMY/TAB/actions) or in a form of pre-releases on discord
for problems of any kind including bugs. This way you will help make the actual releases more stable / help get stable releases sooner.
* 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.
@@ -39,15 +39,15 @@ public class RGBUtils {
*/
public RGBUtils() {
List<RGBFormatter> list = new ArrayList<>();
try {
Class.forName("net.kyori.adventure.text.minimessage.MiniMessage");
list.add(new MiniMessageFormat());
} catch (ClassNotFoundException ignored) {}
list.add(new BukkitFormat());
list.add(new CMIFormat());
list.add(new UnnamedFormat1());
list.add(new HtmlFormat());
list.add(new KyoriFormat());
try {
Class.forName("net.kyori.adventure.text.minimessage.MiniMessage");
list.add(new MiniMessageFormat());
} catch (ClassNotFoundException ignored) {}
formats = list.toArray(new RGBFormatter[0]);
gradients = new GradientPattern[] {
@@ -1,20 +1,18 @@
package me.neznamy.tab.api.chat.rgb.format;
import me.neznamy.tab.api.chat.EnumChatFormat;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
/**
* Formatter for &lt;#RRGGBB&gt;
* Call to MiniMessage API to reformat text to &amp;x&amp;R&amp;R&amp;G&amp;G&amp;B&amp;B
*/
public class MiniMessageFormat implements RGBFormatter {
@Override
public String reformat(String text) {
if (!text.contains("<")) return text;
String format = text.replace(EnumChatFormat.RESET.getFormat(), ""); //remove &r from header/footer newline inserts
try {
return LegacyComponentSerializer.legacySection().serialize(MiniMessage.miniMessage().deserialize(format));
return LegacyComponentSerializer.legacySection().serialize(MiniMessage.miniMessage().deserialize(text));
} catch (Throwable ignored) {
return text;
}
@@ -1,14 +1,11 @@
package me.neznamy.tab.api.config;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import me.neznamy.tab.api.TabAPI;
import me.neznamy.tab.api.util.Preconditions;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.LinkedHashMap;
@@ -16,9 +13,6 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import me.neznamy.tab.api.TabAPI;
import me.neznamy.tab.api.util.Preconditions;
/**
* Abstract class for configuration file
*/
@@ -53,18 +47,9 @@ public abstract class ConfigurationFile {
Preconditions.checkNotNull(destination, "destination");
this.file = destination;
if (file.getParentFile() != null && !file.getParentFile().exists()) Files.createDirectories(file.getParentFile().toPath());
if (!file.exists() && source == null) throw new IllegalStateException("File does not exist and source is null");
if (file.createNewFile()) {
// Files.copy(source, file.toPath());
//avoiding MalformedInputException thrown on fabric due to file not having UTF8 encoding by default
//also automatically using the encoding so users don't have to worry about it anymore
try (BufferedReader reader = new BufferedReader(new InputStreamReader(source, StandardCharsets.UTF_8));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8))){
String line;
while ((line = reader.readLine()) != null) {
writer.write(line + "\n");
}
}
if (!file.exists()) {
if (source == null) throw new IllegalStateException("File does not exist and source is null");
Files.copy(source, file.toPath());
}
detectHeader();
}
@@ -0,0 +1,12 @@
package me.neznamy.tab.api.util;
/**
* Supplier that can throw an exception
*
* @param <T>
* Return class type
*/
public interface SupplierWithException<T> {
T get() throws Exception;
}
@@ -12,9 +12,12 @@ import me.neznamy.tab.api.protocol.PacketPlayOutBoss.Action;
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.EnumGamemode;
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.EnumPlayerInfoAction;
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.PlayerInfoData;
import me.neznamy.tab.platforms.bukkit.nms.*;
import me.neznamy.tab.platforms.bukkit.nms.PacketPlayOutEntityDestroy;
import me.neznamy.tab.platforms.bukkit.nms.PacketPlayOutEntityMetadata;
import me.neznamy.tab.platforms.bukkit.nms.PacketPlayOutEntityTeleport;
import me.neznamy.tab.platforms.bukkit.nms.PacketPlayOutSpawnEntityLiving;
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcher;
import org.bukkit.Bukkit;
import me.neznamy.tab.platforms.bukkit.nms.storage.NMSStorage;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
@@ -99,7 +102,7 @@ public class BukkitPacketBuilder extends PacketBuilder {
);
}
Enum[] array = packet.getActions().stream().map(action -> Enum.valueOf(nms.EnumPlayerInfoAction, action.toString())).toArray(Enum[]::new);
Object nmsPacket = nms.newPacketPlayOutPlayerInfo.newInstance(array[0], nms.getHandle.invoke(Bukkit.getOnlinePlayers().iterator().next()));
Object nmsPacket = nms.newPacketPlayOutPlayerInfo.newInstance(EnumSet.of(array[0], array), Collections.emptyList());
List<Object> items = new ArrayList<>();
for (PlayerInfoData data : packet.getEntries()) {
GameProfile profile = new GameProfile(data.getUniqueId(), data.getName());
@@ -115,7 +118,6 @@ public class BukkitPacketBuilder extends PacketBuilder {
data.getProfilePublicKey() == null ? null : nms.newRemoteChatSession$Data.newInstance(data.getChatSessionId(), data.getProfilePublicKey()));
items.add(obj);
}
nms.setField(nmsPacket, nms.PacketPlayOutPlayerInfo_ACTION, EnumSet.of(array[0], array));
nms.setField(nmsPacket, nms.PacketPlayOutPlayerInfo_PLAYERS, items);
return nmsPacket;
} else {
@@ -9,7 +9,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import me.neznamy.tab.api.TabFeature;
import me.neznamy.tab.api.TabPlayer;
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
import me.neznamy.tab.platforms.bukkit.nms.storage.NMSStorage;
import me.neznamy.tab.api.TabConstants;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.features.PipelineInjector;
@@ -5,6 +5,7 @@ import me.clip.placeholderapi.PlaceholderAPI;
import me.neznamy.tab.api.TabConstants;
import me.neznamy.tab.api.TabPlayer;
import me.neznamy.tab.api.chat.EnumChatFormat;
import me.neznamy.tab.api.chat.rgb.RGBUtils;
import me.neznamy.tab.platforms.bukkit.features.BukkitTabExpansion;
import me.neznamy.tab.platforms.bukkit.features.PerWorldPlayerList;
import me.neznamy.tab.platforms.bukkit.features.PetFix;
@@ -272,6 +273,7 @@ public class BukkitPlatform extends Platform {
/**
* Sends console message using ConsoleCommandSender, due to
* Paper not translating colors correctly in Logger messages
* and to allow RGB (at least on Paper, doesn't work on spigot)
*
* @param message
* Message to send
@@ -280,6 +282,9 @@ public class BukkitPlatform extends Platform {
*/
@Override
public void sendConsoleMessage(String message, boolean translateColors) {
Bukkit.getConsoleSender().sendMessage("[TAB] " + (translateColors ? EnumChatFormat.color(message) : message));
Bukkit.getConsoleSender().sendMessage("[TAB] " + (translateColors ?
EnumChatFormat.color(RGBUtils.getInstance().convertToBukkitFormat(message,
TAB.getInstance().getServerVersion().getMinorVersion() >= 16))
: message));
}
}
@@ -25,7 +25,7 @@ import com.viaversion.viaversion.api.legacy.bossbar.BossStyle;
import io.netty.channel.Channel;
import me.neznamy.tab.api.chat.rgb.RGBUtils;
import me.neznamy.tab.api.protocol.PacketPlayOutBoss;
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
import me.neznamy.tab.platforms.bukkit.nms.storage.NMSStorage;
import me.neznamy.tab.shared.ITabPlayer;
import me.neznamy.tab.shared.TAB;
@@ -1,25 +1,25 @@
package me.neznamy.tab.platforms.bukkit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import me.neznamy.tab.api.ProtocolVersion;
import me.neznamy.tab.api.TabAPI;
import me.neznamy.tab.platforms.bukkit.nms.*;
import me.neznamy.tab.api.TabConstants;
import me.neznamy.tab.api.TabPlayer;
import me.neznamy.tab.api.chat.EnumChatFormat;
import me.neznamy.tab.api.util.SupplierWithException;
import me.neznamy.tab.platforms.bukkit.nms.storage.*;
import me.neznamy.tab.shared.TAB;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.SimplePie;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import me.neznamy.tab.api.ProtocolVersion;
import me.neznamy.tab.api.TabPlayer;
import me.neznamy.tab.api.chat.EnumChatFormat;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.api.TabConstants;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Main class for Bukkit platform
*/
@@ -77,25 +77,16 @@ public class Main extends JavaPlugin {
try {
long time = System.currentTimeMillis();
int minorVersion = Integer.parseInt(serverPackage.split("_")[1]);
if (minorVersion >= 17) {
try {
NMSStorage.setInstance(new BukkitModernNMSStorage());
} catch (ClassNotFoundException e) {
NMSStorage.setInstance(new MojangModernNMSStorage());
}
} else {
NMSStorage.setInstance(new LegacyNMSStorage());
}
NMSStorage.setInstance(getNMSLoader());
if (supportedVersions.contains(serverPackage)) {
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("[TAB] Loaded NMS hook in " + (System.currentTimeMillis()-time) + "ms"));
return true;
} else {
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] No compatibility issue was found, but this plugin version does not claim to support your server package (" + serverPackage + "). This jar has only been tested on 1.5.2 - 1.19.3. Disabling just to stay safe."));
}
} catch (Exception ex) {
} catch (IllegalStateException ex) {
if (supportedVersions.contains(serverPackage)) {
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] Your server version is marked as compatible, but a compatibility issue was found. Please report the error below (include your server version & fork too)"));
getLogger().log(Level.SEVERE, "", ex);
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] Your server version is marked as compatible, but a compatibility issue was found. Please report this issue (include your server version & fork too)"));
} else {
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] Your server version is completely unsupported. This plugin version only supports 1.5.2 - 1.19.3. Disabling."));
}
@@ -103,6 +94,20 @@ public class Main extends JavaPlugin {
return false;
}
private NMSStorage getNMSLoader() {
List<SupplierWithException<NMSStorage>> loaders = new ArrayList<>();
loaders.add(BukkitLegacyNMSStorage::new);
loaders.add(BukkitModernNMSStorage::new);
loaders.add(MojangModernNMSStorage::new);
loaders.add(ThermosNMSStorage::new);
for (SupplierWithException<NMSStorage> loader : loaders) {
try {
return loader.get();
} catch (Exception ignored){}
}
throw new IllegalStateException("Unsupported server version");
}
/**
* Command handler for /tab command
*/
@@ -25,9 +25,6 @@ import me.neznamy.tab.shared.TAB;
@SuppressWarnings("deprecation")
public class PerWorldPlayerList extends TabFeature implements Listener {
/** Reference to main class */
private final JavaPlugin plugin;
/** Config options */
private final boolean allowBypass = TabAPI.getInstance().getConfig().getBoolean("per-world-playerlist.allow-bypass-permission", false);
private final List<String> ignoredWorlds = TabAPI.getInstance().getConfig().getStringList("per-world-playerlist.ignore-effect-in-worlds", Arrays.asList("ignoredworld", "build"));
@@ -41,14 +38,13 @@ public class PerWorldPlayerList extends TabFeature implements Listener {
*/
public PerWorldPlayerList(JavaPlugin plugin) {
super("Per world PlayerList", null);
this.plugin = plugin;
Bukkit.getPluginManager().registerEvents(this, plugin);
TabAPI.getInstance().debug(String.format("Loaded PerWorldPlayerList feature with parameters allowBypass=%s, ignoredWorlds=%s, sharedWorlds=%s", allowBypass, ignoredWorlds, sharedWorlds));
}
@Override
public void load(){
Bukkit.getScheduler().runTask(plugin, () -> Bukkit.getOnlinePlayers().forEach(this::checkPlayer));
Bukkit.getOnlinePlayers().forEach(this::checkPlayer);
}
@Override
@@ -3,7 +3,7 @@ package me.neznamy.tab.platforms.bukkit.features;
import me.neznamy.tab.api.TabAPI;
import me.neznamy.tab.api.TabFeature;
import me.neznamy.tab.api.TabPlayer;
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
import me.neznamy.tab.platforms.bukkit.nms.storage.NMSStorage;
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcher;
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcherItem;
@@ -4,7 +4,7 @@ import me.neznamy.tab.api.TabAPI;
import me.neznamy.tab.api.TabConstants;
import me.neznamy.tab.api.TabFeature;
import me.neznamy.tab.api.TabPlayer;
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
import me.neznamy.tab.platforms.bukkit.nms.storage.NMSStorage;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
@@ -1,38 +0,0 @@
package me.neznamy.tab.platforms.bukkit.nms;
import java.util.Arrays;
/**
* NMS loader for minecraft 1.17+ using Mojang packaging.
*/
public abstract class ModernNMSStorage extends NMSStorage {
/**
* Creates new instance, initializes required NMS classes and fields
*
* @throws ReflectiveOperationException
* If any class, field or method fails to load
*/
public ModernNMSStorage() throws ReflectiveOperationException {
}
/**
* Returns class with given potential names in same order
*
* @param names
* possible class names
* @return class for specified names
* @throws ClassNotFoundException
* if class does not exist
*/
protected Class<?> getModernClass(String... names) throws ClassNotFoundException {
for (String name : names) {
try {
return Class.forName(name);
} catch (ClassNotFoundException e) {
//not the first class name in array
}
}
throw new ClassNotFoundException("No class found with possible names " + Arrays.toString(names));
}
}
@@ -5,7 +5,7 @@ import java.util.List;
import java.util.Map;
import me.neznamy.tab.api.util.Preconditions;
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
import me.neznamy.tab.platforms.bukkit.nms.storage.NMSStorage;
/**
* A class representing the n.m.s.DataWatcher class to make work with it much easier
@@ -112,4 +112,9 @@ public class DataWatcher {
}
return watcher;
}
@Override
public String toString() {
return String.format("DataWatcher{values=%s}", dataValues);
}
}
@@ -4,7 +4,7 @@ import me.neznamy.tab.api.ProtocolVersion;
import me.neznamy.tab.api.TabAPI;
import me.neznamy.tab.api.chat.IChatBaseComponent;
import me.neznamy.tab.platforms.bukkit.BukkitPacketBuilder;
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
import me.neznamy.tab.platforms.bukkit.nms.storage.NMSStorage;
import me.neznamy.tab.shared.TAB;
import java.util.Optional;
@@ -2,7 +2,7 @@ package me.neznamy.tab.platforms.bukkit.nms.datawatcher;
import me.neznamy.tab.api.TabAPI;
import me.neznamy.tab.api.util.Preconditions;
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
import me.neznamy.tab.platforms.bukkit.nms.storage.NMSStorage;
/**
* Class representing NMS Data Watcher Item
@@ -67,4 +67,9 @@ public class DataWatcherItem {
public Object getValue() {
return value;
}
@Override
public String toString() {
return String.format("DataWatcherItem{type=%s,value=%s}", type, value);
}
}
@@ -39,4 +39,9 @@ public class DataWatcherObject {
public Object getSerializer() {
return serializer;
}
@Override
public String toString() {
return String.format("DataWatcherObject{position=%d,serializer=%s}", position, serializer);
}
}
@@ -1,6 +1,6 @@
package me.neznamy.tab.platforms.bukkit.nms.datawatcher;
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
import me.neznamy.tab.platforms.bukkit.nms.storage.NMSStorage;
import java.util.Map;
@@ -1,14 +1,12 @@
package me.neznamy.tab.platforms.bukkit.nms;
import me.neznamy.tab.platforms.bukkit.Main;
package me.neznamy.tab.platforms.bukkit.nms.storage;
import java.util.Arrays;
/**
* NMS loader for Minecraft 1.16.5 and lower using old NMS class structure.
* NMS loader for Minecraft 1.5.2 - 1.16.5 using Bukkit mapping.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class LegacyNMSStorage extends NMSStorage {
public class BukkitLegacyNMSStorage extends NMSStorage {
/**
* Creates new instance, initializes required NMS classes and fields
@@ -16,7 +14,7 @@ public class LegacyNMSStorage extends NMSStorage {
* @throws ReflectiveOperationException
* If any class, field or method fails to load
*/
public LegacyNMSStorage() throws ReflectiveOperationException {
public BukkitLegacyNMSStorage() throws ReflectiveOperationException {
}
/**
@@ -48,44 +46,33 @@ public class LegacyNMSStorage extends NMSStorage {
* @throws ClassNotFoundException
* if class was not found
*/
private Class<?> getLegacyClass(String name) throws ClassNotFoundException {
try {
return Class.forName("net.minecraft.server." + serverPackage + "." + name);
} catch (ClassNotFoundException | NullPointerException e) {
try {
//modded server?
Class<?> clazz = Main.class.getClassLoader().loadClass("net.minecraft.server." + serverPackage + "." + name);
if (clazz != null) return clazz;
} catch (NullPointerException ignored) {}
throw new ClassNotFoundException(name);
}
public Class<?> getLegacyClass(String name) throws ClassNotFoundException {
return Class.forName("net.minecraft.server." + serverPackage + "." + name);
}
@Override
public void loadNamedFieldsAndMethods() throws ReflectiveOperationException {
PING = getField(EntityPlayer, "ping", "field_71138_i"); // {Bukkit, Thermos}
ScoreboardScore_setScore = getMethod(ScoreboardScore, new String[]{"setScore", "func_96647_c"}, int.class); // {Bukkit, Thermos}
ScoreboardTeam_setAllowFriendlyFire = getMethod(ScoreboardTeam,
new String[]{"setAllowFriendlyFire", "func_96660_a"}, boolean.class); // {Bukkit, Thermos}
ScoreboardTeam_setCanSeeFriendlyInvisibles = getMethod(ScoreboardTeam,
new String[]{"setCanSeeFriendlyInvisibles", "func_98300_b"}, boolean.class); // {Bukkit, Thermos}
PING = getField(EntityPlayer, "ping");
ScoreboardScore_setScore = getMethod(ScoreboardScore, new String[] {"setScore", "c"}, int.class); // 1.5.1+, 1.5
ScoreboardTeam_setAllowFriendlyFire = getMethod(ScoreboardTeam, new String[] {"setAllowFriendlyFire", "a"}, boolean.class); // 1.5.1+, 1.5
ScoreboardTeam_setCanSeeFriendlyInvisibles = getMethod(ScoreboardTeam, new String[] {"setCanSeeFriendlyInvisibles", "b"}, boolean.class); // 1.5.1+, 1.5
if (minorVersion >= 7) {
ChatSerializer_DESERIALIZE = getMethod(ChatSerializer, new String[]{"a", "func_150699_a"}, String.class); // {Bukkit, Thermos}
ChatSerializer_DESERIALIZE = ChatSerializer.getMethod("a", String.class);
}
if (minorVersion >= 8) {
ScoreboardTeam_setNameTagVisibility = getMethod(ScoreboardTeam, new String[] {"setNameTagVisibility", "a"}, EnumNameTagVisibility); // {1.8.1+, 1.8}
}
if (minorVersion >= 9) {
DataWatcher_REGISTER = getMethod(DataWatcher, "register", DataWatcherObject, Object.class);
DataWatcher_REGISTER = DataWatcher.getMethod("register", DataWatcherObject, Object.class);
} else {
DataWatcher_REGISTER = getMethod(DataWatcher, new String[]{"a", "func_75682_a"}, int.class, Object.class); // {Bukkit, Thermos}
DataWatcher_REGISTER = DataWatcher.getMethod("a", int.class, Object.class);
}
if (minorVersion >= 13) {
ScoreboardTeam_setPrefix = getMethod(ScoreboardTeam, "setPrefix", IChatBaseComponent);
ScoreboardTeam_setSuffix = getMethod(ScoreboardTeam, "setSuffix", IChatBaseComponent);
ScoreboardTeam_setPrefix = ScoreboardTeam.getMethod("setPrefix", IChatBaseComponent);
ScoreboardTeam_setSuffix = ScoreboardTeam.getMethod("setSuffix", IChatBaseComponent);
} else {
ScoreboardTeam_setPrefix = getMethod(ScoreboardTeam, new String[]{"setPrefix", "func_96666_b"}, String.class); // {Bukkit, Thermos}
ScoreboardTeam_setSuffix = getMethod(ScoreboardTeam, new String[]{"setSuffix", "func_96662_c"}, String.class); // {Bukkit, Thermos}
ScoreboardTeam_setPrefix = getMethod(ScoreboardTeam, new String[] {"setPrefix", "b"}, String.class); // 1.5.1+, 1.5
ScoreboardTeam_setSuffix = getMethod(ScoreboardTeam, new String[] {"setSuffix", "c"}, String.class); // 1.5.1+, 1.5
}
}
@@ -151,7 +138,7 @@ public class LegacyNMSStorage extends NMSStorage {
Scoreboard = getLegacyClass("Scoreboard");
ScoreboardObjective = getLegacyClass("ScoreboardObjective");
ScoreboardScore = getLegacyClass("ScoreboardScore");
IScoreboardCriteria = getLegacyClass("IScoreboardCriteria");
IScoreboardCriteria = getLegacyClass("IScoreboardCriteria", "IObjective"); // 1.5.1+, 1.5
ScoreboardTeam = getLegacyClass("ScoreboardTeam");
if (minorVersion >= 8) {
EnumScoreboardHealthDisplay = (Class<Enum>) getLegacyClass("IScoreboardCriteria$EnumScoreboardHealthDisplay", "EnumScoreboardHealthDisplay");
@@ -1,10 +1,10 @@
package me.neznamy.tab.platforms.bukkit.nms;
package me.neznamy.tab.platforms.bukkit.nms.storage;
/**
* NMS loader for minecraft 1.17+ using Mojang packaging and bukkit names.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class BukkitModernNMSStorage extends ModernNMSStorage {
public class BukkitModernNMSStorage extends NMSStorage {
/**
* Creates new instance, initializes required NMS classes and fields
@@ -18,7 +18,7 @@ public class BukkitModernNMSStorage extends ModernNMSStorage {
@Override
public void loadNamedFieldsAndMethods() throws ReflectiveOperationException {
PING = getField(EntityPlayer, "e");
ChatSerializer_DESERIALIZE = getMethod(ChatSerializer, "a", String.class);
ChatSerializer_DESERIALIZE = ChatSerializer.getMethod("a", String.class);
DataWatcher_REGISTER = getMethod(DataWatcher, new String[]{"register", "a"}, DataWatcherObject, Object.class); // {Bukkit, Bukkit 1.18+}
ScoreboardScore_setScore = getMethod(ScoreboardScore, new String[]{"setScore", "b"}, int.class); // {Bukkit, Bukkit 1.18+}
ScoreboardTeam_setAllowFriendlyFire = getMethod(ScoreboardTeam, new String[]{"setAllowFriendlyFire", "a"}, boolean.class); // {Bukkit, Bukkit 1.18+}
@@ -29,6 +29,7 @@ public class BukkitModernNMSStorage extends ModernNMSStorage {
if (minorVersion >= 19) {
EntityTypes_ARMOR_STAND = EntityTypes.getDeclaredField("d").get(null);
PacketPlayOutSpawnEntityLiving_ENTITYTYPE = getField(PacketPlayOutSpawnEntityLiving, "e");
DataWatcher_b = DataWatcher.getMethod("b");
}
}
@@ -48,9 +49,10 @@ public class BukkitModernNMSStorage extends ModernNMSStorage {
PlayerConnection = Class.forName("net.minecraft.server.network.PlayerConnection");
PacketPlayOutPlayerListHeaderFooter = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutPlayerListHeaderFooter");
PacketPlayOutChat = getModernClass("net.minecraft.network.protocol.game.ClientboundSystemChatPacket",
"net.minecraft.network.protocol.game.PacketPlayOutChat");
if (minorVersion < 19) {
if (minorVersion >= 19) {
PacketPlayOutChat = Class.forName("net.minecraft.network.protocol.game.ClientboundSystemChatPacket");
} else {
PacketPlayOutChat = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutChat");
ChatMessageType = (Class<Enum>) Class.forName("net.minecraft.network.chat.ChatMessageType");
}
@@ -65,8 +67,11 @@ public class BukkitModernNMSStorage extends ModernNMSStorage {
}
// Entities
PacketPlayOutSpawnEntityLiving = getModernClass("net.minecraft.network.protocol.game.PacketPlayOutSpawnEntityLiving",
"net.minecraft.network.protocol.game.PacketPlayOutSpawnEntity");
if (minorVersion >= 19) {
PacketPlayOutSpawnEntityLiving = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutSpawnEntity");
} else {
PacketPlayOutSpawnEntityLiving = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutSpawnEntityLiving");
}
PacketPlayOutEntityTeleport = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutEntityTeleport");
PacketPlayInUseEntity = Class.forName("net.minecraft.network.protocol.game.PacketPlayInUseEntity");
PacketPlayInUseEntity$d = Class.forName("net.minecraft.network.protocol.game.PacketPlayInUseEntity$d");
@@ -1,10 +1,10 @@
package me.neznamy.tab.platforms.bukkit.nms;
package me.neznamy.tab.platforms.bukkit.nms.storage;
/**
* NMS loader for minecraft 1.17+ using Mojang packaging and names.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class MojangModernNMSStorage extends ModernNMSStorage {
public class MojangModernNMSStorage extends NMSStorage {
/**
* Creates new instance, initializes required NMS classes and fields
@@ -18,17 +18,18 @@ public class MojangModernNMSStorage extends ModernNMSStorage {
@Override
public void loadNamedFieldsAndMethods() throws ReflectiveOperationException {
PING = getField(EntityPlayer, "latency");
ChatSerializer_DESERIALIZE = getMethod(ChatSerializer, "fromJson", String.class);
DataWatcher_REGISTER = getMethod(DataWatcher, "define", DataWatcherObject, Object.class);
ScoreboardScore_setScore = getMethod(ScoreboardScore, "setScore", int.class);
ScoreboardTeam_setAllowFriendlyFire = getMethod(ScoreboardTeam, "setAllowFriendlyFire", boolean.class);
ScoreboardTeam_setCanSeeFriendlyInvisibles = getMethod(ScoreboardTeam, "setSeeFriendlyInvisibles", boolean.class);
ScoreboardTeam_setPrefix = getMethod(ScoreboardTeam, "setPlayerPrefix", IChatBaseComponent);
ScoreboardTeam_setSuffix = getMethod(ScoreboardTeam, "setPlayerSuffix", IChatBaseComponent);
ScoreboardTeam_setNameTagVisibility = getMethod(ScoreboardTeam, "setNameTagVisibility", EnumNameTagVisibility);
ChatSerializer_DESERIALIZE = ChatSerializer.getMethod("fromJson", String.class);
DataWatcher_REGISTER = DataWatcher.getMethod("define", DataWatcherObject, Object.class);
ScoreboardScore_setScore = ScoreboardScore.getMethod("setScore", int.class);
ScoreboardTeam_setAllowFriendlyFire = ScoreboardTeam.getMethod("setAllowFriendlyFire", boolean.class);
ScoreboardTeam_setCanSeeFriendlyInvisibles = ScoreboardTeam.getMethod("setSeeFriendlyInvisibles", boolean.class);
ScoreboardTeam_setPrefix = ScoreboardTeam.getMethod("setPlayerPrefix", IChatBaseComponent);
ScoreboardTeam_setSuffix = ScoreboardTeam.getMethod("setPlayerSuffix", IChatBaseComponent);
ScoreboardTeam_setNameTagVisibility = ScoreboardTeam.getMethod("setNameTagVisibility", EnumNameTagVisibility);
if (minorVersion >= 19) {
EntityTypes_ARMOR_STAND = EntityTypes.getDeclaredField("ARMOR_STAND").get(null);
PacketPlayOutSpawnEntityLiving_ENTITYTYPE = getField(PacketPlayOutSpawnEntityLiving, "type");
DataWatcher_b = DataWatcher.getMethod("packDirty");
}
}
@@ -47,9 +48,10 @@ public class MojangModernNMSStorage extends ModernNMSStorage {
EntityLiving = Class.forName("net.minecraft.world.entity.LivingEntity");
PlayerConnection = Class.forName("net.minecraft.server.network.ServerGamePacketListenerImpl");
PacketPlayOutPlayerListHeaderFooter = Class.forName("net.minecraft.network.protocol.game.ClientboundTabListPacket");
PacketPlayOutChat = getModernClass("net.minecraft.network.protocol.game.ClientboundSystemChatPacket",
"net.minecraft.network.protocol.game.ClientboundChatPacket");
if (minorVersion < 19) {
if (minorVersion >= 19) {
PacketPlayOutChat = Class.forName("net.minecraft.network.protocol.game.ClientboundSystemChatPacket");
} else {
PacketPlayOutChat = Class.forName("net.minecraft.network.protocol.game.ClientboundChatPacket");
ChatMessageType = (Class<Enum>) Class.forName("net.minecraft.network.chat.ChatType");
}
@@ -64,8 +66,11 @@ public class MojangModernNMSStorage extends ModernNMSStorage {
}
// Entities
PacketPlayOutSpawnEntityLiving = getModernClass("net.minecraft.network.protocol.game.ClientboundAddMobPacket",
"net.minecraft.network.protocol.game.ClientboundAddEntityPacket");
if (minorVersion >= 19) {
PacketPlayOutSpawnEntityLiving = Class.forName("net.minecraft.network.protocol.game.ClientboundAddEntityPacket");
} else {
PacketPlayOutSpawnEntityLiving = Class.forName("net.minecraft.network.protocol.game.ClientboundAddMobPacket");
}
PacketPlayOutEntityTeleport = Class.forName("net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket");
PacketPlayInUseEntity = Class.forName("net.minecraft.network.protocol.game.ServerboundInteractPacket");
PacketPlayInUseEntity$d = Class.forName("net.minecraft.network.protocol.game.ServerboundInteractPacket$InteractionAction");
@@ -1,4 +1,4 @@
package me.neznamy.tab.platforms.bukkit.nms;
package me.neznamy.tab.platforms.bukkit.nms.storage;
import com.mojang.authlib.GameProfile;
import io.netty.channel.Channel;
@@ -71,13 +71,13 @@ public abstract class NMSStorage {
public Field DataWatcherObject_SLOT;
public Field DataWatcherObject_SERIALIZER;
public Method DataWatcher_REGISTER;
public Method DataWatcher_b;
private final DataWatcherRegistry registry;
//1.19.3+
protected Class<?> DataWatcher$DataValue;
public Field DataWatcher$DataValue_POSITION;
public Field DataWatcher$DataValue_VALUE;
public Method DataWatcher_markDirty;
public Method DataWatcher_b;
/** PacketPlayOutSpawnEntityLiving */
public Class<?> PacketPlayOutSpawnEntityLiving;
@@ -229,7 +229,7 @@ public abstract class NMSStorage {
try {
Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket");
is1_19_3Plus = true;
} catch (ClassNotFoundException ignored) {}
} catch (ClassNotFoundException | NullPointerException ignored) {}
ProtocolVersion.UNKNOWN_SERVER_VERSION.setMinorVersion(minorVersion); //fixing compatibility with forks that set version field value to "Unknown"
loadClasses();
if (minorVersion >= 7) {
@@ -312,7 +312,7 @@ public abstract class NMSStorage {
if (minorVersion < 8) return;
if (is1_19_3Plus()) {
newClientboundPlayerInfoRemovePacket = ClientboundPlayerInfoRemovePacket.getConstructor(List.class);
newPacketPlayOutPlayerInfo = PacketPlayOutPlayerInfo.getConstructor(EnumPlayerInfoAction, EntityPlayer);
newPacketPlayOutPlayerInfo = PacketPlayOutPlayerInfo.getConstructor(EnumSet.class, Collection.class);
ClientboundPlayerInfoRemovePacket_getEntries = getMethods(ClientboundPlayerInfoRemovePacket, List.class).get(0);
PacketPlayOutPlayerInfo_ACTION = getFields(PacketPlayOutPlayerInfo, EnumSet.class).get(0);
newRemoteChatSession$Data = RemoteChatSession$Data.getConstructor(UUID.class, ProfilePublicKey$a);
@@ -466,7 +466,6 @@ public abstract class NMSStorage {
protected void dataWatcher() throws ReflectiveOperationException {
newDataWatcher = DataWatcher.getConstructors()[0];
DataWatcherItem_VALUE = getFields(DataWatcherItem, Object.class).get(0);
DataWatcher_b = getMethods(DataWatcher, List.class).get(0);
if (minorVersion >= 9) {
newDataWatcherObject = DataWatcherObject.getConstructor(int.class, DataWatcherSerializer);
DataWatcherItem_TYPE = getFields(DataWatcherItem, DataWatcherObject).get(0);
@@ -579,7 +578,7 @@ public abstract class NMSStorage {
protected Method getMethod(Class<?> clazz, String[] names, Class<?>... parameterTypes) throws NoSuchMethodException {
for (String name : names) {
try {
return getMethod(clazz, name, parameterTypes);
return clazz.getMethod(name, parameterTypes);
} catch (NoSuchMethodException e) {
//not the first method in array
}
@@ -601,39 +600,6 @@ public abstract class NMSStorage {
Arrays.toString(parameterTypes) + " in class " + clazz.getName() + ". Methods with matching parameters: " + list);
}
/**
* Returns Method from class with given name and parameter types. This should be equal to
* simply calling Class#getMethod, which however does not work with a few specific methods on
* CatServer fork. This workaround works for them.
*
* @param clazz
* Class to get method from
* @param name
* Name of the method
* @param parameterTypes
* Parameter types of the method
* @return Method with specified name and parameter types
* @throws NoSuchMethodException
* If no such method was found
*/
protected Method getMethod(Class<?> clazz, String name, Class<?>... parameterTypes) throws NoSuchMethodException {
List<Method> list = new ArrayList<>();
for (Method m : clazz.getMethods()) {
if (!m.getName().equals(name) || m.getParameterCount() != parameterTypes.length) continue;
Class<?>[] types = m.getParameterTypes();
boolean valid = true;
for (int i=0; i<types.length; i++) {
if (types[i] != parameterTypes[i]) {
valid = false;
break;
}
}
if (valid) list.add(m);
}
if (!list.isEmpty()) return list.get(0);
throw new NoSuchMethodException("No method found with name " + name + " in class " + clazz.getName() + " with parameters " + Arrays.toString(parameterTypes));
}
/**
* Returns all methods from class which return specified class type and have specified parameter types.
*
@@ -720,30 +686,6 @@ public abstract class NMSStorage {
throw new NoSuchFieldException("Field \"" + name + "\" was not found in class " + clazz.getName());
}
/**
* Returns field from class with specified possible names of the field.
* Names are checked in specified order and first match is returned.
* If no match is found, {@link NoSuchFieldException} is thrown.
*
* @param clazz
* Class to get field from
* @param potentialNames
* Potential names of the field
* @return Field with specified name
* @throws NoSuchFieldException
* If no match is found
*/
protected Field getField(Class<?> clazz, String... potentialNames) throws NoSuchFieldException {
for (String name : potentialNames) {
try {
return getField(clazz, name);
} catch (NoSuchFieldException e) {
//not the first field name from array
}
}
throw new NoSuchFieldException("No field found in class " + clazz.getName() + " with potential names " + Arrays.toString(potentialNames));
}
/**
* Returns server's minor version
* @return server's minor version
@@ -0,0 +1,49 @@
package me.neznamy.tab.platforms.bukkit.nms.storage;
import me.neznamy.tab.platforms.bukkit.Main;
/**
* NMS loader for Thermos 1.7.10.
*/
public class ThermosNMSStorage extends BukkitLegacyNMSStorage {
/**
* Creates new instance, initializes required NMS classes and fields
*
* @throws ReflectiveOperationException
* If any class, field or method fails to load
*/
public ThermosNMSStorage() throws ReflectiveOperationException {
}
/**
* Returns class from given name
*
* @param name
* class name
* @return class from given name
* @throws ClassNotFoundException
* if class was not found
*/
@Override
public Class<?> getLegacyClass(String name) throws ClassNotFoundException {
try {
return Main.class.getClassLoader().loadClass("net.minecraft.server." + serverPackage + "." + name);
} catch (NullPointerException e) {
// nested class not found
throw new ClassNotFoundException(name);
}
}
@Override
public void loadNamedFieldsAndMethods() throws ReflectiveOperationException {
PING = getField(EntityPlayer, "field_71138_i");
ScoreboardScore_setScore = ScoreboardScore.getMethod("func_96647_c", int.class);
ScoreboardTeam_setAllowFriendlyFire = ScoreboardTeam.getMethod("func_96660_a", boolean.class);
ScoreboardTeam_setCanSeeFriendlyInvisibles = ScoreboardTeam.getMethod("func_98300_b", boolean.class);
ChatSerializer_DESERIALIZE = ChatSerializer.getMethod("func_150699_a", String.class);
DataWatcher_REGISTER = DataWatcher.getMethod("func_75682_a", int.class, Object.class);
ScoreboardTeam_setPrefix = ScoreboardTeam.getMethod("func_96666_b", String.class);
ScoreboardTeam_setSuffix = ScoreboardTeam.getMethod("func_96662_c", String.class);
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
# Project properties - we put these here so they can be modified without causing a recompile of the build scripts
projectVersion=3.2.1
projectVersion=3.2.3-SNAPSHOT
# Gradle properties
org.gradle.daemon=true
+7 -7
View File
@@ -3,19 +3,19 @@ metadata.format.version = "1.1"
[versions]
# API
netty = "4.1.80.Final"
netty = "4.1.86.Final"
jsonSimple = "1.1.1"
snakeyaml = "1.33"
yamlAssist = "1.0.5"
gson = "2.9.1"
slf4j = "1.7.36"
minimessage = "4.11.0"
gson = "2.10"
slf4j = "2.0.6"
minimessage = "4.12.0"
# General
luckperms = "5.4"
guava = "31.1-jre"
floodgate = "2.2.0-SNAPSHOT"
kotlin = "1.7.10"
kotlin = "1.8.0"
event = "3.0.0"
# Platforms
@@ -27,12 +27,12 @@ velocity = "3.1.2-SNAPSHOT"
# Platform extras
placeholderapi = "2.11.2"
vault = "1.7"
via = "4.4.2"
via = "4.5.1"
authlib = "1.5.25"
bstats = "3.0.0"
essentials = "2.19.7"
premiumVanish = "2.7.11-2"
redisBungee = "0.7.3"
redisBungee = "0.10.1"
# Plugins
indra = "2.1.1"
Binary file not shown.
+1 -1
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+6
View File
@@ -205,6 +205,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
Vendored
+8 -6
View File
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,7 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
+1
View File
@@ -9,6 +9,7 @@ dependencyResolutionManagement {
maven("https://repo.viaversion.com/") // ViaVersion
maven("https://repo.essentialsx.net/releases/") // Essentials
maven("https://repo.codemc.org/repository/maven-public/") // RedisBungee
maven("https://repo.codemc.io/repository/maven-snapshots/") // Fixing compilation
maven("https://repo.kryptonmc.org/releases") // YamlAssist, LuckPerms
maven("https://repo.kryptonmc.org/snapshots") // BungeeCord
maven("https://repo.opencollab.dev/maven-snapshots/") // Floodgate
@@ -44,10 +44,10 @@ public class CpuManager implements ThreadManager {
private Map<String, AtomicInteger> packetsPrevious = new ConcurrentHashMap<>();
/** TAB's main thread where all tasks are executed */
private ExecutorService thread = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("TAB Processing Thread").build());
private final ExecutorService thread = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("TAB Processing Thread").build());
/** Thread pool for delayed and repeating tasks to perform sleep before submitting task to main thread */
private final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(20,
private final ScheduledThreadPoolExecutor threadPool = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(20,
new ThreadFactoryBuilder().setNameFormat("TAB Repeating / Delayed Thread %d").build());
/** Tasks submitted to main thread before plugin was fully enabled */
@@ -74,13 +74,10 @@ public class CpuManager implements ThreadManager {
}
/**
* Cancels all tasks, new instance is set to avoid errors when starting tasks on shutdown (such as packet readers)
* Cancels all tasks and shuts down thread pools
*/
public void cancelAllTasks() {
//preventing errors when tasks are inserted while shutting down
ExecutorService old = thread;
thread = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("TAB Processing Thread").build());
old.shutdownNow();
thread.shutdownNow();
threadPool.shutdownNow();
}
@@ -107,13 +104,20 @@ public class CpuManager implements ThreadManager {
taskQueue.add(task);
return null;
}
return (Future<Void>) thread.submit(() -> {
try {
task.run();
} catch (Exception | LinkageError | StackOverflowError e) {
TAB.getInstance().getErrorManager().printError("An error was thrown when executing task", e);
}
});
if (thread.isShutdown()) return null;
try {
return (Future<Void>) thread.submit(() -> {
try {
task.run();
} catch (Exception | LinkageError | StackOverflowError e) {
TAB.getInstance().getErrorManager().printError("An error was thrown when executing task", e);
}
});
} catch (OutOfMemoryError e) {
TAB.getInstance().getErrorManager().criticalError("Failed to schedule task due to " + e.getClass().getName() +
": " + e.getMessage() + ". Threads created by TAB: " + (threadPool.getActiveCount()+1), null);
return null;
}
}
/**
@@ -359,21 +363,25 @@ public class CpuManager implements ThreadManager {
@Override
public Future<?> startRepeatingMeasuredTask(int intervalMilliseconds, TabFeature feature, String type, Runnable task) {
if (threadPool.isShutdown()) return null;
return threadPool.scheduleAtFixedRate(() -> runMeasuredTask(feature, type, task), 0, intervalMilliseconds, TimeUnit.MILLISECONDS);
}
@Override
public Future<?> startRepeatingTask(int intervalMilliseconds, Runnable task) {
if (threadPool.isShutdown()) return null;
return threadPool.scheduleAtFixedRate(() -> runTask(task), 0, intervalMilliseconds, TimeUnit.MILLISECONDS);
}
@Override
public Future<?> runTaskLater(int delayMilliseconds, TabFeature feature, String type, Runnable task) {
if (threadPool.isShutdown()) return null;
return threadPool.schedule(() -> runMeasuredTask(feature, type, task), delayMilliseconds, TimeUnit.MILLISECONDS);
}
@Override
public Future<?> runTaskLater(int delayMilliseconds, Runnable task) {
if (threadPool.isShutdown()) return null;
return threadPool.schedule(() -> submit(task), delayMilliseconds, TimeUnit.MILLISECONDS);
}
}
@@ -225,6 +225,6 @@ public class DynamicText implements Property {
RelationalPlaceholderImpl pl = (RelationalPlaceholderImpl) TAB.getInstance().getPlaceholderManager().getPlaceholder(identifier);
format = format.replace(pl.getIdentifier(), viewer == null ? "" : pl.getLastValue(viewer, owner));
}
return format;
return EnumChatFormat.color(format);
}
}
@@ -119,15 +119,11 @@ public class FeatureManagerImpl implements FeatureManager {
long millis = System.currentTimeMillis();
TAB.getInstance().addPlayer(connectedPlayer);
for (TabFeature f : values) {
try {
if (!f.overridesMethod("onJoin")) continue;
long time = System.nanoTime();
f.onJoin(connectedPlayer);
TAB.getInstance().getCPUManager().addTime(f, TabConstants.CpuUsageCategory.PLAYER_JOIN, System.nanoTime()-time);
TAB.getInstance().debug("Feature " + f.getClass().getSimpleName() + " processed player join in " + (System.nanoTime()-time)/1000000 + "ms");
} catch (Throwable e) {
TAB.getInstance().getErrorManager().criticalError("Feature " + f.getClass().getSimpleName() + " failed to process player " + connectedPlayer.getName(), e);
}
if (!f.overridesMethod("onJoin")) continue;
long time = System.nanoTime();
f.onJoin(connectedPlayer);
TAB.getInstance().getCPUManager().addTime(f, TabConstants.CpuUsageCategory.PLAYER_JOIN, System.nanoTime()-time);
TAB.getInstance().debug("Feature " + f.getClass().getSimpleName() + " processed player join in " + (System.nanoTime()-time)/1000000 + "ms");
}
((ITabPlayer)connectedPlayer).markAsLoaded(true);
TAB.getInstance().debug("Player join of " + connectedPlayer.getName() + " processed in " + (System.currentTimeMillis()-millis) + "ms");
@@ -150,8 +150,8 @@ public class TAB extends TabAPI {
long time = System.currentTimeMillis();
errorManager = new ErrorManager();
cpu = new CpuManager();
featureManager = new FeatureManagerImpl();
configuration = new Configs();
featureManager = new FeatureManagerImpl();
featureManager.registerFeature(TabConstants.Feature.PLACEHOLDER_MANAGER, new PlaceholderManagerImpl());
featureManager.registerFeature(TabConstants.Feature.GROUP_MANAGER, new GroupManager(platform.detectPermissionPlugin()));
platform.loadFeatures();
@@ -2,6 +2,7 @@ package me.neznamy.tab.shared.command;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import me.neznamy.tab.api.TabPlayer;
import me.neznamy.tab.shared.TAB;
@@ -93,6 +94,9 @@ public class PlayerCommand extends PropertyCommand {
if (property.length > 0 && String.valueOf(value.length() == 0 ? null : value).equals(String.valueOf(property[0]))) return;
TAB.getInstance().getConfiguration().getUsers().setProperty(player, type, server, world, value.length() == 0 ? null : value);
TabPlayer pl = TAB.getInstance().getPlayer(player);
try {
if (pl == null) pl = TAB.getInstance().getPlayer(UUID.fromString(player));
} catch (IllegalArgumentException ignored){} // not an uuid string
if (pl != null) {
pl.forceRefresh();
}
@@ -1,17 +1,16 @@
package me.neznamy.tab.shared.features;
import me.neznamy.tab.api.HeaderFooterManager;
import me.neznamy.tab.api.TabConstants;
import me.neznamy.tab.api.TabFeature;
import me.neznamy.tab.api.TabPlayer;
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerListHeaderFooter;
import me.neznamy.tab.shared.TAB;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import me.neznamy.tab.api.HeaderFooterManager;
import me.neznamy.tab.api.TabFeature;
import me.neznamy.tab.api.TabPlayer;
import me.neznamy.tab.api.chat.EnumChatFormat;
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerListHeaderFooter;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.api.TabConstants;
/**
* Feature handler for header and footer
*/
@@ -90,7 +89,7 @@ public class HeaderFooter extends TabFeature implements HeaderFooterManager {
private String getProperty(TabPlayer p, String property) {
String append = getFromConfig(p, property + "append");
if (append.length() > 0) append = "\n" + EnumChatFormat.COLOR_CHAR + "r" + append;
if (append.length() > 0) append = "\n" + append;
return getFromConfig(p, property) + append;
}
@@ -115,7 +114,7 @@ public class HeaderFooter extends TabFeature implements HeaderFooterManager {
lines = TAB.getInstance().getConfiguration().getConfig().getStringList("header-footer." + property);
}
if (lines == null) lines = new ArrayList<>();
return String.join("\n" + EnumChatFormat.COLOR_CHAR + "r", lines);
return String.join("\n", lines);
}
@Override
@@ -251,7 +251,7 @@ public class PlaceholderManagerImpl extends TabFeature implements PlaceholderMan
int refresh = gcd(p.getRefresh(), refreshInterval);
if (refreshInterval != refresh) {
TAB.getInstance().debug("Decreasing refresh interval of placeholder refreshing task to " + refresh + "ms due to placeholder " + identifier);
refreshTask.cancel(true);
if (refreshTask != null) refreshTask.cancel(true);
refreshInterval = refresh;
refreshTask = TAB.getInstance().getCPUManager().startRepeatingMeasuredTask(refreshInterval, this, "Refreshing placeholders", this::refresh);
atomic.set(0);
@@ -62,11 +62,12 @@ public class YellowNumber extends TabFeature {
addDisabledPlayer(loaded);
continue;
}
if (loaded.isBedrockPlayer()) continue;
loaded.sendCustomPacket(new PacketPlayOutScoreboardObjective(0, OBJECTIVE_NAME, TITLE, displayType), this);
loaded.sendCustomPacket(new PacketPlayOutScoreboardDisplayObjective(DISPLAY_SLOT, OBJECTIVE_NAME), this);
}
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()){
if (isDisabledPlayer(viewer)) continue;
if (isDisabledPlayer(viewer) || viewer.isBedrockPlayer()) continue;
for (TabPlayer target : TAB.getInstance().getOnlinePlayers()){
viewer.sendCustomPacket(new PacketPlayOutScoreboardScore(Action.CHANGE, OBJECTIVE_NAME, target.getNickname(), getValue(target)), this);
}
@@ -76,7 +77,7 @@ public class YellowNumber extends TabFeature {
@Override
public void unload() {
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()){
if (isDisabledPlayer(p)) continue;
if (isDisabledPlayer(p) || p.isBedrockPlayer()) continue;
p.sendCustomPacket(new PacketPlayOutScoreboardObjective(OBJECTIVE_NAME), this);
}
}
@@ -88,17 +89,15 @@ public class YellowNumber extends TabFeature {
addDisabledPlayer(connectedPlayer);
return;
}
connectedPlayer.sendCustomPacket(new PacketPlayOutScoreboardObjective(0, OBJECTIVE_NAME, TITLE, displayType), this);
connectedPlayer.sendCustomPacket(new PacketPlayOutScoreboardDisplayObjective(DISPLAY_SLOT, OBJECTIVE_NAME), this);
if (!connectedPlayer.isBedrockPlayer()) {
connectedPlayer.sendCustomPacket(new PacketPlayOutScoreboardObjective(0, OBJECTIVE_NAME, TITLE, displayType), this);
connectedPlayer.sendCustomPacket(new PacketPlayOutScoreboardDisplayObjective(DISPLAY_SLOT, OBJECTIVE_NAME), this);
}
int value = getValue(connectedPlayer);
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()){
if (all == connectedPlayer) {
connectedPlayer.sendCustomPacket(new PacketPlayOutScoreboardScore(Action.CHANGE, OBJECTIVE_NAME, connectedPlayer.getNickname(), value), this);
continue;
}
if (!isDisabledPlayer(all)) {
all.sendCustomPacket(new PacketPlayOutScoreboardScore(Action.CHANGE, OBJECTIVE_NAME, connectedPlayer.getNickname(), value), this);
connectedPlayer.sendCustomPacket(new PacketPlayOutScoreboardScore(Action.CHANGE, OBJECTIVE_NAME, all.getNickname(), getValue(all)), this);
if (!all.isBedrockPlayer()) all.sendCustomPacket(new PacketPlayOutScoreboardScore(Action.CHANGE, OBJECTIVE_NAME, connectedPlayer.getNickname(), value), this);
if (!connectedPlayer.isBedrockPlayer()) connectedPlayer.sendCustomPacket(new PacketPlayOutScoreboardScore(Action.CHANGE, OBJECTIVE_NAME, all.getNickname(), getValue(all)), this);
}
}
}
@@ -119,7 +118,7 @@ public class YellowNumber extends TabFeature {
removeDisabledPlayer(p);
}
if (disabledNow && !disabledBefore) {
p.sendCustomPacket(new PacketPlayOutScoreboardObjective(OBJECTIVE_NAME), this);
if (!p.isBedrockPlayer()) p.sendCustomPacket(new PacketPlayOutScoreboardObjective(OBJECTIVE_NAME), this);
}
if (!disabledNow && disabledBefore) {
onJoin(p);
@@ -132,7 +131,7 @@ public class YellowNumber extends TabFeature {
public void refresh(TabPlayer refreshed, boolean force) {
int value = getValue(refreshed);
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
if (isDisabledPlayer(all)) continue;
if (isDisabledPlayer(all) || all.isBedrockPlayer()) continue;
all.sendCustomPacket(new PacketPlayOutScoreboardScore(Action.CHANGE, OBJECTIVE_NAME, refreshed.getNickname(), value), this);
}
RedisSupport redis = (RedisSupport) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.REDIS_BUNGEE);
@@ -141,7 +140,7 @@ public class YellowNumber extends TabFeature {
@Override
public void onLoginPacket(TabPlayer packetReceiver) {
if (isDisabledPlayer(packetReceiver)) return;
if (isDisabledPlayer(packetReceiver) || packetReceiver.isBedrockPlayer()) return;
packetReceiver.sendCustomPacket(new PacketPlayOutScoreboardObjective(0, OBJECTIVE_NAME, TITLE, displayType), this);
packetReceiver.sendCustomPacket(new PacketPlayOutScoreboardDisplayObjective(DISPLAY_SLOT, OBJECTIVE_NAME), this);
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()){
@@ -1,5 +1,6 @@
package me.neznamy.tab.shared.features.alignedplayerlist;
import me.neznamy.tab.api.Property;
import me.neznamy.tab.api.TabPlayer;
import me.neznamy.tab.api.chat.EnumChatFormat;
import me.neznamy.tab.api.chat.IChatBaseComponent;
@@ -72,9 +73,12 @@ public class PlayerView {
public synchronized IChatBaseComponent formatName(TabPlayer target) {
Integer width = playerWidths.get(target);
if (width == null) return null; //in packet reader, not loaded yet, will send packet after loading player
String prefixAndName = target.getProperty(TabConstants.Property.TABPREFIX).getFormat(viewer) +
target.getProperty(TabConstants.Property.CUSTOMTABNAME).getFormat(viewer);
String suffix = target.getProperty(TabConstants.Property.TABSUFFIX).getFormat(viewer);
Property prefixPr = target.getProperty(TabConstants.Property.TABPREFIX);
Property namePr = target.getProperty(TabConstants.Property.CUSTOMTABNAME);
Property suffixPr = target.getProperty(TabConstants.Property.TABSUFFIX);
if (prefixPr == null || namePr == null || suffixPr == null) return null; // no idea why is another check needed
String prefixAndName = prefixPr.getFormat(viewer) + namePr.getFormat(viewer);
String suffix = suffixPr.getFormat(viewer);
if (suffix.length() == 0) return IChatBaseComponent.optimizedComponent(prefixAndName);
if ((target.isVanished() && !canSeeVanished) || width > maxWidth) {
//tab sending packets for vanished players or player just unvanished
@@ -170,7 +170,10 @@ public class BossBarLine implements BossBar {
* @return parsed progress
*/
public float parseProgress(String progress) {
return TAB.getInstance().getErrorManager().parseFloat(progress, 100);
float value = TAB.getInstance().getErrorManager().parseFloat(progress, 100);
if (value < 0) value = 0;
if (value > 100) value = 100;
return value;
}
@Override
@@ -168,8 +168,9 @@ public class GlobalPlayerList extends TabFeature {
for (PlayerInfoData playerInfoData : info.getEntries()) {
TabPlayer packetPlayer = TAB.getInstance().getPlayerByTabListUUID(playerInfoData.getUniqueId());
//not preventing NPC removals
if (packetPlayer != null && !packetFromTAB && !packetPlayer.isVanished() &&
(System.currentTimeMillis()-lastServerSwitch.getOrDefault(packetPlayer, 0L) < 500)) {
if (packetPlayer != null && !packetFromTAB && !packetPlayer.isVanished()
&& (System.currentTimeMillis()-lastServerSwitch.getOrDefault(packetPlayer, 0L) < 2000)
) {
//remove packet not coming from tab
//changing to random non-existing player, the easiest way to cancel the removal
playerInfoData.setUniqueId(UUID.randomUUID());
@@ -62,7 +62,7 @@ public class NameTag extends TabFeature implements TeamManager {
@Override
public void unload() {
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()) {
if (!isDisabledPlayer(p)) unregisterTeam(p);
if (!isDisabledPlayer(p)) unregisterTeam(p, sorting.getShortTeamName(p));
}
}
@@ -144,7 +144,7 @@ public class NameTag extends TabFeature implements TeamManager {
}
boolean changed = updateProperties(p);
if (disabledNow && !disabledBefore) {
unregisterTeam(p);
unregisterTeam(p, sorting.getShortTeamName(p));
} else if (!disabledNow && disabledBefore) {
registerTeam(p);
} else if (changed) {
@@ -193,7 +193,7 @@ public class NameTag extends TabFeature implements TeamManager {
@Override
public void pauseTeamHandling(TabPlayer player) {
if (teamHandlingPaused.contains(player)) return;
if (!isDisabledPlayer(player)) unregisterTeam(player);
if (!isDisabledPlayer(player)) unregisterTeam(player, sorting.getShortTeamName(player));
teamHandlingPaused.add(player); //adding after, so unregisterTeam method runs
}
@@ -213,7 +213,7 @@ public class NameTag extends TabFeature implements TeamManager {
public void forceTeamName(TabPlayer player, String name) {
if (Objects.equals(forcedTeamName.get(player), name)) return;
if (name != null && name.length() > 16) throw new IllegalArgumentException("Team name cannot be more than 16 characters long.");
unregisterTeam(player);
unregisterTeam(player, sorting.getShortTeamName(player));
forcedTeamName.put(player, name);
registerTeam(player);
if (name != null) sorting.setTeamNameNote(player, "Set using API");
@@ -257,10 +257,10 @@ public class NameTag extends TabFeature implements TeamManager {
viewer.sendCustomPacket(new PacketPlayOutScoreboardTeam(sorting.getShortTeamName(p), currentPrefix, currentSuffix, translate(visible), translate(collisionManager.getCollision(p)), getTeamOptions()), TabConstants.PacketCategory.NAMETAGS_TEAM_UPDATE);
}
public void unregisterTeam(TabPlayer p) {
public void unregisterTeam(TabPlayer p, String teamName) {
if (hasTeamHandlingPaused(p) || sorting.getShortTeamName(p) == null) return;
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
viewer.sendCustomPacket(new PacketPlayOutScoreboardTeam(sorting.getShortTeamName(p)), TabConstants.PacketCategory.NAMETAGS_TEAM_UNREGISTER);
viewer.sendCustomPacket(new PacketPlayOutScoreboardTeam(teamName), TabConstants.PacketCategory.NAMETAGS_TEAM_UNREGISTER);
}
}
@@ -279,13 +279,12 @@ public class NameTag extends TabFeature implements TeamManager {
}
private void updateTeam(TabPlayer p) {
if (sorting.getShortTeamName(p) == null) return; //player not loaded yet
String oldName = getSorting().getShortTeamName(p);
getSorting().constructTeamNames(p);
if (oldName.equals(sorting.getShortTeamName(p))) {
updateTeamData(p);
} else {
unregisterTeam(p);
unregisterTeam(p, oldName);
LayoutManager layout = (LayoutManager) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.LAYOUT);
if (layout != null) layout.updateTeamName(p, sorting.getFullTeamName(p));
registerTeam(p);
@@ -355,7 +355,7 @@ public abstract class NameTagX extends NameTag implements UnlimitedNametagManage
public void pauseTeamHandling(TabPlayer player) {
Preconditions.checkLoaded(player);
if (teamHandlingPaused.contains(player)) return;
if (!isDisabledPlayer(player)) unregisterTeam(player);
if (!isDisabledPlayer(player)) unregisterTeam(player, getSorting().getShortTeamName(player));
teamHandlingPaused.add(player); //adding after, so unregisterTeam method runs
pauseArmorStands(player);
}
@@ -170,7 +170,7 @@ public class ScoreboardImpl extends TabFeature implements Scoreboard {
@Override
public void refresh(TabPlayer refreshed, boolean force) {
if (refreshed.getProperty(TabConstants.Property.SCOREBOARD_TITLE) == null) return;
if (!players.contains(refreshed)) return;
refreshed.sendCustomPacket(new PacketPlayOutScoreboardObjective(2, ScoreboardManagerImpl.OBJECTIVE_NAME,
refreshed.getProperty(TabConstants.Property.SCOREBOARD_TITLE).updateAndGet(), EnumScoreboardHealthDisplay.INTEGER), TabConstants.PacketCategory.SCOREBOARD_TITLE);
}
@@ -26,7 +26,7 @@ public class Groups extends SortingType {
public String getChars(ITabPlayer p) {
String group = p.getGroup().toLowerCase();
int position;
if (!sortedGroups.containsKey(group.toLowerCase())) {
if (!sortedGroups.containsKey(group)) {
position = sortedGroups.size() + 1;
sorting.setTeamNameNote(p, sorting.getTeamNameNote(p) + "\n-> &cPrimary group (&e" + p.getGroup() + "&c) is not in sorting list. &r");
} else {
@@ -60,9 +60,7 @@ public abstract class SortingType {
int index = 1;
for (String element : elements){
for (String element0 : element.split("\\|")) {
while (element0.startsWith(" ")) element0 = element0.substring(1);
while (element0.endsWith(" ")) element0 = element0.substring(0, element0.length()-1);
sortedGroups.put(EnumChatFormat.color(element0.toLowerCase()), index++);
sortedGroups.put(EnumChatFormat.color(element0.trim().toLowerCase()), index++);
}
}
return sortedGroups;
+3 -41
View File
@@ -1,35 +1,3 @@
MyAnimation1:
change-interval: 100
texts:
- '&d-&3--------------'
- '&3-&d-&3-------------'
- '&3--&d-&3------------'
- '&3---&d-&3-----------'
- '&3----&d-&3----------'
- '&3-----&d-&3---------'
- '&3------&d-&3--------'
- '&3-------&d-&3-------'
- '&3--------&d-&3------'
- '&3---------&d-&3-----'
- '&3----------&d-&3----'
- '&3-----------&d-&3---'
- '&3------------&d-&3--'
- '&3-------------&d-&3-'
- '&3--------------&d-'
- '&3-------------&d-&3-'
- '&3------------&d-&3--'
- '&3-----------&d-&3---'
- '&3----------&d-&3----'
- '&3---------&d-&3-----'
- '&3--------&d-&3------'
- '&3-------&d-&3-------'
- '&3------&d-&3--------'
- '&3-----&d-&3---------'
- '&3----&d-&3----------'
- '&3---&d-&3-----------'
- '&3--&d-&3------------'
- '&3-&d-&3-------------'
- '&d-&3--------------'
ServerName:
change-interval: 300
texts:
@@ -97,16 +65,10 @@ Welcome:
- '&7&lW_'
- '&7&lW_'
time:
change-interval: 900
change-interval: 3000
texts:
- '&7Time &b%time%'
- '&7> Time &b%time% &7<'
- '&7>> Time &b%time% &7<<'
- '&7>>> Time &b%time% &7<<<'
- '&7Date &b%date%'
- '&7> Date &b%date% &7<'
- '&7>> Date &b%date% &7<<'
- '&7>>> Date &b%date% &7<<<'
- '&7Time &b%time%'
- '&7Date &b%date%'
barcolors:
change-interval: 1000
texts:
+2 -2
View File
@@ -6,19 +6,19 @@ header-footer:
disable-in-servers:
- disabledserver
header:
- "<#FFFFFF>&m </#FFFF00>"
- "&3&lServer name"
- "&7&l>> %animation:Welcome%&3 &l%player%&7&l! &7&l<<"
- "&7Online players: &f%online%"
- "&6Online staff: &e%staffonline%"
- ""
- "%animation:MyAnimation1%"
footer:
- "%animation:MyAnimation1%"
- "%animation:time%"
- "&2Ping: %ping%"
- "&7&l Used memory: %memory-used% MB / %memory-max% MB"
- ""
- "&7Visit our webpage %animation:web%"
- "<#FFFFFF>&m </#FFFF00>"
per-world:
world1:
header: